iOS逆向開發(4):注入目標函數 | iOSOpenDev | MSHookFunction

從獲得APP的所有類聲明,到鎖定目標類與函數,現在是時候注入函數了。

所謂“注入函數”,小程的意思是讓APP執行到小程寫的代碼中,跟“鉤子”的概念一致。小程把個叫作iOS上的hook的技術。

本文介紹iOS注入函數的辦法。

在藉助框架之前,先介紹一個簡單的注入辦法,你可以“感性”地認識到“動態綁定”所帶來的注入。


(一)動態綁定的一個示例

(1)鎖定注入點

隨便找一個APP,classdump拿到所有類的結構信息。

比如,“微信”有一個類是這樣聲明的:
viewcontroller的繼承

這個類繼承於UIViewController,也就是有viewDidLoad這個消息處理函數。這裏演示把MMUIViewController::viewDidLoad函數給替換掉,讓它執行到新的函數中。

(2)寫注入代碼

先找一個熟悉的編輯器,創建一個文件,命名爲hookwx.m,然後在裏面添加這樣的代碼:
hookwx的代碼

然後是編譯的事。可以直接使用xcode來編譯出來.o文件,也可以用clang來編譯出來.o文件。比如,小程演示時使用的是iphone4手機,也就是armv7指令集,所以可以這樣編譯出obj文件:

clang -c hookwx.m -arch armv7 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS8.1.sdk

再使用ld來鏈接成動態庫(dylib):

ld -dylib -lsystem -lobjc -syslibroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS8.1.sdk/ -o hookwx.dylib hookwx.o -framework Foundation -framework UIKit -ios_version_min 6.0

以上編譯鏈接命令的參數跟小程使用的sdk版本有關,你如果嘗試的話應該選擇對應的參數。

(3)拷貝dylib到DynamicLibraries

scp hookwx.dylib [email protected]:/Library/MobileSubstrate/DynamicLibraries/

這時,還要創建一個plist,來指定讓哪個APP來加載這個dylib(對於ios8.0以後的系統需要指定哪個APP),具體操作參照上一篇文章--介紹reveal的使用時創建了plist,就是這個操作了。“微信”的bundleID是“com.tencent.xin”或“com.tencent.xin1”,指定讓它加載這個dylib(可指定若干個bundleID)。

記得把plist文件也拷貝到DynamicLibraries目錄中。

(4)驗證效果

啓動“微信”,使用socat觀察log輸出,可以看到:

Dec  2 11:22:05 810 MicroMessenger[974] <Warning>: =======in initialize=================
...
Dec  2 11:24:48 810 MicroMessenger[974] <Warning>: -------------in new_viewDidLoad----------

也就是,“微信”加載了小程寫的dylib,而且也執行到新的函數中。


以上的例子,只是“感性地”知道注入的辦法,而在實際使用場景,更應該藉助一些成熟的可以做到注入的框架。

小程較常見的兩個框架,一個叫fishhook,一個叫MobileSubstrate。

fishhook,是facebook的一個開源工具,可以在運行時修改目標函數的地址,讓控制點執行到自己的代碼。因爲需要知道目標函數的名字,這對於c運行時庫的函數來說是適用的,或者對於能定位到函數名的情況也是適用的,但對於連名字都拿不到的情況(比如只能定位到代碼地址)就不適用。如果只能拿到函數的地址,那可以考慮用MobileSubstrate的MSHookFunction來做到注入。

MobileSubstrate(也叫CydiaSubstrate,以下簡稱爲MS),最大的一個作用,是可以動態綁定新的執行函數,這個功能已經能滿足我們大部分的需求。比如,MS提供的函數MSHookMessageEx,可以用來對oc代碼進行hook,原理上利用了oc的runtime特性(運行時替換執行函數)。

MS提供的函數MSHookFunction,可以用來對c代碼進行hook,比如很多APP在寫文件時都會用到write或fwrite函數,那通過對這兩個函數進行hook,就能看到寫入文件的數據,可以這樣寫代碼:
MSHookFunction示例

但直接使用MS的函數,並不是本文介紹的重點。從“實用”的角度,小程要介紹的是iOSOpenDev的使用。

(二)iOSOpenDev的使用

theos跟iOSOpenDev,都是對MS庫進行封裝的開發工具包,這樣的工具包可以簡化開發的操作。這裏介紹iOSOpenDev的使用。

安裝iOSOpenDev後,就可以使用xcode來完成插件的開發,或者簡單地生成dylib庫。

(1)安裝iOSOpenDev

包裝包地址:

http://iosopendev.com/download/

如果你安裝成功,則不用參考小程失敗的例子。

以下是小程安裝失敗並動手解決的例子。


