Mach-O是一种mac上可执行文件的格式
iOS在加载app的时候,本质其实是通过dyld加载app中的MachO文件,MachO属于一种文件格式,其中包含了可执行文件、静态库、动态库、dyld等;其中包含的可执行文件是集合了多种架构的,例如包含了 armv7、arm64等
Mach-O文件的主组成部分:
Header: 保存Mach-O的一些基本信息,包括平台、文件类型、指令数、指令总大小,dyld标记Flags等。Load Commands: 紧跟Header,加载Mach-O文件时会使用这部分数据确定内存分布,对系统内核加载器和动态连接器起指导作用。Text: 存放代码。Data:存放数据。例如:数据、字符串常量、类、方法
1、DATA区域(Text + data)
Segment & Section:Mach-o 文件有多个Segment(段)
每个Segment有不同的功能
每个Segment还细分为多个Section
| 区 | 描述 |
|---|---|
| TEXT.text | 机器码 |
| TEXT.cstring | 硬编码的字符串 |
| TEXT.const | 初始化过的常量 |
| DATA.data | 初始化过的可变的(静态/全局)数据 |
| DATA.const | 未有初始化过的常量 |
| DATA.bss | (静态/全局)未初始化 的变量 |
| DATA.common | 没有初始化过的符号声明 |
2、 常用概念:
-
VM Address : Virtual Memory Address, 段的虚拟内存地址,在内存中的位置
-
VM Size : Virtual Memory Size, 段的虚拟内存大小, 占用多少内存
-
File Offset : 段在文件中的偏移量
-
File Size : 段在文件中的大小
每个SECTION的基地址都等于上个SECTION的基地址+上个SECTION的Size
或者__PAGEZERO的基地址+SECTION的Offset
__PAGEZERO的基地址 = 0000000000000000 Size = 0000000100000000
0000000000000000 + 0000000100000000= 0000000100000000
那么__TEXT的基地址就是 = 0000000100000000
同理,后面的 __DATA_CONST、__DATA、__LINKEDIT 的基地址都是 上个SECTION的基地址+上个SECTION的Size
3、 ASLR
Address Space Layout Random ,地址空间布局随机化。在iOS系统中打开一个App的时候是会将App的二进制数据从硬盘copy到内存里,那么这时候二进制数据就会对应一个内存地址,由于考虑安全因素的问题,内存的地址都是由虚拟缓存地址替代,而且地址的起始位置都是动态的,每次启动的时候都会不一样,这个技术就是ASLR。大部分主流操作系统都实现了ASLR。
讲人话就是,mach-o在载入内存的时候,前面会加一个随机大小的内存
所以在计算section的基地址的时候,需要额外加上ASLR
section基地址=ASLR+pagezero+section的offset
4、结合lldb工具看一下具体数据都放在mach-o中的哪些位置:
【工具放后面】
测试代码:
int a = 10;
int b;
int main(int argc, const char * argv[]) {
@autoreleasepool {
char *d = "CCCT";
NSLog(@"end");
}
return 0;
}
LLDB工具:
下载地址:pan.baidu.com/s/1u9NCQofG… 提取码3sms
安装方法:
-
把插件放在项目根目录
-
在项目根目录新建 lldbinit 文件
-
在文件中写入内容:
plugin load 插件路径 -
在项目的Edit Scheme -> LLDB init File 填入lldbinit文件路径
-
运行项目,断点后输入命令
cat address 地址