所謂InlineHook
(內(nèi)聯(lián)鉤?),就是直接修改?標(biāo)函數(shù)的頭部代碼铝耻。讓它跳轉(zhuǎn)到?定義函數(shù)中執(zhí)?代碼誊爹,從?達(dá)到Hook
的?的。這種Hook
技術(shù)?般用于靜態(tài)語?
Dobby框架
Dobby
是一個(gè)全平臺(tái)的InlineHook
框架瓢捉,詳情可查看 官方文檔
編譯
Dobby
將代碼
clone
下來git clone https://github.com/jmpews/Dobby.git --depth=1
由于
Dobby
是跨平臺(tái)框架频丘,所以項(xiàng)?并不是?個(gè)Xcode
?程,需要使?cmake
將?程編譯成為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
編譯完成后,會(huì)?成?個(gè)
Xcode
?程
編譯
Xcode
?程兽赁,?成Framework
導(dǎo)?
DobbyX.framework
到?程状答,如果遇到Bitcode
問題,兩種解決方式
- 關(guān)閉當(dāng)前?程的
Bitcode
- 編譯
DobbyX.framework
時(shí)刀崖,開啟Bitcode
DobbyX.framework
拷?問題將
Framework
庫?次拖??程惊科,Xcode
不會(huì)?動(dòng)幫你拷?。運(yùn)?時(shí)會(huì)發(fā)現(xiàn)Framework
沒有打包進(jìn)?App
包亮钦,造成DYLD
加載時(shí)找不到庫的錯(cuò)誤來到
Xcode
中的Build Phases
馆截,點(diǎn)擊+
,選擇New Copy Files Phase
在
Copy Files
中,將Destination
選擇Frameworks
點(diǎn)擊
+
蜡娶,選擇DobbyX.framework
混卵,點(diǎn)擊Add
Dobby
的核心的函數(shù)int DobbyHook(void *address, void *replace_call, void **origin_call);
address
:需要HOOK
的函數(shù)地址replace_call
:新函數(shù)地址origin_call
:保留原始函數(shù)的指針的地址
案例1
Dobby
的使用搭建
InlineDemo
項(xiàng)目,拖入DobbyX.framework
窖张,解決拷?問題打開
ViewController.m
文件幕随,寫入以下代碼:定義將要被
HOOK
的靜態(tài)函數(shù)int sum(int a,int b){ return a + b; }
定義函數(shù)指針,?于保存被替換函數(shù)的地址
static int (*sum_p)(int a,int b);
定義新函數(shù)宿接,?此函數(shù)替換將要
HOOK
的函數(shù)赘淮,該函數(shù)的返回值及參數(shù)必須?致int mySum(int a,int b) { NSLog(@"Sum:%d,??????????",sum_p(a,b)); return a - b; }
在
viewDidLoad
方法中睦霎,調(diào)用DobbyHook
進(jìn)行函數(shù)的Hook
- (void)viewDidLoad { [super viewDidLoad]; DobbyHook((void *)sum, mySum, (void *)&sum_p); }
在
touchesBegan
中梢卸,調(diào)用sum
函數(shù)-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { NSLog(@"Sum:%d",sum(10, 20)); }
真機(jī)運(yùn)行項(xiàng)目,點(diǎn)擊屏幕副女,輸入以下內(nèi)容:
InlineDemo[9140:1691629] Sum:30蛤高,?????????? InlineDemo[9140:1691629] Sum:-10
sum
函數(shù)HOOK
成功,先輸出原始函數(shù)的執(zhí)行結(jié)果碑幅,再輸出替換函數(shù)的執(zhí)行結(jié)果
HOOK原理
案例1:
通過匯編代碼襟齿,查看
HOOK
原理上述案例中,在
touchesBegan
方法上設(shè)置斷點(diǎn)
真機(jī)運(yùn)行項(xiàng)目枕赵,點(diǎn)擊屏幕,進(jìn)入
touchesBegan
方法
單步調(diào)試位隶,向下執(zhí)行
1
步拷窜。進(jìn)入sum
函數(shù)
- 前三句代碼被替換
- 拉伸棧空間的代碼沒有了
單步調(diào)試涧黄,向下執(zhí)行
3
步篮昧。通過br x17
指令,跳轉(zhuǎn)到mySum
函數(shù)
進(jìn)入
mySum
函數(shù)笋妥,通過blr x8
指令懊昨,跳轉(zhuǎn)到指定地址上執(zhí)行代碼
該代碼中,通過
br x17
指令春宣,回到sum
函數(shù)
- 這里出現(xiàn)了拉伸椊桶洌空間的代碼
進(jìn)入
sum
函數(shù),執(zhí)行原始代碼邏輯
- 在
sum
函數(shù)的結(jié)尾月帝,恢復(fù)棧平衡當(dāng)
sum
函數(shù)執(zhí)行ret
指令躏惋,返回mySum
函數(shù),執(zhí)行后續(xù)代碼
靜態(tài)函數(shù)的
HOOK
嚷辅,并沒有在原始函數(shù)中增加代碼簿姨,而是將拉伸棧空間的三句代碼進(jìn)行了替換當(dāng)調(diào)用原始函數(shù),才會(huì)拉伸棧平衡扁位。然后在原始函數(shù)的代碼中准潭,恢復(fù)棧平衡
案例2:
mySum
函數(shù)中,不調(diào)用原始函數(shù)在
mySum
函數(shù)中域仇,注釋原始函數(shù)的調(diào)用
真機(jī)運(yùn)行項(xiàng)目刑然,進(jìn)入
sum
函數(shù)。代碼并沒有發(fā)生變化
進(jìn)入
mySum
函數(shù)殉簸,跳轉(zhuǎn)到指定地址的代碼沒有了
當(dāng)
mySum
函數(shù)執(zhí)行ret
指令闰集,直接返回到touchesBegan
此時(shí)
sum
函數(shù)的原始代碼都不會(huì)被執(zhí)行
這種情況,不會(huì)拉伸棸惚埃空間武鲁,
sum
函數(shù)的原始代碼不會(huì)被執(zhí)行,所以也不會(huì)恢復(fù)棧平衡
HOOK函數(shù)地址
在逆向開發(fā)中蝠检,三方應(yīng)用會(huì)剝離符號(hào)表沐鼠,我們無法獲得符號(hào)名稱,所以
HOOK
的一定是地址應(yīng)用每次啟動(dòng)時(shí)叹谁,
ASLR
偏移地址都不一樣饲梭,所以不能直接HOOK
地址正確的做法:先找到函數(shù)在
MachO
中的偏移地址,加上PAGEZERO
的0x100000000
焰檩,再加上本次啟動(dòng)的ASLR
偏移地址
案例1
延用上述案例憔涉,找到
sum
函數(shù)的實(shí)現(xiàn)地址查看匯編代碼,找到
sum
函數(shù)的調(diào)用
- 函數(shù)實(shí)現(xiàn)地址:
0x1022edd48
使用
image list
函數(shù)析苫,找到主程序的基地址
- 基地址:
0x1022e8000
使用
函數(shù)實(shí)現(xiàn)地址 - 主程序基地址
兜叨,計(jì)算函數(shù)在MachO
中的偏移地址e -f x -- 0x1022edd48-0x1022e8000 ------------------------- $1 = 0x5d48
- 偏移地址:
0x5d48
在
MachO
文件中,查看偏移地址
- 對(duì)應(yīng)的正是
sum
函數(shù)的匯編代碼- 和斷點(diǎn)時(shí)看到的匯編代碼有些區(qū)別衩侥,因?yàn)?code>Dobby在運(yùn)行時(shí)国旷,
Hook
函數(shù)會(huì)替換匯編代碼
案例2:
對(duì)函數(shù)地址進(jìn)行
HOOK
打開
ViewController.m
文件,寫入以下代碼:#import "ViewController.h" #import <DobbyX/dobby.h> #import <mach-o/dyld.h> @implementation ViewController int sum(int a,int b){ return a + b; } static uintptr_t sumP = 0x5d48 + 0x100000000; - (void)viewDidLoad { [super viewDidLoad]; sumP += _dyld_get_image_vmaddr_slide(0); DobbyHook((void *)sumP, mySum, (void *)&sum_p); } static int (*sum_p)(int a,int b); int mySum(int a,int b) { NSLog(@"Sum:%d茫死,??????????",sum_p(a,b)); return a - b; } -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { NSLog(@"Sum:%d",sum(10, 20)); } @end
這里有一個(gè)小問題跪但,因?yàn)榘咐窃谧约旱捻?xiàng)目中
HOOK
地址,所以對(duì)項(xiàng)目的代碼進(jìn)行了修改峦萎,這樣會(huì)造成sum
函數(shù)的實(shí)現(xiàn)地址發(fā)生改變
sum
函數(shù)的偏移地址屡久,從之前的0x5d48
變?yōu)?code>0x5d08打開
ViewController.m
文件,修改代碼:static uintptr_t sumP = 0x5d08 + 0x100000000;
真機(jī)運(yùn)行項(xiàng)目爱榔,點(diǎn)擊屏幕涂身,
HOOK
成功InlineDemo[9883:1880364] Sum:30,?????????? InlineDemo[9883:1880364] Sum:-10
在代碼不修改的情況下搓蚪,地址不會(huì)改變蛤售。所以在逆向開發(fā)中,分析第三方應(yīng)用,不會(huì)出現(xiàn)這種問題
Dobby注入應(yīng)用
案例1:
搭建被
HOOK
的應(yīng)用創(chuàng)建
FuncDemo
項(xiàng)目打開
ViewController.m
文件悴能,寫入以下代碼:#import "ViewController.h" @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; } -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { NSLog(@"Sum:%d",sum(10,15)); } int sum(int a,int b){ return a + b; } @end
真機(jī)運(yùn)行項(xiàng)目揣钦,使用
函數(shù)實(shí)現(xiàn)地址 - 主程序基地址
,計(jì)算出sum
函數(shù)在MachO
中的偏移地址:0x5F04
為了
HOOK
的場景更加真實(shí)漠酿,剝離除了間接符號(hào)之外的全部符號(hào)
剝離符號(hào)后冯凹,驗(yàn)證
sum
函數(shù)的實(shí)現(xiàn)地址是否改變真機(jī)運(yùn)行項(xiàng)目,使用
image list
獲得主程序基地址通過暫停炒嘲,進(jìn)入
lldb
宇姚。通過主程序基地址 + 0x5F04
,得到sum
函數(shù)地址
對(duì)地址設(shè)置斷點(diǎn)夫凸,成功找到函數(shù)浑劳,說明
sum
函數(shù)的實(shí)現(xiàn)地址沒有改變
案例2:
修改重簽名腳本,改為支持
.app
格式定義變量
# 工程文件所在的目錄 TEMP_PATH="${SRCROOT}/Temp" # 資源文件夾夭拌,我們提前在工程目錄下新建一個(gè)APP文件夾魔熏,里面放ipa包 ASSETS_PATH="${SRCROOT}/APP" # 拿到臨時(shí)的APP的路徑 TEMP_APP_PATH=$(set -- "${ASSETS_PATH}/"*.app;echo "$1")
將
.app
拷貝進(jìn)入工程TARGET_APP_PATH="$BUILT_PRODUCTS_DIR/$TARGET_NAME.app" rm -rf $TARGET_APP_PATH mkdir -p $TARGET_APP_PATH cp -rf $TEMP_APP_PATH/ $TARGET_APP_PATH
刪除
Extention
和Watch
rm -rf "$TARGET_APP_PATH/PlugIns" rm -rf "$TARGET_APP_PATH/Watch"
更新
info.plist
文件中的CFBundleIdentifier
/usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier $PRODUCT_BUNDLE_IDENTIFIER" "$TARGET_APP_PATH/Info.plist"
拿到
MachO
文件的路徑,給MachO
文件上執(zhí)行權(quán)限APP_BINARY=`plutil -convert xml1 -o - $TARGET_APP_PATH/Info.plist|grep -A1 Exec|tail -n1|cut -f2 -d\>|cut -f1 -d\<` chmod +x "$TARGET_APP_PATH/$APP_BINARY"
重簽名第三方
Frameworks
TARGET_APP_FRAMEWORKS_PATH="$TARGET_APP_PATH/Frameworks" if [ -d "$TARGET_APP_FRAMEWORKS_PATH" ]; then for FRAMEWORK in "$TARGET_APP_FRAMEWORKS_PATH/"* do
簽名
/usr/bin/codesign --force --sign "$EXPANDED_CODE_SIGN_IDENTITY" "$FRAMEWORK" done fi
注入
./yololib "$TARGET_APP_PATH/$APP_BINARY" "Frameworks/Hook.framework/Hook"
案例3:
對(duì)
FuncDemo.app
進(jìn)行HOOK
搭建
HookDemo
項(xiàng)目將
yololib
鸽扁、appSign.sh
蒜绽、DobbyX.framework
,拷貝到項(xiàng)目根目錄在項(xiàng)目根目錄桶现,創(chuàng)建
App
目錄將
FuncDemo.app
拷貝至App
目錄創(chuàng)建
target
躲雅,添加注入的動(dòng)態(tài)庫,命名HOOK
在
HOOK
動(dòng)態(tài)庫中骡和,創(chuàng)建Inject
類在
HookDemo
主項(xiàng)目中相赁,拖入DobbyX.framework
,勾選HookDemo
和HOOK
在
HookDemo
中即横,找到Embed Framewords
,添加DobbyX.framework
打開
Inject.m
文件裆赵,寫入以下代碼:#import "Inject.h" #import <DobbyX/dobby.h> #import <mach-o/dyld.h> @implementation Inject static uintptr_t sumP = 0x5F04 + 0x100000000; +(void)load{ sumP += _dyld_get_image_vmaddr_slide(0); DobbyHook((void *)sumP, mySum, (void *)&sum_p); } static int (*sum_p)(int a,int b); int mySum(int a,int b) { NSLog(@"Sum:%d东囚,??????????",sum_p(a,b)); return a - b; } @end
真機(jī)運(yùn)行項(xiàng)目,點(diǎn)擊屏幕战授,
HOOK
成功FuncDemo[11452:2162229] Sum:25页藻,?????????? FuncDemo[11452:2162229] Sum:-5
總結(jié)
Dobby
Dobby
原理:運(yùn)行時(shí)對(duì)目標(biāo)函數(shù)的匯編代碼替換,修改的是內(nèi)存中MachO
的代碼段Dobby
替換匯編代碼時(shí)植兰,對(duì)原始函數(shù)的調(diào)用份帐,會(huì)影響棧的拉伸和平衡- 在真實(shí)
HOOK
場景中,我們拿不到符號(hào)名稱楣导,只能對(duì)地址進(jìn)行HOOK
HOOK
地址時(shí)废境,需要加上PAGEZERO
和ASLR