初探反HOOK防護(hù)
當(dāng)
HOOK第三方App時(shí),對(duì)于OC方法,一般會(huì)使用Method Swizzle。例如:使用系統(tǒng)提供的method_exchangeImplementations函數(shù),將兩個(gè)方法進(jìn)行交換自己開(kāi)發(fā)的
App,如果使用fishHook,預(yù)先將method_exchangeImplementations和自定義函數(shù)交換,攻擊方在不知道函數(shù)名稱的情況下,將很難進(jìn)行HOOK
案例1:
使用
fishHook交換method_exchangeImplementations搭建
App項(xiàng)目,命名為AntiHook,作為反HOOK案例防護(hù)代碼寫在
Framework中更適宜,因?yàn)?code>load方法調(diào)用時(shí)機(jī)比主程序更快,并且可以在別人注入的動(dòng)態(tài)庫(kù)之前被執(zhí)行添加
target,創(chuàng)建Framework,命名為HookMgr,設(shè)置為動(dòng)態(tài)庫(kù)在
Framework中,創(chuàng)建AntiHookCode文件,并導(dǎo)入fishhook
打開(kāi)
AntiHookCode.m文件,寫入以下代碼:#import "AntiHookCode.h" #import "fishhook.h" #import <objc/message.h> @implementation AntiHookCode +(void)load{ struct rebinding reb; reb.name="method_exchangeImplementations"; reb.replacement=my_exchange; reb.replaced=(void *)&sys_exchange; struct rebinding rebs[] = { reb }; rebind_symbols(rebs, 1); } void (*sys_exchange)(Method _Nonnull m1, Method _Nonnull m2); void my_exchange(Method _Nonnull m1, Method _Nonnull m2){ NSLog(@"檢測(cè)到HOOK"); } @end在
App中,打開(kāi)ViewController.m文件,寫入以下代碼:#import "ViewController.h" #import <HookMgr/HookMgr.h> @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; } - (IBAction)btnClick1:(id)sender { NSLog(@"按鈕1調(diào)用!"); } - (IBAction)btnClick2:(id)sender { NSLog(@"按鈕2調(diào)用了!"); } @end創(chuàng)建
Payload目錄編譯項(xiàng)目,將編譯后的
AntiHook.app拷貝到Payload目錄下
使用
zip命令,將Payload打包為AntiHook.ipazip -ry AntiHook.ipa Payload
案例2:
測(cè)試
AntiHook項(xiàng)目的反HOOK防護(hù)是否有效搭建
App項(xiàng)目,命名為HookDemo,作為重簽名App添加
target,創(chuàng)建Framework,命名為Hook,設(shè)置為動(dòng)態(tài)庫(kù)在
Framework中,創(chuàng)建Inject文件
打開(kāi)
Inject.h文件,寫入以下代碼:#import "Inject.h" #import <objc/runtime.h> @implementation Inject +(void)load{ Method sysClick1 = class_getInstanceMethod(objc_getClass("ViewController"), @selector(btnClick1:)); Method myClick1 = class_getInstanceMethod(self, @selector(my_btnClick1)); method_exchangeImplementations(sysClick1, myClick1); } -(void)my_btnClick1{ NSLog(@"??????????"); } @end將
appSign.sh文件、yololib文件,拷貝到項(xiàng)目根目錄。然后在項(xiàng)目根目錄,創(chuàng)建App目錄
將
案例1中,最后打包的AntiHook.ipa文件,拷貝到App目錄
在
HookDemo中,選擇Build Phases,在Run Script中輸入:./appSign.sh
真機(jī)運(yùn)行項(xiàng)目,檢測(cè)到
HOOK代碼
點(diǎn)擊
按鈕1,輸出的還是原始內(nèi)容
AntiHook項(xiàng)目中的防護(hù)代碼生效,當(dāng)注入的動(dòng)態(tài)庫(kù),使用method_exchangeImplementations函數(shù)時(shí),可以被檢測(cè)出來(lái),并讓攻擊方的HOOK失效
案例3:
在本工程中使用方法交換
來(lái)到
AntiHook項(xiàng)目在
HookMgr中,打開(kāi)AntiHookCode.h文件,寫入以下代碼:#import <Foundation/Foundation.h> #import <objc/message.h> CF_EXPORT void (*sys_exchange)(Method _Nonnull m1, Method _Nonnull m2); @interface AntiHookCode : NSObject @end打開(kāi)
HookMgr.h文件,寫入以下代碼:#import <Foundation/Foundation.h> #import <HookMgr/AntiHookCode.h>在
AntiHook中,打開(kāi)ViewController.m文件,寫入以下代碼:#import "ViewController.h" #import <HookMgr/HookMgr.h> @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; Method sysClick2 = class_getInstanceMethod(self.class, @selector(btnClick2:)); Method myClick2 = class_getInstanceMethod(self.class, @selector(test)); sys_exchange(sysClick2, myClick2); } -(void)test{ NSLog(@"本工程HOOK,??????????"); } - (IBAction)btnClick1:(id)sender { NSLog(@"按鈕1調(diào)用!"); } - (IBAction)btnClick2:(id)sender { NSLog(@"按鈕2調(diào)用了!"); } @end真機(jī)運(yùn)行項(xiàng)目,點(diǎn)擊
按鈕2
在本工程中,使用
sys_exchange函數(shù)HOOK成功。但對(duì)于攻擊方,在不知道函數(shù)名稱的情況下,則很難進(jìn)行HOOK
上述防護(hù)方式,過(guò)于簡(jiǎn)單。它會(huì)在
MachO的字符串表中,存儲(chǔ)method_exchangeImplementations的字符串使用
Hopper,打開(kāi)HookMgr動(dòng)態(tài)庫(kù)的MachO文件
攻擊方通過(guò)字符串,很容易定位到防護(hù)代碼,然后對(duì)其破解。例如,在更早的執(zhí)行時(shí)機(jī),對(duì)防護(hù)的關(guān)鍵函數(shù)
HOOK,讓防護(hù)代碼失效所以上述方式,不建議使用。高明的防護(hù)代碼,應(yīng)該讓攻擊方很難發(fā)現(xiàn),盡量不留下痕跡。在程序運(yùn)行過(guò)程中,不知不覺(jué)的將其干掉
MokeyDev
MokeyDev:作者劉培慶,原iOSOpenDev的升級(jí)版,一款非越獄插件開(kāi)發(fā)集成神器主要包括四個(gè)模塊:
Logos Tweak:使用theos提供的logify.pl工具,將*.xm文件轉(zhuǎn)成*.mm文件參與執(zhí)行。集成了CydiaSubstrate,可以使用MSHookMessageEx和MSHookFunction來(lái)Hook指定地址和OC函數(shù)CaptainHook Tweak:使用CaptainHook提供的頭文件,進(jìn)行OC函數(shù)的Hook以及屬性的獲取Command-line Tool:可以直接創(chuàng)建運(yùn)行于越獄設(shè)備的命令行工具MonkeyApp:這是自動(dòng)給第三方應(yīng)用集成Reveal、Cycript和注入dylib的模塊。支持調(diào)試dylib和第三方應(yīng)用,支持Pod給第三放應(yīng)用集成SDK,只需要準(zhǔn)備一個(gè)砸殼后的ipa或app文件即可
安裝
MokeyDev,需要先安裝theos。詳情可參見(jiàn):官方文檔 & 安裝說(shuō)明安裝中,遇到
xcode 12 Types.xcspec not found錯(cuò)誤,可執(zhí)行以下命令:sudo ln -s /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/Library/Xcode/PrivatePlugIns/IDEOSXSupportCore.ideplugin/Contents/Resources /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/Library/Xcode/Specifications
- 詳情可查看:原文地址
案例1
搭建
MokeyApp項(xiàng)目安裝
MokeyDev成功后,打開(kāi)Xcode,創(chuàng)建新項(xiàng)目選擇
MokeyApp
創(chuàng)建成功,默認(rèn)包含
App和注入的動(dòng)態(tài)庫(kù)
案例2
使用
MokeyApp實(shí)現(xiàn)應(yīng)用重簽名
MokeyApp支持.ipa和.app格式將
ipa包,拷貝到MokeyDemo下的TargetApp目錄中
運(yùn)行
MokeyDemo項(xiàng)目,即可安裝成功
案例3
使用
MokeyApp實(shí)現(xiàn)代碼注入在
MokeyDemoDylib中,點(diǎn)擊MokeyDemoDylib.xm文件,選擇Objective-C++ Source
打開(kāi)
MokeyDemoDylib.xm文件,寫入以下代碼:#import <UIKit/UIKit.h> %hook ViewController - (void)btnClick1:(id)sender { NSLog(@"??????????"); } %end
- 使用
Logos語(yǔ)法,詳情可查看:官方文檔真機(jī)運(yùn)行項(xiàng)目,檢測(cè)到
HOOK代碼
點(diǎn)擊
按鈕1,輸出的是交換后的內(nèi)容
HOOK成功后,調(diào)用原始函數(shù)- (void)btnClick1:(id)sender { NSLog(@"??????????"); %orig; }只需要
%orig一句代碼,即可調(diào)用
使用
MokeyApp,在AntiHook項(xiàng)目中,可以檢測(cè)到method_exchangeImplementations函數(shù)的使用,說(shuō)明防護(hù)代碼有效。至于方法還是被交換了,可能MokeyDev使用的是get/set方法
案例4
在
AntiHook項(xiàng)目中,增加對(duì)method_setImplementation的防護(hù)來(lái)到
AntiHookCode項(xiàng)目在
Framework中,打開(kāi)AntiHookCode.m文件,修改為以下代碼#import "AntiHookCode.h" #import "fishhook.h" @implementation AntiHookCode +(void)load{ struct rebinding rebExchange; rebExchange.name="method_exchangeImplementations"; rebExchange.replacement=my_check; rebExchange.replaced=(void *)&sys_exchange; struct rebinding rebSetImp; rebSetImp.name="method_setImplementation"; rebSetImp.replacement=my_check; rebSetImp.replaced=(void *)&sys_setImp; struct rebinding rebs[] = { rebExchange, rebSetImp }; rebind_symbols(rebs, 2); } void (*sys_exchange)(Method _Nonnull m1, Method _Nonnull m2); IMP _Nonnull (*sys_setImp)(Method _Nonnull m, IMP _Nonnull imp); void my_check(Method _Nonnull m1, Method _Nonnull m2){ NSLog(@"檢測(cè)到HOOK"); } @end編譯項(xiàng)目,將
ipa包,覆蓋到MokeyDemo下的TargetApp目錄中真機(jī)運(yùn)行項(xiàng)目,檢測(cè)到
HOOK代碼
點(diǎn)擊
按鈕1,輸出的還是原始內(nèi)容
當(dāng)
method_setImplementation函數(shù)被交換,MokeyDev的HOOK代碼同樣失效
在
MokeyDev中,使用的是Substrate框架
在
MokeyDemoDylib.xm中寫入的Logos語(yǔ)法,也是被libsubstrate.dylib庫(kù)進(jìn)行解析
將
.xm中的代碼,解析到MokeyDemoDylib.mm文件
在
MSHookMessageEx函數(shù)內(nèi)部,也是通過(guò)get/set方法,對(duì)OC方法進(jìn)行HOOK
總結(jié):
反
HOOK防護(hù)
- 利用
fishHook,修改Method Swizzle相關(guān)函數(shù)- 不推薦使用,防護(hù)痕跡過(guò)于明顯。會(huì)導(dǎo)致其他三方庫(kù)無(wú)法使用
Method Swizzle- 防護(hù)代碼需要最先被執(zhí)行,否則先被
HOOK,防護(hù)代碼失效- 原始工程編寫的
Framework庫(kù),優(yōu)先于注入庫(kù)的加載,適合寫防護(hù)代碼
MokeyDev
- 原
iOSOpenDev的升級(jí)版,一款非越獄插件開(kāi)發(fā)集成神器- 使用
Substrate框架- 底層通過(guò)
get/set方法,對(duì)OC方法進(jìn)行HOOK























