Frida 在設計之初主要是用於應用的逆向工程,使用方法通常是在越獄環境下動態注入,在非越獄環境下使用 FridaGadget 時,因爲其寫死了 LC_ID_DYLIB
的 Install Name
爲 @rpath/Framework/FridaGadget.dylib
,致使直接使用時必須在工程中建立一個名爲 Framework
的實體目錄。對於正向開發而言,須要對這類動態庫進行環境控制,即僅在 Debug 模式下引入,通常方法爲將動態庫打成 Pod,而後基於 CocoaPods 的語法去作環境控制。ios
對於常規的 Cocoa Touch Dynamic Framework,其 Install Name 通常爲 @rpath/SomeLib.framework/SomeLib
的形式,顯然 FridaGadget 的 Install Name 與其不符,爲了將 FridaGadget 打成 Pod,咱們不得不將其封裝成 Framework,以享受 CocoaPods 的自動簽名功能,這就要求修改 FridaGadget 的 Install Name 爲正確格式,並將其包裝成標準的 Framework 格式。git
其次,FridaGadget 爲了保證對啓動流程的控制,默認阻塞了進程,這會致使應用必須在 Frida Console Attach 後纔會繼續運行,這很適用於逆向工程,但對於正向開發者和測試者十分不利,更爲麻煩的是,FridaGadget.config 彷佛在非越獄環境下不生效,從而致使咱們沒法修改 FridaGadget 的默認行爲,這個問題彷佛只有修改源碼並從新編譯才能解決。github
對於包裝成 Framework 的問題,其實沒必要從新編譯 FridaGadget,只須要用 MachOView 打開動態庫文件,找到每一個架構的 LC_ID_DYLIB
並修改 Name
字段: macos
這裏的注意點是,Name 的存儲方法比較巧妙,是將其直接存儲在 LC_ID_DYLIB
這一條 Load Command 的尾部,經過第三個字段 String Offset 指定基於當前 Load Command 的偏移量,這一條指令的總長度爲 72,字符串從第 24 個字節開始存儲,所以字符串的總長度不能超過 47 (須要額外一位來存儲\0
),MachOView 提供了直接修改字符串值的方法,雙擊 Name 的 Data 行便可修改,圖中所示的就是修改後的值,字符串和二進制互轉可使用這個網站。npm
一個 Framework 須要包含 dylib、Info.plist 和 modulemap 等信息,不然 Xcode 在編譯時會報錯(特別是缺乏 Info.plist),這裏有個取巧的方案是建立一個名爲 FridaGadget 的 Cocoa Touch Framework 工程,Build 後將二進制替換爲真正的 FridaGadget,即完成了 FridaGadget.framework 的包裝。ruby
這裏注意一個簽名問題,FridaGadget.dylib須要先用本身的開發者帳號從新簽名一次,不然bash
若是直接使用動態庫,須要在 Xcode 中手動配置一個 Copy File 的 Build Phase 來實現對動態庫的簽名和拷貝,爲了將這個過程自動化,咱們能夠將 FridaGadget.framework 打成 Pod 庫,一方面 Pod 會爲咱們自動生成工程配置,另外一方面也能夠基於 Podfile 的 configurations
實現環境控制。架構
CocoaPods 包含動態庫的方式很簡單,只須要聲明一個 vendored_frameworks
:測試
s.vendored_frameworks = "FridaGadget.framework"
複製代碼
對於聲明瞭 vendored_frameworks
的 Pod 庫,CocoaPods 會自動爲其建立 Pods-ProjectName-frameworks.sh 的腳本,並添加一個 Embed Pods Framework 的 Build Phase 來完成動態庫的簽名,這裏有個坑咱們須要先手動重簽名依次 FridaGadget.dylib,不然可能會致使 Pods 腳本中籤名失敗,重簽名的方法可參考 Frida Doc。網站
隨後,將 Pod 庫部署到企業私有環境或是公庫下,便可經過 Podfile 直接引入 FridaGadget:
# 注意我尚未將其上傳到公庫,所以你沒法直接這麼引入
pod 'FridaGadget', :configurations => ['Debug']
複製代碼
這種方式完美解決了 FridaGadget 的環境控制問題,可是啓動時自動阻塞進程不是咱們想要的(畢竟是正向開發環境,只是偶爾使用 Frida 來調試和自動化測試),這個問題在於 Frida 默認採用了阻塞方式,要修改能夠經過在工程中建立一個 FridaGadget.config 來修改 on_load 策略,但非越獄環境 FridaGadget 下彷佛讀不到 Main Bundle 中的 config 文件,所以咱們只剩下一條路:修改源碼。
首先下載 Frida 源碼,具體方式請參考 Build Frida,先完成 clone 便可,隨後咱們須要定位到 on_load
相關邏輯的代碼,全工程搜索 on_load
首先會找到一堆看起來不像是人寫的 C 代碼,這些代碼是由 Vala Language 自動生成的,所以核心代碼都在 Vala 裏,隨後咱們找到 gadget.vala,從中搜索 on_load
可找到默認等待的邏輯,將 WAIT 修改成 RESUME 便可:
public LoadBehavior on_load {
get;
set;
default = LoadBehavior.RESUME;
}
public enum LoadBehavior {
RESUME,
WAIT
}
複製代碼
很顯然,將 default 改成 LoadBehavior.RESUME
便可。
既然要從新編譯,咱們能夠直接指定 Install Name 爲 Framework 須要的形式,這個配置位於 Makefile.macos.mk
的第 36四、371 行,直接修改便可:
build/.core-macos-stamp-%: build/%/lib/pkgconfig/frida-core-1.0.pc
@if [ -z "$$MAC_CERTID" ]; then echo "MAC_CERTID not set, see https://github.com/frida/frida#macos-and-ios"; exit 1; fi
. build/frida-meson-env-macos-$(build_arch).rc \
&& $$CODESIGN -f -s "$$MAC_CERTID" -i "re.frida.Server" build/$*/bin/frida-server \
## Install Name
&& $$INSTALL_NAME_TOOL -id @rpath/../FridaGadget.framework/FridaGadget build/$*/lib/frida-gadget.dylib \
&& $$CODESIGN -f -s "$$MAC_CERTID" build/$*/lib/frida-gadget.dylib
@touch $@
build/.core-ios-stamp-%: build/%/lib/pkgconfig/frida-core-1.0.pc
@if [ -z "$$IOS_CERTID" ]; then echo "IOS_CERTID not set, see https://github.com/frida/frida#macos-and-ios"; exit 1; fi
. build/frida-meson-env-macos-$(build_arch).rc \
&& $$CODESIGN -f -s "$$IOS_CERTID" --entitlements frida-core/server/frida-server.xcent build/$*/bin/frida-server \
## Install Name
&& $$INSTALL_NAME_TOOL -id @rpath/FridaGadget.framework/FridaGadget build/$*/lib/frida-gadget.dylib \
&& $$CODESIGN -f -s "$$IOS_CERTID" build/$*/lib/frida-gadget.dylib
@touch $@
複製代碼
Frida 的編譯相對比較簡單,參考 官方文檔 便可,這裏說幾個編譯過程當中遇到的坑。
make core-ios
再執行 make gadget-ios
;隨後再按照相同的步驟,將 FridaGadget 封裝成 Framework,再打包成 Pod 庫,再結合環境控制,便可完美的將 FridaGadget 用於正向開發過程當中,環境控制也強有力的保證了 FridaGadget 不會被打包到正式環境。