一情妖、 反 hook 初探
我們Hook
別人的代碼一般使用OC
的MethodSwizzle
抖部,如果我們用
fishhook
將MethodSwizzle hook
了逞力,別人是不是就hook
不了我們的代碼了弯淘?
1.1 創(chuàng)建主工程 AntiHookDemo
創(chuàng)建一個工程AntiHookDemo
您觉,頁面中有兩個按鈕btn1
和btn2
:
對應(yīng)兩個事件:
- (IBAction)btn1Click:(id)sender {
NSLog(@"click btn1");
}
- (IBAction)btn2Click:(id)sender {
NSLog(@"click btn2");
}
1.2 創(chuàng)建防護(hù) HookManager (FrameWork
動態(tài)庫)
這個時候要使用fishhook
防護(hù),在FrameWork
中寫防護(hù)代碼拖吼×凵希基于兩點(diǎn):
-
Framework
在主工程+ load
執(zhí)行之前執(zhí)行+ load
。 - 別人注入的
Framework
也在防護(hù)代碼之后吊档。
創(chuàng)建一個HookManager
Framework
篙议,文件結(jié)構(gòu)下:
AntiHookManager.h
:
#import <Foundation/Foundation.h>
#import <objc/message.h>
//暴露給外界使用
CF_EXPORT void (*exchange_p)(Method _Nonnull m1, Method _Nonnull m2);
@interface AntiHookManager : NSObject
@end
AntiHookManager.m
:
#import "AntiHookManager.h"
#import "fishhook.h"
@implementation AntiHookManager
+ (void)load {
//基本防護(hù)
struct rebinding exchange;
exchange.name = "method_exchangeImplementations";
exchange.replacement = hp_exchange;
exchange.replaced = (void *)&exchange_p;
struct rebinding bds[] = {exchange};
rebind_symbols(bds, 1);
}
//指回原方法
void (*exchange_p)(Method _Nonnull m1, Method _Nonnull m2);
void hp_exchange(Method _Nonnull m1, Method _Nonnull m2) {
//可以在這里進(jìn)行上報(bào)后端等操作
NSLog(@"find Hook");
}
@end
HookManager.h
中導(dǎo)出頭文件:
#import <HookManager/AntiHookManager.h>
然后將AntiHookManager.h
放入public Headers
:
修改主工程的ViewController.m
如下:
#import <HookManager/HookManager.h>
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
exchange_p(class_getInstanceMethod(self.class, @selector(btn2Click:)),class_getInstanceMethod(self.class, @selector(test)));
}
- (void)test {
NSLog(@"self Hook Success");
}
- (IBAction)btn1Click:(id)sender {
NSLog(@"click btn1");
}
- (IBAction)btn2Click:(id)sender {
NSLog(@"click btn2");
}
@end
在工程中Hook
自己的方法,這個時候運(yùn)行主工程:
AntiHookDemo[1432:149145] click btn1
AntiHookDemo[1432:149145] self Hook Success
btn2
能夠被自己正常Hook
怠硼。
1.3 創(chuàng)建注入工程 HookDemo
- 在根目錄創(chuàng)建
APP
文件夾以及Payload
文件夾鬼贱,拷貝AntiHookDemo.app
到APP/Payload
目錄,壓縮zip -ry AntiHookDemo.ipa Payload/
生成.ipa文件
香璃。 - 拷貝
appResign.sh
重簽名腳本以及yololib
注入工具到根目錄这难。 - 創(chuàng)建
HPHook
注入Framework
。
HPHook
代碼如下:
#import "HPInject.h"
#import <objc/message.h>
@implementation HPInject
+ (void)load {
method_exchangeImplementations(class_getInstanceMethod(objc_getClass("ViewController"), @selector(btn1Click:)), class_getInstanceMethod(self, @selector(my_click)));
}
- (void)my_click {
NSLog(@"inject Success");
}
@end
編譯運(yùn)行:
AntiHookDemo[1437:149999] find Hook
AntiHookDemo[1437:149999] click btn1
AntiHookDemo[1437:149999] self Hook Success
首先是檢測到了Hook
葡秒,其次自己內(nèi)部btn2 hook
成功了姻乓,btn1 hook
沒有注入成功。到這里暴露給自己用和防止別人Hook
都已經(jīng)成功了眯牧。對于三方庫中正常使用到的Hook
可以在防護(hù)代碼中做邏輯判斷可以加白名單等調(diào)用回原來的方法蹋岩。如果自己的庫在image list
最后一個那么三方庫其實(shí)已經(jīng)Hook
完了。
當(dāng)然只Hook
method_exchangeImplementations
不能完全防護(hù)学少,還需要Hook
class_replaceMethod
以及method_setImplementation
剪个。
這種防護(hù)方式破解很容易,一般不這么處理:
1.在Hopper
中可以找到method_exchangeImplementations
版确,直接在MachO
中修改這個字符串HookManager
中就Hook
不到了(這里會直接crash
扣囊,因?yàn)?code>viewDidLoad中調(diào)用了exchange_p
乎折,對于有保護(hù)邏輯的就可以繞過了,并且method_exchangeImplementations
沒法做混淆)
2.可以很容易定位到防護(hù)代碼如暖,直接在防護(hù)代碼之前Hook
笆檀,或者將fishhook
中的一些系統(tǒng)函數(shù)Hook
也能破解。本質(zhì)上是不執(zhí)行防護(hù)代碼盒至。
二酗洒、MonkeyDev
MonkeyDev
是逆向開發(fā)中一個常用的工具 MonkeyDev。能夠幫助我們進(jìn)行重簽名和代碼注入枷遂。
2.1 安裝 MonkeyDev
theos安裝(Cydia Substrate
就是 theos
中的工具)
sudo git clone --recursive https://github.com/theos/theos.git /opt/theos
配置環(huán)境變量
#逆向相關(guān)配置
#export THEOS=/opt/theos
#寫入環(huán)境變量
#export PATH=$THEOS/bin:$PATH
運(yùn)行nic.pl
查看theos
信息樱衷。
[error] Cowardly refusing to make a project inside $THEOS (/opt/theos/)
出現(xiàn)這個錯誤則是export
配置有問題。
指定Xcode
sudo xcode-select -s /Applications/Xcode.app
安裝命令
sudo /bin/sh -c "$(curl -fsSL https://raw.githubusercontent.com/AloneMonkey/MonkeyDev/master/bin/md-install)"
這里是安裝Xcode
插件酒唉。安裝完成后重啟Xcode
在Xcode
中會出現(xiàn)MonkeyDev
對應(yīng)的功能:
-
MonkeyApp
:自動給第三方應(yīng)用集成Reveal
矩桂、Cycript
和注入dylib
的模塊,支持調(diào)試dylib
和第三方應(yīng)用痪伦,支持Pod
給第三放應(yīng)用集成SDK
侄榴,只需要準(zhǔn)備一個砸殼后的ipa
或者app
文件即可。 -
MonkeyPod
:提供了創(chuàng)建Pod的項(xiàng)目网沾。 -
CaptainHook Tweak
:使用CaptainHook
提供的頭文件進(jìn)行OC
函數(shù)的Hook
以及屬性的獲取癞蚕。 -
Command-line Tool
:可以直接創(chuàng)建運(yùn)行于越獄設(shè)備的命令行工具。 -
Logos Tweak
:使用theos
提供的logify.pl
工具將.xm
文件轉(zhuǎn)成.mm
文件進(jìn)行編譯辉哥,集成了CydiaSubstrate
桦山,可以使用MSHookMessageEx
和MSHookFunction
來Hook OC
函數(shù)和指定地址。
卸載命令
sudo /bin/sh -c "$(curl -fsSL https://raw.githubusercontent.com/AloneMonkey/MonkeyDev/master/bin/md-uninstall)"
更新命令
sudo /bin/sh -c "$(curl -fsSL https://raw.githubusercontent.com/AloneMonkey/MonkeyDev/master/bin/md-update)"
錯誤處理
1.MonkeyDev
安裝出現(xiàn):Types.xcspec not found
添加一個軟連接:
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
https://github.com/AloneMonkey/MonkeyDev/issues/266
2.2 重簽名
創(chuàng)建一個MonkeyDemo
工程:
工程目錄如下:
在工程目錄下有一個TargetApp
目錄醋旦,直接將微信8.0.2版本拖進(jìn)去:
編譯運(yùn)行工程:
這個時候就重簽名成功了恒水。相比用腳本自己跑方便很多,也能避免很多異常饲齐。
2.3 MonkeyDev 代碼注入
工程配置
用MonkeyDemo
注入一下AntiHookDemo
钉凌,將AntiHookDemo
編譯生成的App
加入MonkeyDemo
的TargetApp
中:
代碼注入
在MonkeyDemo
工程MonkeyDemoDylib->Logos
目錄,.xm
文件可以寫OC
捂人、C++
御雕、C
:
將MonkeyDemoDylib.xm
的type
改為Objective-C++ Preprocessed Source
:
這里面的默認(rèn)代碼就是Logos
語法:
將
.xm
默認(rèn)打開方式修改為Xcode
后重啟Xcode
就能識別代碼了,否則就還是默認(rèn)文本文件先慷。將默認(rèn)的代碼刪除,寫Hook
btn1Click
的代碼:
#import <UIKit/UIKit.h>
//要hook的類
%hook ViewController
//要hook的方法
- (void)btn1Click:(id)sender {
NSLog(@"Monkey Hook Success");
//調(diào)用原來的方法
%orig;
}
%end
直接運(yùn)行工程后點(diǎn)擊btn1
:
AntiHookDemo[9306:5972601] find Hook
AntiHookDemo[9306:5972601] find Hook
AntiHookDemo[9309:5973617] Monkey Hook Success
AntiHookDemo[9350:5987306] click btn1
這個時候就
Hook
成功了咨察,并且檢測到了Hook
论熙。這里沒有防護(hù)住是因?yàn)?code>Monkey中用的是getImp
和setImp
。對
AntiHookManager
做下改進(jìn):AntiHookManager .h
:
#import <Foundation/Foundation.h>
#import <objc/message.h>
//暴露給外界使用
CF_EXPORT void (*exchange_p)(Method _Nonnull m1, Method _Nonnull m2);
CF_EXPORT IMP _Nonnull (*getImp_p)(Method _Nonnull m);
CF_EXPORT IMP _Nonnull(*setImp_p)(Method _Nonnull m, IMP _Nonnull imp);
@interface AntiHookManager : NSObject
@end
AntiHookManager .m
:
#import "AntiHookManager.h"
#import "fishhook.h"
@implementation AntiHookManager
+ (void)load {
//基本防護(hù)
struct rebinding exchange;
exchange.name = "method_exchangeImplementations";
exchange.replacement = hp_exchange;
exchange.replaced = (void *)&exchange_p;
struct rebinding setIMP;
setIMP.name = "method_setImplementation";
setIMP.replacement = hp_setImp;
setIMP.replaced = (void *)&setImp_p;
struct rebinding getIMP;
getIMP.name = "method_getImplementation";
getIMP.replacement = hp_getImp;
getIMP.replaced = (void *)&getImp_p;
struct rebinding bds[] = {exchange,setIMP,getIMP};
rebind_symbols(bds, 3);
}
//指回原方法
void (*exchange_p)(Method _Nonnull m1, Method _Nonnull m2);
IMP _Nonnull (*getImp_p)(Method _Nonnull m);
IMP _Nonnull(*setImp_p)(Method _Nonnull m, IMP _Nonnull imp);
void hp_exchange(Method _Nonnull m1, Method _Nonnull m2) {
//可以在這里進(jìn)行上報(bào)后端等操作
NSLog(@"find Hook");
}
void (hp_getImp)(Method _Nonnull m) {
NSLog(@"find Hook getImp");
}
void (hp_setImp)(Method _Nonnull m, IMP _Nonnull imp) {
NSLog(@"find Hook setImp");
}
@end
這個時候控制臺輸出:
AntiHookDemo[1488:207119] find Hook getImp
AntiHookDemo[1488:207119] find Hook
AntiHookDemo[1488:207119] find Hook getImp
AntiHookDemo[1488:207119] find Hook
AntiHookDemo[1488:207119] click btn1
點(diǎn)擊btn1
也沒有Hook
到了摄狱。在這里運(yùn)行時有可能Crash
在JSEvaluateScript
的時候脓诡,直接刪除App
重新跑一次就可以了无午。
libsubstrate.dylib
解析的,
其實(shí)這里.xm
文件是被libsubstrate.dylib
解析成MonkeyDemoDylib.mm
中的內(nèi)容(.xm
代碼是不參與編譯的):
MSHookMessageEx
底層用的是setImp
和getImp
對OC
進(jìn)行Hook
的祝谚。
錯誤問題
1.Signing for "MonkeyDemoDylib" requires a development team. Select a development team in the Signing & Capabilities editor.
直接在該target
的build settings
中添加CODE_SIGNING_ALLOWED=NO
https://iosre.com/t/xcode11-monkeydev/17021
2.Failed to locate Logos Processor. Is Theos installed? If not, see https://github.com/theos/theos/wiki/Inst allation.
出現(xiàn)這個錯誤一般是theos
沒有安裝好宪迟。或者路徑配置的有問題交惯。
3.library not found for -libstdc++
需要下載對應(yīng)的庫到XCode
目錄中次泽。參考:https://github.com/longyoung/libstdc.6.0.9-if-help-you-give-a-star
4.The WatchKit app’s Info.plist must have a WKCompanionAppBundleIdentifier key set to the bundle identifier of the companion app.
刪除DerivedData
重新運(yùn)行。
5.This application or a bundle it contains has the same bundle identifier as this application or another bundle that it contains. Bundle identifiers must be unique.
這種情況大概率是手機(jī)上之前安裝過相同bundleId
的App
安裝不同版本導(dǎo)致席爽,需要刪除重新安裝意荤。還有問題的話刪除DerivedData
改bundleId
。
6.This app contains a WatchKit app with one or more Siri Intents app extensions that declare IntentsSupported that are not declared in any of the companion app's Siri Intents app extensions. WatchKit Siri Intents extensions' IntentsSupported values must be a subset of the companion app's Siri Intents extensions' IntentsSupported values.
需要刪除com.apple.WatchPlaceholder
(在/opt/MonkeyDev/Tools
目錄中修改pack.sh
):
rm -rf "${TARGET_APP_PATH}/com.apple.WatchPlaceholder" || true
然后刪除DerivedData
重新運(yùn)行只锻。
-
LLVM Profile Error: Failed to write file "default.profraw": Operation not permitted
這個說明App
內(nèi)部做了反調(diào)試防護(hù)玖像。直接在Monkey
中開啟sysctl
:
rebind_symbols((struct rebinding[1]){{"sysctl", my_sysctl, (void*)&orig_sysctl}},1);
8.Attempted to load Reveal Library twice. Are you trying to load dynamic library with Reveal Framework already linked?
直接刪除dylib
中Other Linker Flags
的設(shè)置即可(可能的原因是手機(jī)端已經(jīng)導(dǎo)入了這個庫):
??遇見莫名其妙的錯誤建議刪除DerivedData
重啟Xcode
重新運(yùn)行。
總結(jié)
- 反
Hook
- 使用
fishhook
Hook
method_exchangeImplementations
齐饮、class_replaceMethod
捐寥、method_setImplementation
- 需要在動態(tài)庫中添加防護(hù)代碼。
- 本地導(dǎo)出原函數(shù)
IMP
供自己項(xiàng)目使用祖驱,配合白名單握恳。 - 這種防護(hù)很容易破解,一般不推薦這么使用羹膳。
- 使用
-
MonkeyDev
:逆向開發(fā)中一個常用的工具睡互。- 重簽名:很容易,直接拖進(jìn)去
.ipa
或者.app
運(yùn)行工程就可以了陵像。 - 代碼注入:
Logos
主要是編寫.xm
文件就珠。底層依然是getImp
和setImp
的調(diào)用。
- 重簽名:很容易,直接拖進(jìn)去