概述
前面經過分析與調試,瞭解了程序的執行邏輯。現在想改變執行邏輯,腦海裏也大致有了新邏輯,例如讓判斷是否是會員的函數始終返回 true。那麼怎麼把新邏輯應用到程序中呢?這是本文要介紹的。
Hook,鉤子,用來改變程序執行流程。iOS 中有以下幾種方式:
- Method Swizzling:利用 OC runtime 特性,對 OC 方法重排。
- fishhook:利用 Mach-O 格式程序加載原理修改符號表,對 C 函數重排。
- Cydia Substrate:Cydia 底層框架,提供對 OC 方法、C 函數的重排接口。
Hook 原理
Method Swizzling
原理比較簡單,概括就是:OC 方法 = 方法名 + C 函數地址,我們交換兩個 OC 方法的實際 C 函數地址,即實現方法重排。細節可以直接看以前寫的文章 。
fishhook
fushhook 的核心思想就是修改懶加載和非懶加載符號表,源碼地址。
前面提到過懶加載與非懶加載符號綁定過程,實際上就是蘋果的位置代碼獨立技術(PIC)。由於地址空間隨機化的存在,不能使用固定的地址,於是調用符號實際去調用函數樁,函數樁內讀取符號表上的值並調用。目標功能函數的真實地址由 dyld 獲取後寫入數據段中的符號表。fishhook 就是利用 PIC 技術的特點,實現 C 語言符號的“動態”特性。給定目標函數名和要替換的函數指針,fishhook 對目標函數在符號表中的值重新綁定,讓其指向要替換的函數地址,這樣就實現了 C 函數的重排。
Cydia Substrate
Cydia 底層框架,提供:
MSHookMessageEx 函數用來 hook OC 方法,原理就是對上述 Method Swizzling 的封裝。
MSHookFuntion 函數可以 hook 任意 C 函數,原理是直接修改了內存中的彙編指令,調用目標函數時,會直接跳轉到自定義函數。這種 hook 方式只能在越獄設備上使用,在非越獄設備上如果想使用這種思路,必須修改靜態文件中的指令。
Hook 工具
Theos
爲了更便捷地進行逆向開發,有人封裝了上面的 Hook 原理,編寫了注入、攔截工具 Theos。
安裝
先用 brew 安裝 ldid、fakeroot、dpkg,其中 dpkg 需要指定版本 1.18.10,可以通過執行 brew install --from-bottle https://raw.githubusercontent.com/Homebrew/homebrew-core/7a4dabfc1a2acd9f01a1670fde4f0094c4fb6ffa/Formula/dpkg.rb
安裝。最近 raw.githubusercontent.com 的 DNS 被污染,可能會出現 443 Connection Refused 的錯誤,可以修改系統中的 hosts 文件,添加該網站的 IP 地址 199.232.28.133 來恢復訪問。api.github.com 同理。
然後執行 git clone --recursive https://github.com/theos/theos.git
下載 Theos,下載後將 Theos 根目錄和 bin 目錄添加到環境變量,後面會用到。
export THEOS=/path/of/theos
export PATH=$THEOS/bin:$PATH
export THEOS_MAKE_PATH=$THEOS/makefiles
至此安裝完成。
使用
執行 nic.pl 開始創建項目,模版選擇 iphone/tweak,按提示輸入項目名,項目 ID,創建者,目標應用的 Bundle ID 等信息,創建完成後,自動生成四個文件:Makefile,編寫代碼的 Tweak.x,指定注入目標 Bundle ID 的 plist 文件,指定 deb 包的一些信息的 control。
Theos 爲了讓逆向開發更簡便,對前面的 hook 原理進行封裝,然後提供了一種新的語法。即使是沒有讀過 runtime 源碼、不瞭解程序加載等底層問題,使用 Theos 仍然可以寫 hook 代碼做逆向開發。例如,我要 hook 番茄Todo 應用中 SystemUtil 類中的 +shouldSH 函數,在 Tweak.x 中編輯如下:
%hook SystemUtil
+ (_Bool)shouldSH {
return 1;
}
%end
編譯時,Theos 語法會被轉換爲真正的代碼。其中 %hook 類名
用於指定要 hook 的類,然後在裏面寫需要 hook 的方法,如果參數或返回值涉及到閉包,則使用 id 類型替代。%log 打印日誌,%orig 調用原來的方法。
然後編輯 Makefile,Theos 已自動生成了部分內容,包括目標進程名,項目名,源碼文件,編譯參數。
INSTALL_TARGET_PROCESSES = TomatoTime
include $(THEOS)/makefiles/common.mk
TWEAK_NAME = MyTomato
MyTomato_FILES = Tweak.x
MyTomato_CFLAGS = -fobjc-arc
include $(THEOS_MAKE_PATH)/tweak.mk
一般還需要手動添加目標架構和目標系統版本:
ARCHS = arm64
TARGET = iphone:latest:8.0
在命令行執行 make,沒有錯誤的話會生成一個 .theos 文件夾,裏面包含一個 MyTomato.dylib。可以手動把這個 dylib 注入到目標 App,當然 Theos 肯定也封裝了這個步驟,執行 make package 打包成 deb,成功後會生成 packages 文件夾,裏面包含一個 deb 文件。現在要把該文件安裝到手機中,如果用 ssh 傳輸則用手機的 IP 以及端口號 22,如果用 USB 連接,先用 iproxy 轉發iproxy 3333 3333
,端口號是 3333,IP 用 localhost。然後編輯 Makefile,添加對應方式的值:
export THEOS_DEVICE_IP=localhost
export THEOS_DEVICE_PORT=3333
執行 make install 即可安裝。安裝成功後在手機的 /Library/MobileSubstrate/DynamicLibraries 目錄下可以看到 MyTomato.dylib 和 plist 文件。如果想查看動態庫有沒有被加載,除了直接觀察 App 運行外,電腦打開 Console.app,USB 連接手機後打開 App 就可以看到 App 的日誌。編譯前在代碼文件裏寫一個 __attribute__((constructor))
函數,函數中打印自定義的信息,即可在日誌中觀察到。或者用 lldb 給原函數打斷點,觀察函數執行邏輯是否已改變。
更多語法
逆向工程中可能有更復雜的需求,下面介紹一些常用語法。
獲取類對象 %c
使用原 App 內的類時,必須使用 runtime 函數動態獲取:Class objc_getClass(const char *aClassName)
,Theos 將其封裝成了一個簡潔的語法 %c(aClassName)
。
個別文件應用 MRC
如果源文件有兩個,MyTomato_FILES = Tweak.x MySwizzle.m
,其中 MySwizzle.m 必須用 MRC,則單獨爲其指定編譯參數:MySwizzle.m_CFLAGS = -fno-objc-arc
。
給類添加方法 %new
在要 hook 的類內,聲明 %new,下面寫方法即可。添加的是實例方法,熟悉 runtime 的話可以猜出來實際是封裝的 class_addMethod 函數。如果想給某個類添加靜態方法呢?根據 runtime 原理,需要依次用 objc_getClass 和 object_getClass 獲取元類對象,然後 class_addMethod 給元類添加方法。由此可見,Theos 並不是萬能的,只有熟悉 runtime 才能靈活地編寫代碼。
添加資源文件
如果有添加圖片等文件需求,則需要在項目根目錄新建 layout 文件夾,這個文件夾將來實際映射到手機根目錄。因此一般都會在 layout 裏建多層目錄使用,例如 layout/Library/Application Support/TomatoTime/。
使用第三方庫
和命令行編譯差不多,將庫文件複製到項目中自定義的目錄下,指定 CFLAGS、LDFLAGS、LIBRARIES、FRAMEWORKS,在代碼中直接可以導入頭文件即可使用。
快速生成代碼
如果要對某個類中的所有方法進行 hook,監控該類所有的函數調用,則對 class-dump 得到的頭文件使用 logify.pl 命令,輸出所有方法的 hook 函數。如果涉及到未知的類,手動添加 @class 聲明。輸出結果保存到一個 .xm 文件或其他位置,將該文件添加到 Makefile 編譯文件集合。
MonkeyDev
Theos 是一個命令行工具,對於習慣使用 Xcode 的 iOS 開發者並不友好。於是《iOS 應用逆向與安全》的作者開發了 MonkeyDev,相當於對 Theos 再次封裝,讓越獄開發更人性化,是一款插件開發集成神器。
安裝
在完成 Theos 安裝後,下載 MonkeyDev,然後執行 sudo ./MonkeyDev/bin/md-install
。該文件夾下也有卸載、更新腳本。
使用
打開 Xcode 創建項目,在 iOS 一欄最下面選擇 Logos Tweak,創建完成後即可看到 Theos 中熟悉的幾個文件,按照 Theos 項目的規則編輯即可。其中的 Makefile 被 Xcode 工程代替,讓不熟悉 make 的開發者也可以開發越獄插件。因此前面修改 Makefile 的內容現在改爲修改項目文件,在項目 Build Settings 最後一塊,主要是設置設備 IP 和端口號。需要注意的是,項目默認 theos 和 MonkeyDev 的路徑保存在 /opt/theos 和 /opt/MonkeyDev,修改項目文件或者把對應的文件放到 /opt 目錄下。項目編寫完成後,只需要 Build 就完成了 Theos 的三步操作:make,make package,make install。
注意
第八九章還沒寫,有機會再補充,不過不重要。
八 其他知識
九 一些工具的源碼解讀