1272 字
6 分钟
MachO文件
一、基础概念
- Mach-O文件其实是MachObject文件格式的缩写。是Mac以及iOS上客户性文件的格式。
- 属于MachO格式的常见文件:
- 目标文件.o
- 库文件
- .a
- .dylib
- Framework
- 可执行文件
- dyld
- .dsym
file指令可以产看文件类型
二、我们通过一个简单的例子来看下MachO是怎么生成的
Test.c
# include <stdio.h>
int main() { printf("Hello world"); return 1;}Test2.c
# include <stdio.h>
int main2() { printf("Hello money"); return 1;}2.1 源文件编译为.o文件(中间对象文件)
执行命令clang -c Test.c Test2.c

看到编译出了两个对应的.o文件
可以直接 -o 一步到位
2.2 将.o文件生成可执行文件
执行命名clang -o TestEx Test.o Test2.o
生成TestEx的可执行文件,通过file指令确认一下,这里可以发现生成的就是MachO文件了
file TestExTestEx: Mach-O 64-bit executable x86_642.3 链接顺序对MachO文件的影响
我们看下当前生成TestEx文件的MD5
md5 TestExMD5 (TestEx) = 3db04e90a4e078438a03f7cb9d8bf8c8再执行命名clang -o TestEx2 Test2.o Test.o,调整.o文件顺序。
➜ Create md5 TestEx2MD5 (TestEx2) = b32bbfd76c8784f8a517249f5f7c4bec通过objdump查看MachO文件数据
➜ Create objdump --macho -d TestExTestEx:(__TEXT,__text) section_main:100003f20: 55 pushq %rbp100003f21: 48 89 e5 movq %rsp, %rbp100003f24: 48 83 ec 10 subq $16, %rsp100003f28: c7 45 fc 00 00 00 00 movl $0, -4(%rbp)100003f2f: 48 8d 3d 60 00 00 00 leaq 96(%rip), %rdi ## literal pool for: "Hello world"100003f36: b0 00 movb $0, %al100003f38: e8 39 00 00 00 callq 0x100003f76 ## symbol stub for: _printf100003f3d: b9 01 00 00 00 movl $1, %ecx100003f42: 89 45 f8 movl %eax, -8(%rbp)100003f45: 89 c8 movl %ecx, %eax100003f47: 48 83 c4 10 addq $16, %rsp100003f4b: 5d popq %rbp100003f4c: c3 retq100003f4d: 90 nop100003f4e: 90 nop100003f4f: 90 nop_main2:100003f50: 55 pushq %rbp100003f51: 48 89 e5 movq %rsp, %rbp100003f54: 48 83 ec 10 subq $16, %rsp100003f58: 48 8d 3d 43 00 00 00 leaq 67(%rip), %rdi ## literal pool for: "Hello money"100003f5f: b0 00 movb $0, %al100003f61: e8 10 00 00 00 callq 0x100003f76 ## symbol stub for: _printf100003f66: b9 01 00 00 00 movl $1, %ecx100003f6b: 89 45 fc movl %eax, -4(%rbp)100003f6e: 89 c8 movl %ecx, %eax100003f70: 48 83 c4 10 addq $16, %rsp100003f74: 5d popq %rbp100003f75: c3 retq➜ Create objdump --macho -d TestEx2TestEx2:(__TEXT,__text) section_main2:100003f20: 55 pushq %rbp100003f21: 48 89 e5 movq %rsp, %rbp100003f24: 48 83 ec 10 subq $16, %rsp100003f28: 48 8d 3d 6f 00 00 00 leaq 111(%rip), %rdi ## literal pool for: "Hello money"100003f2f: b0 00 movb $0, %al100003f31: e8 48 00 00 00 callq 0x100003f7e ## symbol stub for: _printf100003f36: b9 01 00 00 00 movl $1, %ecx100003f3b: 89 45 fc movl %eax, -4(%rbp)100003f3e: 89 c8 movl %ecx, %eax100003f40: 48 83 c4 10 addq $16, %rsp100003f44: 5d popq %rbp100003f45: c3 retq100003f46: 90 nop100003f47: 90 nop100003f48: 90 nop100003f49: 90 nop100003f4a: 90 nop100003f4b: 90 nop100003f4c: 90 nop100003f4d: 90 nop100003f4e: 90 nop100003f4f: 90 nop_main:100003f50: 55 pushq %rbp100003f51: 48 89 e5 movq %rsp, %rbp100003f54: 48 83 ec 10 subq $16, %rsp100003f58: c7 45 fc 00 00 00 00 movl $0, -4(%rbp)100003f5f: 48 8d 3d 44 00 00 00 leaq 68(%rip), %rdi ## literal pool for: "Hello world"100003f66: b0 00 movb $0, %al100003f68: e8 11 00 00 00 callq 0x100003f7e ## symbol stub for: _printf100003f6d: b9 01 00 00 00 movl $1, %ecx100003f72: 89 45 f8 movl %eax, -8(%rbp)100003f75: 89 c8 movl %ecx, %eax100003f77: 48 83 c4 10 addq $16, %rsp100003f7b: 5d popq %rbp100003f7c: c3 retq可以确定生成的MachO文件不同了。
MachO是一系列.o文件的集合
三:MachO文件结构
3.1 Header
- 包含了二进制文件的一般信息
- 字节顺序、架构类型、加载指令的数量等
- 使得一些信息可以快速确认
- 比如当前文件是用于32位还是64位,对应的处理器是什么、文件类型是什么
Header数据结构
可以再Xcode中快速打开文件
Loader.h查看,这个文件时学习MachO非常好的一个入口!
/* * 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 */};magic 快速定位是64位还是32位
cputype CPU类型,比如ARM
cpusubtype CPU具体类型,比如:arm64/armv7
filetype 文件类型,比如:可执行文件
ncmds LoadCommands条数
sizeofcmds LoadCommands大小
flags 标志位,标识二进制文件支持的功能。主要是和系统加载、链接有关。
使用otool查看Header内容
➜ Create otool -v -h TestEx2TestEx2:Mach header magic cputype cpusubtype caps filetype ncmds sizeofcmds flagsMH_MAGIC_64 X86_64 ALL 0x00 EXECUTE 16 1368 NOUNDEFS DYLDLINK TWOLEVEL PIE3.2 Load commands
- 内容包括区域的位置、符号表、动态符号表等
Rebase info offset
MachO文件在加载到内存中后(虚拟内存),会被分配一个随机的偏移值ASLR。
我们使用静态分析工具看到的并不是真实的内存地址。
查看当前ASLR

命令image list -o -f | grep 当前MachO文件名
(lldb) image list -o -f | grep WeChat[ 0] 0x0000000000118000 /Users/RyukieW/Library/Developer/Xcode/DerivedData/WeChat-ajurlvyhlazpsbhatmdivvridyee/Build/Products/Debug-iphoneos/WeChat.app/WeChatASLR 0x0000000000118000 (随机的每次都不一样)
真实地址 0x10011e640
用工具查看地址
0x0000000100006640
计算真实地址
ASLR+工具显示的地址- 使用编程计算器验证成功!
使用otool查看Load commands内容
➜ Create otool -v -l TestEx2...3.3 Data
- 通常是文件中最大的部分
- 包含Segement的具体数据