iOS 逆向
Mach-O 文件格式解析:iOS App 逆向的第一步
0x
为什么从 Mach-O 开始?
iOS 上的可执行文件、动态库、dylib 都是 Mach-O(Mach Object)格式。无论你想做 静态分析 还是 动态调试,第一步都是读懂这个二进制文件的结构。它决定了代码段在哪里、符号表在哪里、依赖哪些动态库。
Mach-O 的三层结构
一个 Mach-O 文件由三部分组成:
┌─────────────────────┐
│ Mach-O Header │ -- 文件类型、CPU 架构、加载命令数量
├─────────────────────┤
│ Load Commands │ -- 描述段布局、入口点、依赖库
├─────────────────────┤
│ Data (Segments) │ -- __TEXT / __DATA / __LINKEDIT
└─────────────────────┘
Header
头部前 4 字节是魔数 0xFEEDFACE(32 位)或 0xFEEDFACF(64 位)。cputype 字段标识架构:0x0100000C 是 arm64。可以用 otool 直接读取:
$ otool -h App
Mach header
magic cputype cpusubtype caps filetype ncmds sizeofcmds flags
0xfeedfacf 16777228 0 0x00 2 50 5848 0x00200085
Load Commands:文件的"配置清单"
Header 之后是一系列 Load Command,每条命令以 LC_ 开头。最常用的几个:
- LC_SEGMENT_64:声明一个段(__TEXT、__DATA、__LINKEDIT)的虚拟内存映射
- LC_LOAD_DYLIB:声明依赖的动态库,如
Foundation、UIKit - LC_MAIN:主程序入口(默认是
_main符号) - LC_CODE_SIGNATURE:代码签名数据位置(逆向后必须重签名才能运行)
常用读取工具
# 查看依赖库
$ otool -L App
# 查看入口点
$ otool -l App | grep -A5 LC_MAIN
# 查看符号表
$ nm -nm App | head -50
__TEXT 段:代码与只读数据
最重要的 section:
__text:编译后的机器码,是反汇编与反编译的主要对象__cstring:字符串常量。很多敏感信息(API Key、URL、提示语)会出现在这里__objc_methname:Objective-C 方法名。OC 的方法名总是以字符串形式存在于二进制中,这大大降低了逆向门槛
# 提取字符串
$ strings App | grep -i "api" | head -20
# 用 Ghidra / IDA 打开 __text 进行反编译
符号表与 class-dump
iOS App 通常保留 Objective-C 类信息(__objc_classlist)。class-dump 可以把这些信息还原成近似头文件的接口声明:
$ class-dump App -H -o ./headers
# 输出示例
@interface LoginViewController : UIViewController
@property (nonatomic, copy) NSString *token;
- (void)loginWithAccount:(NSString *)account password:(NSString *)password;
@end
这一步往往几秒钟就能让你看到 App 的全部类结构,是逆向分析的"第一桶金"。
实战流程总结
otool -h / -l查看头部与加载命令,确认架构与依赖strings+nm快速浏览字符串与符号class-dump还原 OC 类头文件- Ghidra / IDA 对
__text做反编译,定位关键函数 - 如需动态验证,配合
frida或lldb在运行时观察行为
Mach-O 是 iOS 逆向的地图。看懂地图,才能知道该去哪里下刀。