從新編譯 FridaGadget 使其更好地用於非越獄機的代碼調試和自動化測試

背景

Frida 在設計之初主要是用於應用的逆向工程,使用方法通常是在越獄環境下動態注入,在非越獄環境下使用 FridaGadget 時,因爲其寫死了 LC_ID_DYLIBInstall 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

修改 Install Name

對於包裝成 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

一個 Framework 須要包含 dylib、Info.plist 和 modulemap 等信息,不然 Xcode 在編譯時會報錯(特別是缺乏 Info.plist),這裏有個取巧的方案是建立一個名爲 FridaGadget 的 Cocoa Touch Framework 工程,Build 後將二進制替換爲真正的 FridaGadget,即完成了 FridaGadget.framework 的包裝。ruby

這裏注意一個簽名問題,FridaGadget.dylib須要先用本身的開發者帳號從新簽名一次,不然bash

打成 Pod 庫

若是直接使用動態庫,須要在 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

既然要從新編譯,咱們能夠直接指定 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 的編譯相對比較簡單,參考 官方文檔 便可,這裏說幾個編譯過程當中遇到的坑。

  1. 建議使用 Node 8.0 及以上的環境;
  2. 先執行 make core-ios 再執行 make gadget-ios
  3. Build 過程須要建立一個證書來簽名,具體方式參考 官方文檔
  4. 在 Node 高版本執行失敗時,先切換到低版本(例如 Node 5.9.1),隨後可能會在 npm install 過程當中遇到錯誤,再切換到高版本便可;

隨後再按照相同的步驟,將 FridaGadget 封裝成 Framework,再打包成 Pod 庫,再結合環境控制,便可完美的將 FridaGadget 用於正向開發過程當中,環境控制也強有力的保證了 FridaGadget 不會被打包到正式環境。

相關文章
相關標籤/搜索