目錄
一、InlineHook新秀Dobby框架
由于最近研究InlineHook(內(nèi)聯(lián)鉤?),發(fā)現(xiàn)了?個(gè)不錯(cuò)的框架,Dobby(原名:HOOKZz)。這是?個(gè)全平臺(tái)的InlineHook框架,它?起來就和fishhook?樣,我們先看?下如何使?。
內(nèi)聯(lián)鉤?:所謂InlineHook就是直接修改?標(biāo)函數(shù)的頭部代碼。讓它跳轉(zhuǎn)到我們?定義的函數(shù)??執(zhí)?我們的代碼,從?達(dá)到Hook的?的。這種Hook技術(shù)?般?在靜態(tài)語?的HOOK上?
1.1 編譯Dobby
?先我們將代碼clone下來
#depth?于指定克隆深度,為1即表示只克隆最近?次commit.
git clone https://github.com/jmpews/Dobby.git --depth=1
注意由于這家伙是跨平臺(tái)的,所以項(xiàng)?并不是?個(gè)Xcode?程,我們要使?cmake將這個(gè)?程編譯成為Xcode?程。進(jìn)?Dobby?錄,創(chuàng)建?個(gè)?件夾,然后cmake編譯?程參考鏈接
cd Dobby && mkdir build_for_ios_arm64 && cd build_for_ios_arm64
cmake .. -G Xcode \
-DCMAKE_TOOLCHAIN_FILE=cmake/ios.toolchain.cmake \
-DPLATFORM=OS64 -DARCHS="arm64" -DCMAKE_SYSTEM_PROCESSOR=arm64 \
-DENABLE_BITCODE=0 -DENABLE_ARC=0 -DENABLE_VISIBILITY=1 -DDEPLOYMENT_TARGET=9.3 \
-DDynamicBinaryInstrument=ON -DNearBranch=ON -DPlugin.SymbolResolver=ON \
-DPlugin.Darwin.HideLibrary=ON -DPlugin.Darwin.ObjectiveC=ON-DDOBBY_GENERATE_SHARED=OFF
編譯完成后,會(huì)?成?個(gè)Xcode?程

接下來選擇DobbyX Target、Bitcode設(shè)置為YES編譯Xcode?程。?成我們的Framework

1.2 導(dǎo)?DobbyX.Framework
bitcode問題
我們新建?個(gè)?程開始使?Dobby。那么將Framework加??程會(huì)有?個(gè)常?的問題,就是bitcode。
解決?案兩種。1、解決Framework讓他?持bitcode。2、本?程關(guān)閉bitcode。
拷?問題
Framework庫?次拖??程,Xcode不會(huì)?動(dòng)幫你拷?,運(yùn)?時(shí)你會(huì)發(fā)現(xiàn)庫沒有打包進(jìn)?App包。造成DYLD加載時(shí)找不到庫的錯(cuò)誤。

此刻需要?動(dòng)添加拷?

