导语:当用户启动iPhone手机时,iBoot是加载iOS系统的第一个进程。它加载并验证内核是否被苹果正确签名,然后执行。本文将讲述构建iBoot具体方法。
2018年2月,有一个名为“Dark-Liberty Team”的团队将苹果iBoot源代放在了GitHub中,以MediaFire下载链接的方式公开,资料标题是”iBoot源代码 – 重新上传”。 谁都知道iBoot是iOS系统的关键源码之一,它确保了操作系统的可信任启动,相当于是Windows电脑的BIOS系统。长期以来,尽管苹果部分开源了macOS和iOS,但iBoot源码一直被其谨慎保密。
其实早在几个月前,iBoot源码就被泄露在Reddit社交平台上。对此,苹果公司表示:
泄露到GitHub上的代码确实是iBoot源代码,但对iPhone安全没有影响。因为苹果的安全性除了依赖源代码的安全性外,产品内部还有许多硬件和软件保护层来保障用户的安全。再说,此次泄露的是3年前iOS 9的旧代码,而现在苹果已更新到了iOS 11,这两个版本的iBoot源码仅有小部分重合。
根据文件中的时间戳和泄露代码中的各种符号,可以发现字符串不但被混淆了,且缺少对搭载A5处理器的设备(iPhone4s、iPad 2、Apple TV 3G、iPod Touch 5、iPad mini)以外的任何设备的支持,其实其中是启动过程是四步(LLB,iBoot,iBSS,iBEC)而不是像iOS 10两步(iBootStage1,iBootStage2),因此我们可以确认此代码属于iOS 9版本。
如何构建iBoot
简单说,当用户启动iPhone手机时,iBoot是加载iOS系统的第一个进程。它加载并验证内核是否被苹果正确签名,然后执行。
不过仅凭这些泄露的代码片段,就想构建出一个可用的完整的iBoot副本是不可能的。因为迄今为止,这些泄露的源代码都是不完整的。不过据我所知,我的Twitter好友中有两位安全研究人员试图挑战这个项目。其中一个是@ xerub,他成功构建了引导加载程序,但据他自己说,他只是重新创建了丢失的文件。我非常怀疑以这种方式构建的引导加载程序是否真的能工作,特别是考虑到一个具体帐户,丢失的文件很可能与电源管理有关。
按着他的思路,我进行了自己的研究,发现以下3点:
1.可以为搭载A5处理器的设备 (s5l8940x, s5l8942x, s5l8945x, s5l8947x)和s5l8747x(在Haywire中使用)构建iBoot,但是在device_map中需要修改(稍后我将详细讨论);
2.可以为搭载A6处理器的设备(s5l8950x和s5l8955x)构建iBoot;
3.但搭载A7(s5l8960x),A8(t7000,t7001),A9(s8000,s8003,s8001),S1(s7002)和S1P / S2(t8002)的设备由于丢失了很多标头信息,无法构建iBoot;
另外,利用DEBUG-fuse进行调试的引导加载程序由于某些不明显的原因,也无法进行正常构建。不过有一种特殊的技术可以解决这个问题,但是我还没有掌握,所以还不能分享。
构建iBoot的过程
第一步很简单:
cd iboot
然而,第二步就并不那么简单了:
sudo make APPLICATIONS="iBoot" TARGETS="n41 n42" BUILDS="DEVELOPMENT DEBUG" PRODUCTS="iBSS iBEC"
让我们来详细解读一下其中的参数含义:
1.APPLICATIONS参数定义了要构建的应用程序。有效值有:iBoot,SecureROM(bootrom)和EmbeddedIOP(由内核加载并位于其缓存中的内容);
2.TARGETS参数定义了要为其构建的设备模型(不包含"ap"/"dev" 部分);
3.BUILDS参数定义了要构建的BUILD_STYLE。 iBoot应用程序的有效值为:RELEASE(就像正常iBoot提供IPSW), DEVELOPMENT(在Image3兼容设备上执行不受信任的映像,不过在新版本上有大量冗长的版本以及许多其他命令),DEBUG(与DEVELOPMENT相同,不过有更多的冗长,甚至更多的额外命令),SECRET(这个构建样式没有在device_map中定义,所以你无法构建它)。
当然,这些参数不会直接发挥作用,在构建过程中,你会遇到几个问题。对于构建的环境,我强烈建议使用安装了Xcode 7的OS X El Capitan。另外,也不建议使用低版本的SDK。
构建iBoot过程中的主要问题
问题1:缺少SDK
查找SDK路径的嵌入式机制通常会失败:
%%% building on OS darwin xcodebuild: error: SDK "iPhoneOS" cannot be located. xcodebuild: error: SDK "ProductName" cannot be located. xcodebuild: error: SDK "iPhoneOS" cannot be located. xcodebuild: error: SDK "iPhoneOS" cannot be located. Makefile:86: *** A path to a component of the SDK specifies a directory that does not exist (SDKROOT=). Stop.
这可以通过编辑main makefile轻松修复。在本文所使用的样本中,我将SDK_PLATFORM变量设置为“iOS 9.3”就足够了。
问题2:缺少工具的执行权限
你可能会遇到的下一个问题是:
make: execvp: ./tools/generate_debug_hashes.py: Permission denied
这是因为tools/目录中的所有内容都丢失了执行权限。可以轻松修复:
sudo chmod +x tools/*
问题3:缺少embedded_device_map
接下来你需要做的是将embedded_device_map添加到/usr/local/bin或/usr/bin:
%%%%%% library_list iBoot makefiles/device_map.mk:15: *** Cannot locate embedded_device_map - device map queries will fail.. Stop. make: *** [library_list-iBoot] Error 2
embedded_device_map是一个很小的shell脚本,可以从device_map.db进行查询。该脚本可以在HomeDiagnostics.pkg中找到,另外,它还需要image3maker和img4payload,但它们并不重要。
问题4:缺少device_map.db
显然,如果没有数据库来查询,embedded_device_map是无用的。如果没有数据库,你会得到一些很模糊的信息:
%%%%%% library_list iBoot apps/iBoot/iBoot.mk:162: *** multiple target patterns. Stop. make: *** [library_list-iBoot] Error 2
device_map.db也可以在HomeDiagnostics.pkg中找到。你可以通过在makefiles/device_map.mk中读取DEVICEMAP_DATABASE变量或尝试构建SecureROM来找到放置它的位置,它将出现在应该放置的位置。
device_map.db是SQLite 3数据库,它定义了目标的属性(因为大多数属性对于构建iBoot是没用的,很可能是在其他地方使用的。例如,在Purple Restore中有它的plist版本),以及可以为它构建哪些BUILD_STYLE。
问题5:未使用的变量
对于第二阶段的引导程序,会出现错误:
CC build/n41-iBEC-DEBUG/lib/macho/macho.o lib/macho/macho.c:29:17: error: unused variable 'gkalsr_debug'
解决方案非常简单,只需在lib/macho/macho.c中删除或注释该变量即可。
问题6:-lcompiler_rt-static
当构建快要完成时,就要将所有组件组装到一个映像中,这样得到的结果如下。
LD build/n42-iBEC-DEVELOPMENT/iBEC.sys using -L/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.3.sdk/usr/local/lib -lcompiler_rt-static ./build/lib-armv7-thumb-DEVELOPMENT/lib/libbuiltin/LIBBUILTIN.a ld: warning: directory not found for option '-L/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.3.sdk/usr/local/lib' ld: library not found for -lcompiler_rt-static clang: error: linker command failed with exit code 1 (use -v to see invocation) make[2]: *** [build/n42-iBEC-DEVELOPMENT/iBEC.sys] Error 1 make[1]: *** [build-n42-iBEC-DEVELOPMENT] Error 2
这也很容易解决,只需从makefiles/build.mk中的_RUNTIME_FLAGS变量中删除-lcompiler_rt-static标记即可。
最后,如果一切都顺利解决了,你应该看到以下的结果。
STRIP build/n41-iBEC-DEBUG/iBEC.stripped dSYM build/n41-iBEC-DEBUG/iBEC.sys.dSYM SIZE build/n41-iBEC-DEBUG/iBEC.size STRIP build/n42-iBEC-DEVELOPMENT/iBEC.stripped dSYM build/n42-iBEC-DEVELOPMENT/iBEC.sys.dSYM STRIP build/n41-iBEC-DEVELOPMENT/iBEC.stripped SIZE build/n42-iBEC-DEVELOPMENT/iBEC.size dSYM build/n41-iBEC-DEVELOPMENT/iBEC.sys.dSYM SIZE build/n41-iBEC-DEVELOPMENT/iBEC.size STRIP build/n42-iBEC-DEBUG/iBEC.stripped dSYM build/n42-iBEC-DEBUG/iBEC.sys.dSYM SIZE build/n42-iBEC-DEBUG/iBEC.size __TEXT __DATA __OBJC others dec hex 380928 73728 0 0 454656 6f000 __TEXT __DATA __OBJC others dec hex 344064 73728 0 0 417792 66000 BIN build/n41-iBEC-DEBUG/iBEC.bin BIN build/n41-iBEC-DEVELOPMENT/iBEC.bin __TEXT __DATA __OBJC others dec hex 344064 73728 0 0 417792 66000 0+0 records in 0+0 records out 0 bytes transferred in 0.000011 secs (0 bytes/sec) 0+0 records in 0+0 records out 0 bytes transferred in 0.000010 secs (0 bytes/sec) BIN build/n42-iBEC-DEVELOPMENT/iBEC.bin 0+0 records in 0+0 records out 0 bytes transferred in 0.000008 secs (0 bytes/sec) __TEXT __DATA __OBJC others dec hex 380928 73728 0 0 454656 6f000 BIN build/n42-iBEC-DEBUG/iBEC.bin 0+0 records in 0+0 records out 0 bytes transferred in 0.000009 secs (0 bytes/sec) 348160+0 records in 348160+0 records out 348160 bytes transferred in 1.518022 secs (229351 bytes/sec) 348160+0 records in 348160+0 records out 348160 bytes transferred in 1.523777 secs (228485 bytes/sec) 385024+0 records in 385024+0 records out 385024 bytes transferred in 1.682545 secs (228834 bytes/sec) 385024+0 records in 385024+0 records out 385024 bytes transferred in 1.622805 secs (237258 bytes/sec)
在build/目录中,你将找到包含已编译iBoot的子目录。 * .sys是没有经过strip()处理的Mach-O,它在反汇编程序中非常好用,因为每个函数甚至一些变量都有它们的原有名称。 * .bin是你可以在设备上加载的二进制文件。
调整device_map.db以支持加载A5处理器的设备
如上所述,device_map.db是SQLite3数据库。可以使用embedded_device_map轻松获取其架构:
embedded_device_map -db device_map.db -schema
如你所见,它由三个Table控件组成:
1.Targets是最重要的TABLE,定义了每个支持的设备的属性。有很多属性,但只有一些属性似乎对构建iBoot很重要:Target,TargetType,Platform,ChipID,SecurityEpoch,CryptoHashMethod,ProductID(似乎并不重要)和ImageFormat;查看makefiles/device_map.mk,可以进行属性检查。复制其中一个目标或只取一个现有目标,并用数据填充这些属性。
2.ManifestsTABLE定义了来自manifestType的Targets设备的manifestId,
manifestType的有效值为Debug,Development,Production,FactoryFA和VendorInstall)。使用你在Targets TABLE中为每个manifestType创建的Target的TargetType属性,替换那些不重要设备的Target属性:
3.Files TABLE定义了具有指定manifestId的文件的manifest属性;