1、什么是Mach-O文件
- Mach-O 为 Mach Object 文件格式的缩写,它是一种用于 目标代码、内核转储 等的文件格式.作为
a.out格式的替代, Mach-O 提供了更强的扩展性,并提升了 符号表 中信息的访问速度.苹果系统中常用于可执行文件、动态库、.o的目标文件、.a和.framework的静态库以及动态连接器dyld等
2、Mach-O结构
- Mach-O 是一个以数据块分组的
二进制字节流,这些数据块包含元信息,比如 字节顺序、CPU类型、数据块大小 等
2.1、ASLR
- ASLR ,全称是
Address Spce Layout Randomization,翻译过来就是地址空间布局随机化,是一种针对缓冲区溢出的安全保护技术,通过对堆、栈、共享库映射等线性区布局的随机化,增加了攻击者预测目的地址的难度,防止攻击者直接定位代码位置,阻止溢出攻击- 未使用ASLR时Mach-O载入内存情况:
- 使用ASLR时Mach-O载入内存情况:
- 未使用ASLR时Mach-O载入内存情况:
- 虚拟内存中的真正地址 = ASLR偏移量 + PAGEZERO的大小 + Mach-O中的偏移量 (其中PAGEZERO的大小就是VM Size,Mach-O中的偏移量就是Offset,因为PAGEZERO到内存中才会展开,所以要加上PAGEZERO的大小)
2.2、Header
- 保存 Mach-O 的一些基本信息
-
Magic Number(模数): 表示该二进制所支持的CPU位数,用于校验- MH_MAGIC : 0xFEEDFACE //32位
- MH_MAGIC_64 : 0xFEEDFACF //64位
-
CPU Type、CPU SubType:CPU架构及子版本 -
File Type:文件类型- MH_EXECUTABLE : 可执行二进制文件
- MH_OBJECT : 目标文件
- MH_DYLIB : 动态库
-
Number of Load Commands:加载命令的数量 -
Size of load Commands:所有加载命令的大小 -
Flags(文件状态信息)包含一些状态位.(dyld加载需要的一些标记,20多种宏定义,需要查看源码)- MH_DYLDLINK : 该二进制不能再静态链接
- MH_PIE : 启用 ASLR 地址空间布局随机化
-
reserved:64位保留字段
2.3、Load Commands(加载指令)
-
紧跟 Header,加载 Mach-O 文件时会使用这部分数据
确定内存分布,对系统内核加载器和动态连接器起指导作用 -
load_commands 展开后的数目与总大小已经在 Header 中有记录,所有加载指令都是以
Command、Command Size起头。Command Size 字段以字节为单位,主要记录偏移量让 load command 指针进入下一条加载指令,32位架构的 load command 是以4字节的倍数,64位结构的 load command 是以8字节的倍数(加载指令永远是这样对齐),不够用0填充字节,这样就可以被映射到内存 -
VM Address、VM Size记录这此段在虚拟内存的位置和大小 -
File Offset、File Size记录着此段在Mach-O中的位置和大小 -
结构如图所示:
指令分析
- Load Commands 指令如下:
-
LC_SEGMENT_64 : 加载段
- 源码中数据结构:
- 4种主要 LC_SEGMENT_64 类型: __PAGEZERO 、__TEXT 、__DATA 、 __LINKEDIT
- 源码中数据结构:
-
LC_DYLD_INFO_ONLY :动态链接相关信息
-
LC_SYMTAB:加载符号地址
-
LC_DYSYMTAB:加载动态符号表地址
-
LC_LOAD_DYLINKER :加载动态链接器dyld,用于后续加载动态库
-
LC_UUID :加载二进制的UUID,唯一标识,常用于解析crash堆栈。
-
LC_VERSION_MIN_MACOSX :加载该二进制支持的最小操作系统版本,对应于工程配置中的 Deployment Target
-
LC_SOURCE_VERSION : 源代码版本
-
LC_MAIN :加载main函数
-
LC_DYLIB :加载动态库,外挂如WeChatPlugin,会增加一条这样的指令,用于加载自定义的动态库
-
LC_RPATH :加载
@rpath,对应于工程配置中的 Runpath Search Paths -
LC_FUNCTION_STARTS :加载函数入口信息。
-
LC_DATA_IN_CODE :定义在代码段内的非指令的表
-
LC_CODE_SIGNATURE :加载签名,用于校验,外挂如WeChatPlugin,会删掉这条指令
-
2.4、Section64(节)
-
Load Commands 区域下来接着就是 DATA 区域,展开 Load Commands 下的 LC_SEGMENT_64 可以看到多个 Section64 ,各个Section的具体信息可以在 DATA 区查看,它们是一一对应的:
-
DATA: Load Commands 中每个segment的具体数据保存在这里,包含具体的代码、数据等 -
section 节已经是最小的分类,大部分内容集中在 __TEXT, __DATA 这两段中,部分内容如下
3、符号表:Symbol Table
-
方法的名称称为
符号,存在于Symbols这项中 -
上架时会剔除符号表,只保留动态符号表 ,因为编译完成后地址就已经确定了,如果还留着符号表只是为别人Hook你的内容提供便利