如何對iOS應用進行修改并重新簽名
前言
在某些場景下,你可能需要在沒越獄的iOS設備上運行修改過的iOS應用,特別是當手上已越獄的iPhone突然變磚,只能被迫升級到非越獄版本的iOS系統(tǒng)時,這種需求顯得更加迫切。再如,你需要使用這項技術來動態(tài)分析測試應用程序,或者你可能需要使用GPS欺騙手段來繞過Pokemon的鎖區(qū)限制,在非洲地區(qū)捕捉寵物小精靈,而又不想承擔越獄帶來的安全風險。無論是哪種情況,你都可以使用本文介紹的方法對某個經(jīng)過修改的應用重新簽名并在自己的設備上成功運行。需要注意的是,這種技術僅在應用程序不是經(jīng)過FairPlay加密(即從應用商店上下載)時才能正常工作。
由于Apple采用了較為復雜的配置及代碼簽名系統(tǒng),在iOS系統(tǒng)上對程序進行重新簽名會比想象中困難得多。只有使用正確的配置文件以及完全正確的代碼簽名頭,iOS系統(tǒng)才會允許應用程序正常運行。這使得你需要熟知許多概念:如不同類型的證書、BundleID、應用ID、團隊ID,以及如何使用Apple的編譯工具將這些東西結(jié)合在一起。簡而言之,要想讓不經(jīng)過默認方法(即XCode環(huán)境)編譯生成的程序在iOS上正確運行將會是一個困難重重的過程。
我們在本文中使用的工具集包括optool、Apple的編譯環(huán)境以及一些shell命令。我們所使用的方法靈感來自于Vincent Tan的Swizzler項目。此外,NCC工作組采用其他工具集也完成了同樣的工作。
要復現(xiàn)下文列出的步驟,請從OWASP Mobile Testing Guide軟件倉庫中下載UnCrackable Ios App Level 1這個示例應用,我們的目標是修改UnCrackable這個應用,使它在啟動時加載FridaGadget.dylib,以便后續(xù)可以用Frida來加載該應用進行測試。
獲取開發(fā)者配置文件(Provisioning Profile)及證書
開發(fā)者配置文件是由Apple簽名的一個plist文件,它將開發(fā)者的代碼簽名證書列入一個或多個設備的白名單中。話句話說,Apple通過這種方式顯式允許開發(fā)者的應用程序在某些設備的上下文環(huán)境中運行(如對特定設備進行調(diào)試)。配置文件還列出了應用程序所能獲得的權限信息。代碼簽名證書包含了開發(fā)者在對應用進行簽名時所用到的私鑰。
1)使用iOS開發(fā)者賬號時
如果你之前使用Xcode開發(fā)和部署過iOS應用,你已經(jīng)獲得了一個代碼簽名證書。你可以使用security工具列出你現(xiàn)有的簽名身份碼:
- $ security find-identity -p codesigning -v
- 1) 61FA3547E0AF42A11E233F6A2B255E6B6AF262CE "iPhone Distribution: Vantage Point Security Pte. Ltd."
- 2) 8004380F331DCA22CC1B47FB1A805890AE41C938 "iPhone Developer: Bernhard Müller (RV852WND79)"
已經(jīng)注冊的開發(fā)者可以從Apple開發(fā)者門戶上獲取配置文件。首先你需要創(chuàng)建一個新的App ID,之后發(fā)起一個配置文件請求,以便該App ID能在你的設備上運行。要是只是想對應用進行重新打包,那么選擇哪個App ID并不重要,你甚至可以重復使用之前使用過的App ID。關鍵點在于你需要一個正確匹配的配置文件,因為需要將調(diào)試器附加到應用上進行工作,請確保你創(chuàng)建的是一個開發(fā)配置文件(development provisioning profile)而不是分發(fā)配置文件(distribution profile)。
在下文的shell命令中,我使用了自己的簽名身份,該簽名身份與我公司的開發(fā)團隊相關聯(lián)。我創(chuàng)建了名為“sg.vp.repackaged”的app-id,以及一個名為“AwesomeRepackaging”的配置文件,生成了一個名為“AwesomeRepackaging.mobileprovision”的文件,請你在實際操作時將這些字段替換為你自己的文件名。
2)使用普通iTunes賬號時
幸運的是,即便你不是付費開發(fā)者,Apple也會給你發(fā)放一個免費的開發(fā)配置文件。你可以使用自己的Apple賬戶,通過Xcode環(huán)境獲得該配置文件——只需要創(chuàng)建一個空的iOS工程,并從應用容器中提取embedded.mobileprovision即可。NCC博客對整個過程進行了詳細描述。
獲取到配置文件后,你可以使用security工具檢查其內(nèi)容。除了證書及設備信息外,你還可以從配置文件中找到應用所被賦予的運行權限。這些信息在后續(xù)的代碼簽名工作中都需要用到,因此你需要將它們提取到單獨的plist文件中,如下所示。
- $ security cms -D -i AwesomeRepackaging.mobileprovision > profile.plist
- $ /usr/libexec/PlistBuddy -x -c 'Print :Entitlements' profile.plist > entitlements.plist
- $ cat entitlements.plist
- <?xml version="1.0" encoding="UTF-8"?>
- <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
- <plist version="1.0">
- <dict>
- <key>application-identifier</key>
- <string>LRUD9L355Y.sg.vantagepoint.repackage</string>
- <key>com.apple.developer.team-identifier</key>
- <string>LRUD9L355Y</string>
- <key>get-task-allow</key>
- <true/>
- <key>keychain-access-groups</key>
- <array>
- <string>LRUD9L355Y.*</string>
- </array>
- </dict>
- </plist>
你還需要檢查一下生成的plist文件,看文件內(nèi)容是否正確生成。
其中,應用標識(App ID)是由Team ID(LRUD9L355Y)以及Bundle ID(sg.vantagepoint.repackage)組合而成。此配置文件僅對使用該App ID的應用有效。 “get-task-allow” 鍵值也十分重要,當該鍵值設為“true”時,其他進程(如調(diào)試服務器)可以被允許附加到該應用程序上,因此,在分發(fā)配置文件中,需要將該鍵值設置為“false”。
其他的準備措施
要想讓我們的應用在啟動時加載一個附加庫,我們使用某些方法將一個附加加載命令插入到主執(zhí)行文件的Mach-O頭中。我們使用optool來自動化完成這個步驟:
- $ git clone https://github.com/alexzielenski/optool.git
- $ cd optool/
- $ git submodule update --init --recursive
不使用Xcode的情況下,我們可以使用ios-deploy工具來完成應用的部署及調(diào)試。
- git clone https://github.com/phonegap/ios-deploy.git
- cd ios-deploy/
- git submodule update --init --recursive
你需要FridaGadget.dylib完成本文示例。
- $ curl -O https://build.frida.re/frida/ios/lib/FridaGadget.dylib
除了上述工具,我們還將使用OS X及XCode附帶的標準工具集,請確保你的環(huán)境中已安裝Xcode命令行開發(fā)者工具。
應用的修改、重新打包和重新簽名
IPA文件其實就是ZIP文件,因此我們可以解壓ipa包,將FridaGadget.dylib拷貝至app目錄,之后使用optool將load命令添加到“UnCrackable Level 1”這個應用中。
- $ unzip UnCrackable_Level1.ipa
- $ cp FridaGadget.dylib Payload/UnCrackable\ Level\ 1.app/
- $ optool install -c load -p "@executable_path/FridaGadget.dylib" -t Payload/UnCrackable\ Level\ 1.app/UnCrackable\ Level\ 1
- Found FAT Header
- Found thin header...
- Found thin header...
- Inserting a LC_LOAD_DYLIB command for architecture: arm
- Successfully inserted a LC_LOAD_DYLIB command for arm
- Inserting a LC_LOAD_DYLIB command for architecture: arm64
- Successfully inserted a LC_LOAD_DYLIB command for arm64
- Writing executable to Payload/UnCrackable Level 1.app/UnCrackable Level 1...
上述操作肯定會使主執(zhí)行文件的代碼簽名無效,因此應用不能在非越獄設備上運行。你需要替換其中的配置文件,使用配置文件中列出的證書對主執(zhí)行文件及FridaGadget.dylib進行簽名。
首先,我們向包中添加自己的配置文件:
- $ cp AwesomeRepackaging.mobileprovision Payload/UnCrackable\ Level\ 1.app/embedded.mobileprovision\
接下來,我們要確保Info.plist中的BundleID與配置文件中的BundleID一致。Codesign在簽名過程中會從Info.plist中讀取BundleID信息,兩者如果不一致將會導致應用簽名無效。
- $ /usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier sg.vantagepoint.repackage" Payload/UnCrackable\ Level\ 1.app/Info.plist
***,我們使用codesign工具來對修改過的應用重新簽名/
- $ rm -rf Payload/F/_CodeSignature
- $ /usr/bin/codesign --force --sign 8004380F331DCA22CC1B47FB1A805890AE41C938 Payload/UnCrackable\ Level\ 1.app/FridaGadget.dylib
- Payload/UnCrackable Level 1.app/FridaGadget.dylib: replacing existing signature
- $ /usr/bin/codesign --force --sign 8004380F331DCA22CC1B47FB1A805890AE41C938 --entitlements entitlements.plist Payload/UnCrackable\ Level\ 1.app/UnCrackable\ Level\ 1
- Payload/UnCrackable Level 1.app/UnCrackable Level 1: replacing existing signature
安裝及運行修改后的應用
一切準備就緒,你可以使用以下命令在設備上部署和運行經(jīng)過修改后的應用。
- $ ios-deploy --debug --bundle Payload/UnCrackable\ Level\ 1.app/
如果一切順利,應用應該可以在附加IIdb的調(diào)試模式下在設備上啟動運行。Frida應該也可以正確加載到應用中運行,你可以使用frida-ps命令驗證這一點:
- $ frida-ps -U
- PID Name
- --- ------
- 499 Gadget
現(xiàn)在你可以使用Frida正常測試應用程序了。
故障排除
如果你在進行上述操作時發(fā)生錯誤,你可以檢查一下配置文件和代碼簽名頭是否正確匹配,通常的錯誤都是因為兩者不匹配導致的。這種情況下你可以參考Apple的官方文檔,了解整個系統(tǒng)的工作原理。另外,Apple的故障排除頁面也是一個不錯的參考資料。