安裝時失敗,/var/log/system.log裏面記錄着“安裝器遇到了一個錯誤,導致安裝失敗。請聯繫軟件製造商以獲得幫助。”。

雖然安裝失敗,但是在/opt下面還是創建了三個目錄(紅框內):
iosopendev目錄

在iOSOpenDevSetup/bin裏面已經有一個shell腳本:iod-setup,這個是安裝的腳本。

直接運行iod-setup來安裝:sudo ./iod-setup base

發現總是在下載某個東西時失敗,打開iod-setup來定位,發現有三個downloadGithubTarball的地方,
直接註釋掉,然後手動去下載這三個東西,並拷貝到iOSOpenDev目錄:

分別下載下面三個地址的zip包:
https://github.com/kokoabim/iOSOpenDev
https://github.com/kokoabim/iOSOpenDev-Xcode-Templates
https://github.com/kokoabim/iOSOpenDev-Framework-Header-Files

解壓上面下載的zip包,拷貝:
sudo cp -r iosopendev-master/* /opt/iosopendev/

在iosopendev目錄裏面,sudo mkdir templates,然後:
sudo cp -r iosopendev-xcode-templates-master/* /opt/iosopendev/templates

在iosopendev目錄裏面,sudo mkdir frameworks,然後:
sudo cp -r iosopendev-framework-header-files-master/* /opt/iosopendev/frameworks

再次安裝:

sudo ./iod-setup base

指定最新xcode sdk:

sudo ./iod-setup sdk -sdk iphoneos


小程還遇到另一種情況:在一臺imac上,xcode8.3.2,安裝包失敗後,直接sudo ./iod-setup base,成功。
所以,上面不成功的情況,有可能是從github下載時網絡上失敗導致。

最終安裝成功,表現爲:

1.
~/library/developer/xcode 裏面會多出
Templates/iosopendev

2. 
打開 ~/.bash_profile
會看到:
export iOSOpenDevPath=/opt/iOSOpenDev
export iOSOpenDevDevice=
export PATH=/opt/iOSOpenDev/bin:$PATH

3.
啓動xcode,新建工程,多出一個“iOSOpenDev”的模板。

就算使用iOSOpenDev,也有必要安裝theos,否則編譯時會有提示:

Preparing to run Xcode Build Phase for Logos Processor...
Failed to locate Logos Processor. Is Theos installed? If not, see http://iphonedevwiki.net/index.php/Theos/Getting_Started.

安裝theos很簡單(可以安裝完iOSOpenDev後,再安裝theos):

brew install dpkg ldid
sudo Git clone --recursive https://github.com/theos/theos.git /opt/theos
(2)使用iOSOpenDev的示例

創建項目,iOSOpenDev -> Logos Tweak (安裝後會有圖標)。

在項目中,可以找到一個後綴爲xm的文件,這個文件就是寫代碼的地方。iOSOpenDev會根據xm的內容編譯到mm中(xm不是必須要有的,但xm的語法比mm中的好懂多了)。

xm文件裏面的#error會提示你拷貝個libsubstrate.dylib過來。到/opt/iosopendev/lib裏面把libsubstrate.dylib拉到項目的Frameworks目錄。

再拉進一個UIKit.framework,因爲SpringBoard在UIKit裏面聲明,而這個例子就是對SpringBoard進行hook。

SpringBoard是系統的組件,在啓動機子時加載。

清空xm文件,寫代碼:
注入SpringBoard的一個例子

小程這裏用的UIAlertView是舊sdk支持的,如果是新版本的sdk,應該使用新的“提示框”類。

編譯,成功的話,會生成對應的動態鏈接庫,即xx.dylib。然後是plist文件,在項目中找到xx.plist,對它進行修改,指定讓哪一個APP啓動時加載這個dylib。

然後,把dylib與plist拷貝到DynamicLibraries目錄(小程有多次提到了)。其實,xcode可以在編譯後自行拷貝到手機,只需要這樣配置下項目(當然也要保證電腦可以ping到手機):

在build settings頁面,查找iOSOpenDevDevice,把內容設置爲IP,比如:192.168.1.101 ,讓xcode知道往哪臺手機安裝應用。然後編譯並安裝到手機:Project->Build For->Profiling。

注意,編譯時,目標設備哪一項,應該選擇Generic iOS Device, 否則會遇到一堆錯誤(選擇真機或模擬器都可能一堆編譯錯誤)。

安裝後可以到cydia的“已安裝”中看有沒有你的應用,也可以ssh到手機後查看:

dpkg -l

重啓機子(killall springboard),啓動時會看到彈出的alertview。


總結一下,本文內容較多,但主體是iOSOpenDev的使用,這個是注入APP的有效的工具。


hello world

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章