通常情況下,想去了解一個App,可以進(jìn)行重簽名后,在進(jìn)行
view hierarchy debug調(diào)試了解。
對App破解時,一般是修改原始的程序,主要是利用代碼注入的方式,注入代碼就會選擇Framework或者Dylib等第三方庫等方式注入。
Framework注入
- 重簽名App
- Xcode新建Framework,編譯,將庫安裝進(jìn)App包中
- 通過yololib注入Framwork庫路徑。修改Mach-O文件
$yololib Mach-O文件路徑 Framework文件路徑- 所有的Framework加載都是有DYLD加載進(jìn)內(nèi)存被執(zhí)行的
- 注入成功的庫路徑會寫入Mach-O文件的LC_LOAD_DYLIB字段中
- 替換Mach-O文件,重新打包成
.ipa文件
腳本注入方式:
在重簽名腳本中追加注入腳本
yololib "目標(biāo)App的Mach-O路徑" "注入的framework文件路徑"
Dylib注入
- 重簽名App
- 通過Xcode新建Dylib庫(注意:Dylib屬于MacOS,所以需要修改屬性)
- 添加Target依賴,讓Xcode將自定義Dylib文件打包進(jìn)App包中
- 利用yololib指令進(jìn)行注入(同F(xiàn)ramework注入)
HOOK
HOOK,中文譯為“掛鉤”或者“鉤子”。
在iOS逆向開發(fā)中,是指改變程序運(yùn)行流程的一種技術(shù)。通過hook可以使別人的程序執(zhí)行自己所寫的代碼。
iOS中HOOK技術(shù)的幾種方式
Method Swizzle
利用OC的Runtime特性,動態(tài)改變SEL(方法編號)和IMP(方法實(shí)現(xiàn))的對應(yīng)關(guān)系,達(dá)到OC方法調(diào)用流程改變的目的。主要用于OC方法
原理
在OC中,SEL和IMP之間的關(guān)系,就好像書的目錄一樣。
SEL是方法編號,就像“標(biāo)題”一樣
IMP是方法實(shí)現(xiàn)的真實(shí)地址,就像“頁碼”一樣。
Runtime提供了交換兩個SEL和IMP對應(yīng)關(guān)系的函數(shù)。
Method Swizzle的實(shí)現(xiàn)方式
// 添加方法的方式進(jìn)行交換
Method oldMethod = class_getInstanceMethod(objc_getClass("class"), @selector(oldSelector));
BOOL didAddMethod = class_addMethod(objc_getClass("class"), @selector(newSelector), my_selector, "v@:");
Method newMethod = class_getInstanceMethod(objc_getClass("class"), @selector(newSelector));
method_exchangeImplementations(oldMethod, newMethod);
// 新增的IMP
void newSelector(id self, SEL _cmd) {
// hook實(shí)現(xiàn)
[self performSelector:@selector(newSelector)]; //繼續(xù)執(zhí)行原始方法
}
// 替換
Method oldSel = class_getInstanceMethod(objc_getClass("class"), @selector(oldSel));
oldSelector = method_getImplementation(oldSel); //舊的IMP保存
class_replaceMethod(objc_getClass("class"), @selector(oldSel), newSelector, "v@:");
// 用于保存舊的IMP
IMP (*oldSelector)(id self, SEL _cmd);
// 新的IMP實(shí)現(xiàn)
void newSelector(id self, SEL _cmd) {
// hook實(shí)現(xiàn)
oldSelector(self, _cmd);
}
// getIMP 和 setIMP 進(jìn)行方法修改
Method oldSel = class_getInstanceMethod(objc_getClass("class"), @selector(oldSel));
oldSelector = method_getImplementation(oldSel);
method_setImplementation(oldSel, newSelector);
IMP (*oldSelector)(id self, SEL _cmd);
void newSelector(id self, SEL _cmd) {
// hook實(shí)現(xiàn)
oldSelector(self, _cmd);
}
fishHook
fishhook 源碼地址:https://github.com/facebook/fishhook
由動態(tài)修改鏈接Mach-O文件的工具。
利用Mach-O文件加載原理,通過修改懶加載和非懶加載兩個表的指針,達(dá)到C函數(shù)Hook的目的。
fishhook.h
/*
* 結(jié)構(gòu)體
* 表示從符號名到替換名的特定重新綁定
*/
struct rebinding {
const char *name; //需要HOOK的函數(shù)名稱,C字符串
void *replacement; //新函數(shù)的地址
void **replaced; //原始函數(shù)地址的指針!
};
/*
* 重新綁定符號
* rebindings:要重新綁定的結(jié)構(gòu)體數(shù)組
* rebindings_nel:重新綁定的數(shù)量
* 如果rebind_functions被多次調(diào)用,
* 則要重新綁定的符號將被添加到現(xiàn)有的重新綁定列表中,
* 如果給定的符號被多次重新綁定,則優(yōu)先執(zhí)行后面的重新綁定。
*/
int rebind_symbols(struct rebinding rebindings[], size_t rebindings_nel);
/*
* 如上所述重新綁定,但僅在指定的image中。
* header:指iamge的頭
* slide:是相對偏移量(ASLR)
*/
int rebind_symbols_image(void *header,
intptr_t slide,
struct rebinding rebindings[],
size_t rebindings_nel);
fishhook使用例子
- (void)hookFunction {
struct rebinding nslog;
nslog.name = "NSLog";
nslog.replacement = myNSLog;
//fishhook在運(yùn)行時刻,動態(tài)獲取相應(yīng)函數(shù)的地址
nslog.replaced = (void *)&sys_nslog;
struct rebinding rebs[1] = {nslog};
rebind_symbols(rebs, 1);
}
// 函數(shù)指針,用于保存原始函數(shù)地址
static void(*sys_nslog)(NSString *format,...);
// 定義一個新的函數(shù)
void myNSLog(NSString *format,...) {
// hook 內(nèi)容實(shí)現(xiàn)
sys_nslog(format); //調(diào)用原來的函數(shù)
}
只針對
系統(tǒng)的函數(shù),對于自定義的函數(shù)無法進(jìn)行交換HOOK。
原理
-
兩個前導(dǎo)知識
- 蘋果為了節(jié)約內(nèi)存和提高加載速度,將系統(tǒng)的動態(tài)庫放在內(nèi)存的特殊位置,然后將這塊內(nèi)存共享給其他應(yīng)用。這塊區(qū)域就是
動態(tài)庫共享緩存(dyld share cache)。 - PIC技術(shù)(位置代碼獨(dú)立)
- 由于使用共享緩存,使得所調(diào)用的系統(tǒng)函數(shù)在編譯時無法確定內(nèi)存地址
- 所以蘋果采用了PIC技術(shù),在Mach-O文件的DATA段中建立兩張表,懶加載和非懶加載表,利用存放指向外部函數(shù)的指針
- 在運(yùn)行,調(diào)用到對應(yīng)的函數(shù)時,DYLD則會相應(yīng)的函數(shù)進(jìn)行綁定。
- 蘋果為了節(jié)約內(nèi)存和提高加載速度,將系統(tǒng)的動態(tài)庫放在內(nèi)存的特殊位置,然后將這塊內(nèi)存共享給其他應(yīng)用。這塊區(qū)域就是
-
通過字符查找對應(yīng)的表
- fishhook利用string Table、Symbols、indirect symbols、懶加載表之間的對應(yīng)關(guān)系查找到相應(yīng)的指針,再通過重新綁定的方式進(jìn)行指針修改。
fishhook就是利用綁定符號這一邏輯進(jìn)行方法的替換綁定,而
自定義函數(shù)無需通過符號表,因此無法進(jìn)行重新綁定。
Cydia Substrate
Cydia Substrate原名 Mobile Substrate,它主要作用是針對OC方法,C函數(shù)以及函數(shù)地址進(jìn)行HOOK操作。不僅僅只是針對iOS設(shè)計的,Android一樣可用。
MobileHooker
采用一系列的宏和函數(shù),底層調(diào)用objc的Runtime和fishhook來替換系統(tǒng)或者目標(biāo)應(yīng)用的函數(shù)。
兩個函數(shù):
- MSHookMessageEx
主要作用于Objective-C方法
void MSHookMessageEx(Class class, SEL selector, IMP replacement, IMP result)
- MSHookFunction
主要作用于C和C++函數(shù)
void MSHookFunction(void function, void* replacement, void** p_original)
MobileLoader
MobileLoader用于加載第三方dylib到運(yùn)行的應(yīng)用程序中。
啟動時MobileLoader會根據(jù)規(guī)則把指定目錄的第三方的動態(tài)庫加載進(jìn)去,第三方的動態(tài)庫也就是我們所寫的Hook代碼。
Safe Mode
破解程序本質(zhì)是dylib,寄生在別人的進(jìn)程里。
系統(tǒng)進(jìn)程一旦出錯,可能導(dǎo)致整個進(jìn)程崩潰,崩潰后會造成iOS癱瘓。所以CydiaSubstrate引入了俺去模式,在安全模式下的所有基于CydiaSubstrate的第三方dylib都會被禁用,便于差錯和修復(fù)。