系列文章
- iOS Jailbreak Principles 0x01 - rootfs remount r/w 原理
- iOS Jailbreak Principles 0x02 - codesign and amfid bypass
前言
在上一篇文章中我们介绍了 amfid 的 codesign 机制及其绕过,amfid 是 codesign 逻辑在 user mode 的一个 daemon,代表了 C/S 架构中的 Server。本文将介绍 kernel mode 的 amfi.kext,它是 amfid 的 Client,以 Kernel Extension 的形式被加载和注册到 Kernel 中。
Kernel Extension
定义
XNU 是一个功能丰富的内核,包含了调度, 内存管理, I/O 等必要的服务,但它依然难以直接适配浩如烟海的硬件和外设,即使是宏内核也无法完全做到这一点[1]。
就像是 user mode application 中常常包含 dylib,在 kernel mode 也有 kernel modules 作为扩展,在 XNU 中被称为 kernel extensions,简称为 kext[1]。
Pre-Linking
以常规视角而言,操作系统应当是先 boot kernel,随后 load kexts。在 iOS 中,kernel 和它的扩展不是以分离的文件形式存在,而是将 kernel 和 kexts 合并成一个 kernelcache 文件直接被 boot loader 加载。
kernelcache 带来了两个好处,其一是 kexts 不必再像 dylib 那样进行动态链接,省去了外部符号地址解析的过程,加快了加载速度;其二是 kernelcache 可以被完整的签名以降低 kext 被篡改的风险[1]。
分析 AppleMobileFileIntegrity.kext
从 kernelcache 中分离
由于 amfi.kext 被 prelink 到 kernelcache 中,因此其 Info.plist 和 binary 都直接包含在了庞大的 kernelcache 中,为了便于分析我们可以将它们从 kernelcache 中分离出来。
通过 joker 分离 kext binary
使用 joker (http://www.newosxbook.com/tools/joker.html) 可以分离出 kext 和进行部分符号化:
# 指定输出目录
> cd /tmp/kext
> export JOKER_DIR=/tmp/kext
# 准备好 kernelcache
> ls .
kernelcache
# 分离 amfi.kext
> joker -K com.apple.driver.AppleMobileFileIntegrity kernelcache
Writing kext out to /tmp/kext/com.apple.driver.AppleMobileFileIntegrity.kext
Symbolicated stubs to /tmp/kext/com.apple.driver.AppleMobileFileIntegrity.kext.ARM64.E815A4DD-90E7-3A38-A4BA-EFA2425BC543
# 查看产物
> ls .
com.apple.driver.AppleMobileFileIntegrity.kext
com.apple.driver.AppleMobileFileIntegrity.kext.ARM64.E815A4DD-90E7-3A38-A4BA-EFA2425BC543
kernelcache
可以看到我们得到了 kext 的 binary 和一份符号表,由于 kext 是从内核中分离的,与从 dyld_shared_cache
分离出 dylib 类似,有大量的外部地址无法正常解析,通过符号表或是在 kernelcache 中定位都可以帮助判断这些地址的含义和内容。
使用 jtool 分离 PRELINK_INFO
与 App 通过 Info.plist 描述关键信息类似,kext 也有其 Info.plist 来描述 kext 的各种信息,其中包含了标识符、加载地址等关键信息,为了方便分析,我们还需要从 kernelcache 中分离出 amfi 的 Info.plist。这里我们使用 jtool (http://www.newosxbook.com/tools/jtool.html) 来完成分离:
# 指定输出目录
export JTOOLDIR=/tmp/kext
# 分离 PRELINK_INFO
> jtool -e __PRELINK_INFO kernelcache
Requested segment found at offset 1e10000!
Extracting __PRELINK_INFO at 31522816, 2342912 (23c000) bytes into kernelcache.__PRELINK_INFO
# 查看产物
> ls .
com.apple.driver.AppleMobileFileIntegrity.kext
com.apple.driver.AppleMobileFileIntegrity.kext.ARM64.E815A4DD-90E7-3A38-A4BA-EFA2425BC543
kernelcache
kernelcache.__PRELINK_INFO
打开 kernelcache.__PRELINK_INFO
可以看到这里包含了大量被 prelink 到 kernelcache 中的 kext 的信息,在其中还混入了大量被 base64 编码的 Data Blob。
在 PRELINK_INFO 中查找关键信息
在 kernelcache.__PRELINK_INFO
中搜索 _PrelinkBundlePath/System/Library/Extensions/AppleMobileFileIntegrity.kext
可以定位到 amfi.kext 的 Info.plist,这里包含了 amfi.kext 的一些关键信息:
<dict>
<key>BuildMachineOSBuildkey>
<string>18A391011string>
<key>_PrelinkExecutableLoadAddrkey>
<integer ID="32" size="64">0xfffffff005ab1980integer>
<key>CFBundlePackageTypekey>
<string>KEXTstring>
<key>_PrelinkExecutableSourceAddrkey>
<integer IDREF="32"/>
<key>CFBundleDevelopmentRegionkey>
<string>Englishstring>
<key>MinimumOSVersionkey>
<string>13.1string>
<key>CFBundleVersionkey>
<string>1.0.5string>
<key>DTXcodeBuildkey>
<string>11L374mstring>
<key>DTPlatformBuildkey>
<string ID="33"/>
<key>_PrelinkBundlePathkey>
<string>/System/Library/Extensions/AppleMobileFileIntegrity.kextstring>
<key>_PrelinkExecutableSizekey>
<integer size="64">0x5211integer>
<key>_PrelinkKmodInfokey>
<integer size="64">0xfffffff0077e51c8integer>
<key>UIDeviceFamilykey>
<array>
<integer IDREF="10"/>
array>
<key>OSBundleRequiredkey>
<string>Rootstring>
<key>CFBundleIdentifierkey>
<string>com.apple.driver.AppleMobileFileIntegritystring>
<key>DTXcodekey>
<string>1100string>
<key>CFBundleExecutablekey>
<string IDREF="31"/>
dict>
其中以 _Prelink
开头的字段非常重要:
<dict>
<key>_PrelinkExecutableLoadAddrkey>
<integer ID="32" size="64">0xfffffff005ab1980integer>
<key>_PrelinkExecutableSourceAddrkey>
<integer ID="32" size="64">0xfffffff005ab1980integer>
<key>_PrelinkBundlePathkey>
<string>/System/Library/Extensions/AppleMobileFileIntegrity.kextstring>
<key>_PrelinkExecutableSizekey>
<integer size="64">0x5211integer>
<key>_PrelinkKmodInfokey>
<integer size="64">0xfffffff0077e51c8integer>
<key>CFBundleIdentifierkey>
<string>com.apple.driver.AppleMobileFileIntegritystring>
dict>
这些字段的含义如下[1]:
- _PrelinkExecutableSourceAddr: kext 的起始地址,即 kext 的 Mach-O Header 地址;
- _PrelinkExecutableLoadAddr: kext 在内存中的加载地址,对于 prelink kext 这个值一般等于 _PrelinkExecutableSourceAddr;
- _PrelinkKmodInfo: kext 在 Mach layer 的对象模型。
下面我们大致看一下这些地址的内容,首先