认识Mach-O

Mach-O

Mach-O(Mach Object)是macOS、iOS、iPadOS存储程序和库的文件格式。对应系统通过应用二进制接口(application binary interface,缩写为 ABI)来运行该格式的文件。

Mach-O格式用来替代BSD系统的a.out格式。Mach-O文件格式保存了在编译过程和链接过程中产生的机器代码和数据,从而为静态链接和动态链接的代码提供了单一文件格式。

Mach-O格式常见文件

  • 目标文件.o
  • 库文件
    • .a
    • .dylib
    • Framework
  • 可执行文件
  • dyld
  • .dsym

可在终端通过file命令查看文件类型
图片[1]-认识Mach-O-一一网
可看到当前Demo文件是一个Mach-O类型的64位x86_64架构的可执行文件

Mach-O文件结构

MachOView工具上查看一个Mach-O文件

能够看到Mach-O文件格式由HeaderLoad Commands__TEXT代码__DATA代码符号表和以及一些其它信息构成。dyld会根据Load Commands保存的信息找到具体的代码

Mach-O可理解为文件配置加上二进制代码,即:

Mach-O = 文件配置 + 二进制代码

用苹果官方图概括即:

Mach-O的组成结构如图所示包括了:

  • Header 包含该⼆进制⽂件的⼀般信息
    • 字节顺序、架构类型、加载指令的数量量等
    • 使得可以快速确认⼀些信息,⽐如当前⽂件⽤于32位还是64位,对应的处理器是什么、文件类型是什么
  • Load commands ⼀张包含很多内容的表
    • 内容包括区域的位置、符号表、动态符号表等
  • Data 通常是对象文件中最大的部分
    -包含Segement的具体数据

Header

64位的Header结构

struct mach_header_64 {
	uint32_t	magic;		/* 魔术,快速定位属于64还是32位 */
	cpu_type_t	cputype;	/* cpu类型,如ARM */
	cpu_subtype_t	cpusubtype;	/* cpu具体类型,如arm64/armv7 */
	uint32_t	filetype;	/* 文件类型 */
	uint32_t	ncmds;		/*loadCommands数量*/
	uint32_t	sizeofcmds;	/*loadCommands大小 */
	uint32_t	flags;		/* 标志位标识二进制文件支持功能。主要和系统加载、连接有关 */
	uint32_t	reserved;	/* reserved */
};

复制代码

MachOView工具上查看Header

使用objdump --macho -private-header命令查看Mach-O文件,输出对应Header数据结构,与上面对应

LoadCommands

64位的load_command结构

struct segment_command_64 { /* for 64-bit architectures */
	uint32_t	cmd;		/* command的类型 LC_SEGMENT_64 */
	uint32_t	cmdsize;	/* section_64大小 */
	char		segname[16];	/* 段名称 */
	uint64_t	vmaddr;		/* 段的虚拟内存地址 */
	uint64_t	vmsize;		/* 段的虚拟内存大小 */
	uint64_t	fileoff;	/* 段的文件偏移量 */
	uint64_t	filesize;	/* 段在文件中的大小 */
	vm_prot_t	maxprot;	/* 最大的虚拟机保护 */
	vm_prot_t	initprot;	/* 最初的虚拟保护 */
	uint32_t	nsects;		/* 段中的section数 */
	uint32_t	flags;		/* 标记 */
};
复制代码

其它的一些load_commands

LC_SEGMENT_64 将⽂件中(32位或64位)的段映射到进程地址空间中
LC_DYLD_INFO_ONLY 动态链接相关信息
LC_SYMTAB 符号地址
LC_DYSYMTAB 动态符号表地址
LC_LOAD_DYLINKER 使⽤谁加载,我们使用dyld
LC_UUID ⽂件的UUID
LC_VERSION_MIN_MACOSX 支持最低的操作系统版本
LC_SOURCE_VERSION 源代码版本
LC_MAIN 设置程序主线程的⼊口地址和栈⼤小
LC_ENCRYPTION_INFO_64 获取加密信息
LC_LOAD_DYLIB 依赖库的路径,包含三方库
LC_FUNCTION_STARTS 函数起始地址表
LC_DATA_IN_CODE 定义在代码段内的非指令的表
LC_CODE_SIGNATURE 代码签名

Data

存放数据:代码,字符常量,类,方法等

  • 代码段(__TEXT)

代码段开始地址是0,所以读内存当中的MachO开始的位置从代码段开始读的

  • 数据段(__DATA)

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享