如何構建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__OBJCothersdechex 380928 73728004546566f000 __TEXT__DATA__OBJCothersdechex 344064737280041779266000 BIN build/n41-iBEC-DEBUG/iBEC.bin BIN build/n41-iBEC-DEVELOPMENT/iBEC.bin __TEXT__DATA__OBJCothersdechex 344064737280041779266000 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__OBJCothersdechex 38092873728004546566f000 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屬性: