文章目录
摘要:对于mach-o是Mac和iOS可以执行文件的格式。进程就是系统根据该格式将执行文件加载到内存后得到的结果。系统通过解析文件,建立依赖(动态库),初始化运行时环境,才能真正开始执行该App(进程)
1. Mach-O的文件结构
小工具介绍下:烂苹果MachOView。通过改工具可以直接review mach-o可执行文件的几个主要的组成部分:
-
简单浏览mach-o可执行文件,具体可以分为几个部分
- 文件头 mach64 Header
- 加载命令 Load Commands
- 文本段 __TEXT
- 数据段 __DATA
- 动态库加载信息 Dynamic Loader Info
- 入口函数 Function Starts
- 符号表 Symbol Table
- 动态库符号表 Dynamic Symbol Table
- 字符串表 String Table
-
具体介绍下各个区域的作用,以及加载时系统是如何使用该可执行文件。
2. Mach-O文件在虚拟内存中的分布情况
2.1 VM Address、VM Size、File Offset、File Size的含义
- VM Address : Virtual Memory Address, 段的虚拟内存地址,在内存中的位置
- VM Size : Virtual Memory Size, 段的虚拟内存大小, 占用多少内存
- File Offset : 段在文件中的偏移量
- File Size : 段在文件中的大小
2.2 虚拟内存的分布
-
__PAGEZERO
: 预留内存- VM Address: 0x0
- VM Size: 0x100000000
-
__TEXT
: 代码段, 用来存放代码的- VM Address: 0x100000000
- VM Size: 0x380C000
-
__DATA
: 数据段, 用来存储全局变量的值, 以及其他- VM Address: 0x10380C000
- VM Size: 0xD4C000
-
__LINKEDIT
- VM Address: 0x104558000
- VM Size:
-
函数代码存放在
__TEXT
段中 -
全局变量存放在
__ DATA
段中 -
可执行文件的内存地址是0x0
-
代码段(_ TEXT )的内存地址
- 就是LC_ SEGMENT(_ _TEXT)中的VM Address
- arm64 : 0x100000000 ( 8个0 )
- 非arm64 : 0x4000 ( 3个0 )
-
可以使用
size -l -m -x
来查看 Mach-O 的内存分布
Mach Header - 可执行文件文件头
- mach-o标准的文件头格式,其相关的数据结构在
/*
* The 32-bit mach header appears at the very beginning of the object file for
* 32-bit architectures.
*/
struct mach_header {
uint32_t magic; /* mach magic number identifier */
cpu_type_t cputype; /* cpu specifier */
cpu_subtype_t cpusubtype; /* machine specifier */
uint32_t filetype; /* type of file */
uint32_t ncmds; /* number of load commands */
uint32_t sizeofcmds; /* the size of all the load commands */
uint32_t flags; /* flags */
};
/* Constant for the magic field of the mach_header (32-bit architectures) */
#define MH_MAGIC 0xfeedface /* the mach magic number */
#define MH_CIGAM 0xcefaedfe /* NXSwapInt(MH_MAGIC) */
/*
* The 64-bit mach header appears at the very beginning of object files for
* 64-bit architectures.
*/
struct mach_header_64 {
uint32_t magic; /* mach magic number identifier */
cpu_type_t cputype; /* cpu specifier */
cpu_subtype_t cpusubtype; /* machine specifier */
uint32_t filetype; /* type of file */
uint32_t ncmds; /* number of load commands */
uint32_t sizeofcmds; /* the size of all the load commands */
uint32_t flags; /* flags */
uint32_t reserved; /* reserved */
};
/* Constant for the magic field of the mach_header_64 (64-bit architectures) */
#define MH_MAGIC_64 0xfeedfacf /* the 64-bit mach magic number */
#define MH_CIGAM_64 0xcffaedfe /* NXSwapInt(MH_MAGIC_64) */
- 对照命令结果和具体的数据结构,下表介绍各个字段的具体意义:
字段 | 说明 | 举例 |
---|---|---|
magic | 魔数,系统加载器通过改字段快速,判断该文件是用于32位 or 64位。32位-0xfeedface 64位-0xfeedfacf | demo中magic值为0xfeedfacf,表明该文件支持64位 |
cputype | CPU类型以及子类型字段,该字段确保系统可以将适合的二进制文件在当前架构下运行 | demo值为0x1000007, 根据#define CPU_TYPE_X86_64 (CPU_TYPE_X86) |
cpusubtype | CPU指定子类型,对于inter,arm,powerpc等CPU架构,其都有各个阶段和等级的CPU芯片,该字段就是详细描述其支持CPU子类型 | 对于Demo,可以查看 #define CPU_SUBTYPE_X86_ALL ((cpu_subtype_t)3) #define CPU_SUBTYPE_X86_64_ALL ((cpu_subtype_t)3) #define CPU_SUBTYPE_X86_ARCH1 ((cpu_subtype_t)4) #define CPU_SUBTYPE_X86_64_H ((cpu_subtype_t)8) |
filetype | 说明该mach-o文件类型(可执行文件,库文件,核心转储文件,内核扩展,DYSM文件,动态库),具体可以看 | demo中该值为2,表示该文件为二进制文件 |
ncmds | 说明加载命令条数 | demo中表示该文件加载命令条数为15,通过machoview工具,看到也是15条加载命令 |
sizeofcmds | 表示加载命令大小 | demo表示该文件加载命令大小为1200字节 |
flags | 标志位,该字段用位表示二进制文件支持的功能,主要是和系统加载,链接相关,具体可以看 | demo中值为0x00200085,分别表示三个功能: 1. MH_PRELOAD 2. MH_TWOLEVEL 动态库加载二级名称空间 3. MH_PIE 对可执行文件类型启用地址空间随机布局化 |
reserved | 保留字段 |
- 系统解释,先解释文件头,获得文件支持位数(64位 or 32位),获得CPU类型,获得文件类型,获得加载命令条数和大小,获得文件标识。
Load Commands - 加载命令
- Mach-O文件包含非常详细的加载指令,这些指令非常清晰地指示加载器如何设置并且加载二进制数据。
- Load Commands紧紧跟着二进制文件头。
- 先使用工具review demo中二进制文件Load Commands
- 可以查看Mach-O文件是否加密