再次運(yùn)?我們可以看到控制臺(tái)的輸出,說明引?成功了!
[*] [DobbySymbolResolver] resolve image: /usr/lib/system/libdyld.dylib
[*] Initialize DobbyInstrument => 0x102cc9548 => 0x102db0b60
[*] ================ DynamicBinaryInstrumentRouting Start ================
[*] Initialize assembler code buffer at 0x283c3cc20
[*] Initialize assembler code buffer at 0x283c3cc60
1.3 使?Dobby
引?成功之后,我們就可以開始玩?下了。?先我們來看看最關(guān)鍵的函數(shù)。
// replace function
/**
arg1:需要HOOK的函數(shù)地址
arg2:新函數(shù)地址
arg3:保留原始函數(shù)的指針的地址
*/
int DobbyHook(void *function_address, void *replace_call, void **origin_call);
這個(gè)就是?來HOOK我們?定義函數(shù)的,那么我們來使??下。你會(huì)發(fā)現(xiàn)這個(gè)函數(shù)的使?和fishhook?常像!
接下來,我們可以寫?個(gè)Demo。?如我們有?個(gè)?定義的sum函數(shù),明顯的加法運(yùn)算。
int sum(int a,int b) {
return a + b;
}
接下來,我們?cè)赩iewController的ViewDidLoad中輸出
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(@"打印出:%d",sum(10, 20));
}
這個(gè)函數(shù)正常的執(zhí)?結(jié)果應(yīng)該是30。那么我們要在Load?法中去HOOK這個(gè)sum。
HOOK前的準(zhǔn)備
?先我們要定義?個(gè)東?。
- 函數(shù)指針,?于保存被替換函數(shù)的地址
//函數(shù)指針?于保留原來的執(zhí)?流程
static int(*sum_p)(int a, int b);
- 新函數(shù)(?這個(gè)函數(shù)替換你需要HOOK的函數(shù),那么該函數(shù)的返回值以及參數(shù)要保持?致)
//新函數(shù)
int mySum(int a, int b){
NSLog(@"原有的結(jié)果是:%d",sum_p(a,b));
return a - b;
}
開始HOOK
使?DobbyHook來HOOK我們的函數(shù)。接下來,在Load?法中:
+ (void)load {
//Hook sum
DobbyHook(sum, mySum, (void *)&sum_p);
}
參數(shù)解析
- arg1(sum):需要HOOK的函數(shù)的地址,函數(shù)名稱就是函數(shù)指針
- arg2(mySum):新函數(shù)的地址
- arg3(sum_p):將原來的sum函數(shù)的地址存放到sum_p這個(gè)函數(shù)指針中(因?yàn)橐o指針賦值,所以取指針的地址,so:?級(jí)指針)
運(yùn)?結(jié)果:
原有的結(jié)果是:30
打印出:-10
順利HOOK 自定義C函數(shù)!
二、利用純地址進(jìn)行HOOK
結(jié)合上面次的Demo我們進(jìn)??點(diǎn)改進(jìn)。在真實(shí)的逆向過程中,我們是沒有函數(shù)符號(hào)的,因?yàn)榉?hào)表脫掉了。
接下來,我們通過純地址的?式來HOOK函數(shù)。
2.1 通過LLDB調(diào)試獲取Sum函數(shù)的?件偏移地址。
?先在sum函數(shù)上下?個(gè)斷點(diǎn)
然后通過匯編顯示確定函數(shù)地址,在Xcode頂部工具欄Debug設(shè)置中設(shè)置?下
Debug --> Debug Workflow --> Always Show Disassembly(?直顯示匯編)接下來通過LLDB指令找出主程序的?地址。得到 sum函數(shù)偏移地址 = sum函數(shù)地址 - 主程序?地址

我們可以?Mac?帶的計(jì)算器算出偏移值,很?便(CMD+3 使?編程器)

2.2 在MachOView中查看到當(dāng)前函數(shù)
我們打開MachOView,可以看到這?就是我們sum函數(shù)的開始位置。所以我們可以驗(yàn)證了sum函數(shù)的?件偏移地址就是0x5DA8。那么我們就?這個(gè)地址進(jìn)?接下來的HOOK了。

