百趣云 百趣云的博客

iOS 签名机制与 Mach-O:理解 fairplay 之前先理解加载

Mach-O:iOS 二进制的解剖图

iOS/macOS 的可执行文件是 Mach-O 格式,结构分三段:

Mach Header(头部:架构、加载命令数量)
    ↓
Load Commands(加载命令:告诉系统怎么加载)
    ↓
Segments/Sections(数据段:代码、数据、符号)

逆向必知的几个 Load Command:

  • LC_SEGMENT_64:定义内存段(__TEXT 代码段、__DATA 数据段)
  • LC_ENCRYPTION_INFO_64FairPlay 加密信息cryptid=1 表示加密,砸壳就是把它清 0 并替换明文段
  • LC_CODE_SIGNATURE:代码签名位置
  • LC_LOAD_DYLIB:依赖的动态库列表——MonkeyDev 注入就是在这里加一条

分析工具:otool -l 看加载命令,MachOView 图形化查看(强烈推荐,结构一目了然)。

代码签名:iOS 安全的地基

iOS 的"所有代码必须签名"机制,是理解越狱、砸壳、重打包一切问题的前提:

  1. 苹果签名:App Store 的包由苹果私钥签名,系统信任
  2. 开发者签名:开发调试包由开发者证书 + 描述文件签名,描述文件绑定设备 UDID
  3. 企业签名:企业证书签的包任意设备可装(苹果监管之外的灰色地带,常被吊销)

验证签名:

codesign -dv --verbose=4 Target.app
# 看签名者、team id、entitlements

重打包必须重签名:改了二进制或注入 dylib 后原签名失效,系统拒绝加载。重签名流程:

# 1. 删掉原签名
rm -rf Target.app/_CodeSignature
# 2. 先签所有 framework 和 dylib(从内到外)
codesign -fs "Apple Development: xxx" Target.app/Frameworks/*.framework
# 3. 最后签主包,带上 entitlements
codesign -fs "Apple Development: xxx" --entitlements ent.plist Target.app

FairPlay 加密的实现位置

理解砸壳原理需要知道 FairPlay 加密的是什么:

  • 加密的只是 __TEXT 段的代码页(不是整个文件)
  • 密钥在苹果的 FairPlay 体系里,设备加载时由内核/AMFID 解密
  • LC_ENCRYPTION_INFO_64 里的 cryptoff/cryptsize 标记加密范围,cryptid 标记是否加密

砸壳工具做的事:等系统解密后从内存抠明文,写回 cryptoff 指定的文件偏移,清 cryptid。所以砸壳产物在非越狱设备上也能静态分析——它已经是普通未加密二进制了。

精髓:三个实战认知

  1. __RESTRICT 段的反注入。二进制里若有 __RESTRICT/__restrict 段,DYLD_INSERT_LIBRARIES 注入会被系统拒绝。砸壳后重打包时可以顺手删掉这个段(MachOView 或 optool),为后续注入扫清障碍。
  2. Fat Binary 的架构拆分。App Store 包常含 arm64/arm64e 多架构,分析前用 lipo -thin arm64 抽单架构,IDA/Hopper 加载更快,也避免架构混淆。
  3. Swift 二进制的符号特征。Swift 方法名是 mangled 格式($s7TargetApp11SignManagerC7getSign...),用 swift-demangle 还原可读;class-dump 对纯 Swift 类效果差,要配合 swift-dump 或 IDA 的 Swift 插件。

总结

  1. Mach-O 三段结构:头部、加载命令、数据段,MachOView 是查看神器
  2. 代码签名是 iOS 安全地基,重打包必须重签名(从内到外)
  3. FairPlay 只加密 __TEXT 段,砸壳 = 内存抠明文 + 清 cryptid
  4. __RESTRICT 段防注入,重打包时顺手删除

交流微信:run1255

By 百趣云 阅读量:3 On