1. 解析Mach-O文件头

任务说明

本案例目标:使用Ghidra加载一个简单的iOS Mach-O二进制文件,通过Ghidra的Mach-O解析能力识别文件头中的魔数(magic)、CPU类型(cputype)、文件类型(filetype)等关键字段,并验证解析结果与otool命令行输出一致。

环境准备

  • Ghidra 11.x(已安装并完成首次初始化)
  • macOS或Linux主机,已安装Xcode Command Line Tools(提供otool)
  • 示例文件:使用Xcode编译一个最小iOS静态库(或直接使用任意现有iOS .a文件)

生成示例Mach-O文件

若手头没有现成的iOS Mach-O文件,可执行以下命令生成一个最小静态库(包含arm64架构):

# 创建最小C源文件
echo 'int dummy_symbol(void) { return 42; }' > dummy.c
# 使用iOS SDK交叉编译为arm64目标文件
xcrun -sdk iphoneos clang -arch arm64 -c dummy.c -o dummy.o
# 打包为静态库(.a本质上是Mach-O格式的归档文件)
ar rcs libdummy.a dummy.o
# 查看文件头信息(验证用)
otool -hv libdummy.a

Ghidra导入与解析步骤

  1. 启动Ghidra,创建新项目(Non-Shared项目即可)。
  2. 将libdummy.a(或dummy.o)拖入Ghidra项目窗口。
  3. 双击文件,Ghidra自动识别格式为Mach-O,弹出导入对话框,保持默认选项点击OK。
  4. 在Analyze窗口中点击Yes执行自动分析(对于静态库,分析很快完成)。
  5. 分析完成后,在代码浏览器中打开Program Tree窗口,展开Headers目录。

关键字段识别与验证

在Ghidra的Headers目录下,双击mach_header结构体,即可在Listing窗口中看到解析后的文件头字段。对照下表确认关键字段值:

字段偏移预期值(arm64静态库)说明
magic0x000xfeedfacfMH_MAGIC_64(小端)
cputype0x040x0100000cCPU_TYPE_ARM64
cpusubtype0x080x00000000CPU_SUBTYPE_ARM64_ALL
filetype0x0c0x00000002MH_OBJECT(.o文件)或0x00000006(静态库成员)
ncmds0x10≥1Load commands数量
sizeofcmds0x14≥0所有Load commands总字节数
flags0x180x00200085包含MH_SUBSECTIONS_VIA_SYMBOLS等标志

验证方法与判定标准

  1. Ghidra内部验证:在Listing窗口确认magic字段显示为feedfacf,cputype显示为0100000c,filetype显示为2(MH_OBJECT)或6(MH_DYLIB_STUB等,取决于文件类型)。
  2. 与otool交叉验证:在终端执行otool -hv libdummy.a,观察输出中的Magic、Cputype、Filetype列,与Ghidra中解析出的值逐一比对,必须完全一致。
  3. 判定通过条件:Ghidra中识别出的魔数、CPU类型、文件类型与otool输出一致,且能正确区分64位(feedfacf)与32位(feedface)Mach-O文件。

常见问题

  • Ghidra无法识别文件:确认文件确实是Mach-O格式(可用file libdummy.a检查),且未损坏。
  • 字段显示为原始字节而非解析值:在Listing窗口右键选择Data → Structure,确保已应用mach_header_64结构体模板。
  • 静态库与目标文件差异:.a归档文件包含多个成员,每个成员都有独立的Mach-O头;Ghidra会分别列出。若直接导入.o文件则只有一个头。