2.3 HOOK前的準(zhǔn)備
準(zhǔn)備?個(gè)指針
注意:由于要?便我們計(jì)算,這?定義函數(shù)指針不要定義成為函數(shù)的結(jié)構(gòu)。?是uintptr_t類型
//定義指針,表示sum函數(shù)的偏移地址!
static uintptr_t sumP = 0x100005DA8;
動(dòng)態(tài)獲取ASLR
?先導(dǎo)?頭#import <mach-o/dyld.h>
然后使?函數(shù)_dyld_get_image_vmaddr_slide獲取ASLR,我們?cè)贚oad中就可以這樣寫。
+ (void)load {
//獲取ASLR,讓sumP變成準(zhǔn)確的地址
//參數(shù)0代表imagelist中的主程序(??)
uintptr_t aslr = _dyld_get_image_vmaddr_slide(0);
sumP += aslr;
//Hook sum
DobbyHook((void *)sumP, mySum, (void *)&sum_p);
}
但是這個(gè)時(shí)候,我們運(yùn)?會(huì)發(fā)現(xiàn)HOOK失敗,調(diào)用的任然是原來的sum函數(shù)?
2.4 為什么會(huì)出錯(cuò)?
原因很簡(jiǎn)單。我們剛才算出來的sum函數(shù)的?件偏移地址,在我們修改了這?的代碼之后變了!所以只能再次去獲取sum函數(shù)的偏移。(注意:HOOK別?應(yīng)?時(shí)因?yàn)槲覀兪莿?dòng)態(tài)庫注?,所以不會(huì)修改?標(biāo)應(yīng)?的MachO,那么偏移值是固定的。沒有這么麻煩)
注意:
這?有?個(gè)?技巧!因?yàn)樾薷拇a之后,我們的sum函數(shù)有可能會(huì)沒法斷點(diǎn)調(diào)試(因?yàn)槌绦蚪粨Q就崩潰),那么沒關(guān)系,我們不做交換
1、將交換的代碼注釋起來
2、獲取到最?改動(dòng)的sum函數(shù)偏移地址。
3、再講該執(zhí)?的代碼打開。?成最新的MachO。
4、在MachOView中找到那附近(往?地址?)最像函數(shù)起始位置的作為sum函數(shù)的偏移(?般都是)
這個(gè)時(shí)候,我們只需要將sum函數(shù)的偏移地址修改?下就可以了!
//定義指針,表示sum函數(shù)的偏移地址!
static uintptr_t sumP = 0x100005D6C;
運(yùn)?!通過純地址也能輕松搞定InlineHook了!這樣離我們HOOK三?應(yīng)?就更加接近了。
三、將Dobby注入目標(biāo)程序
3.1 實(shí)現(xiàn)一個(gè)目標(biāo)應(yīng)用
簡(jiǎn)單的sum函數(shù)調(diào)用
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
NSLog(@"10+15的結(jié)果是%d",sum(10,15));
}
int sum(int a, int b) {
return a + b;
}
編譯完成之后,我們現(xiàn)在獲取sum函數(shù)的準(zhǔn)確地址,記錄一下。

0x10229dfa4-0x0000000102298000 = 0x5FA4
接下來將該應(yīng)用的符號(hào)脫掉。在Build Settings里面

重新編譯運(yùn)行后會(huì)發(fā)現(xiàn)符號(hào)斷點(diǎn)來不了,這是一個(gè)明顯的脫符號(hào)成功的標(biāo)志。
那么這個(gè)時(shí)候我們可以通過內(nèi)存斷點(diǎn)來看看。運(yùn)行APP,點(diǎn)擊調(diào)試區(qū)域?,進(jìn)入調(diào)試

使用sum內(nèi)存偏移地址0x5FA4加上ASLR得到當(dāng)前sum的內(nèi)存地址,并在控制臺(tái)添加內(nèi)存斷點(diǎn)

點(diǎn)擊屏幕就會(huì)進(jìn)入sum的函數(shù)內(nèi)存斷點(diǎn)

3.2 注入目標(biāo)應(yīng)用
接下來按照重簽、注入的步驟進(jìn)行代碼注入。這里需要注意appSign.sh中APP的路徑
TEMP_APP_PATH=$(set -- "${ASSETS_PATH}/"*.app;echo "$1")


重簽成功后就可以調(diào)試了,接下來就是注入動(dòng)態(tài)庫了。創(chuàng)建HankHook動(dòng)態(tài)庫

添加DobbyX.framework
將DobbyX.framework拖入到項(xiàng)目并配置Other Linker Flags和Framework Search Paths、Library Search Paths




將appSign.sh中注入腳本的注釋打開,并重新運(yùn)行程序
#注入
./yololib "$TARGET_APP_PATH/$APP_BINARY" "Frameworks/HankHook.framework/HankHook"

Dobby 是在運(yùn)行時(shí)進(jìn)行HOOK的。當(dāng)APP運(yùn)行在內(nèi)存中后對(duì)目標(biāo)函數(shù)的匯編代碼進(jìn)行修改,修改的是內(nèi)存中的MachO的
代碼段。