iOS開發(fā) HOOK 上篇之 fishhook

一 HOOK之Method Swizzle

利用OC的Runtime特性,動(dòng)態(tài)改變SEL(方法編號(hào))和IMP(方法實(shí)現(xiàn))的對(duì)應(yīng)關(guān)系,達(dá)到OC方法調(diào)用流程改變的目的甲葬。主要用于OC方法甜刻。

#import <objc/message.h>
+(void)hookClass:(Class )class Withmethod:(SEL)oldMethod newMethod:(SEL)newMethod
{
    Method old = class_getInstanceMethod(class, oldMethod);
    Method news = class_getInstanceMethod(class, newMethod);
    method_exchangeImplementations(old, news);
}
 //交換方法
    [hookManager hookClass:self.class Withmethod:@selector(old) newMethod:@selector(news)];
    //類方法
[hookManager hookClass:object_getClass(self.class) Withmethod:@selector(classOld) newMethod:@selector(classNew)];

二 HOOK之 fishhook

Facebook提供的一個(gè)動(dòng)態(tài)修改鏈接mach-O文件的工具。利用MachO文件加載原理眨八,原理是通過修改懶加載和非懶加載兩個(gè)表的指針達(dá)到C函數(shù)HOOK的目的,所以不能修改自己定義的函數(shù),只能修改系統(tǒng)庫函數(shù)左电。

  1. 簡單使用
#import "fishhook.h"
- (void)viewDidLoad {
    [super viewDidLoad];
    NSLog(@"123");
    //定義rebinding結(jié)構(gòu)體
/*
struct rebinding {
  const char *name;//需要HOOK的函數(shù)名稱,字符串
  void *replacement;//替換到那個(gè)新的函數(shù)上(函數(shù)指針,也就是函數(shù)的名稱)
  void **replaced;//保存原始函數(shù)指針變量的指針(它是一個(gè)二級(jí)指針!)
};
*/
    struct rebinding nslogBind;
    //函數(shù)的名稱
    nslogBind.name = "NSLog";
    //新的函數(shù)地址
    nslogBind.replacement = myNSLog;
    //保存原始函數(shù)地址的變量的指針
    nslogBind.replaced = (void *)&old_nslog;
    //定義數(shù)組
    struct rebinding rebs[] = {nslogBind};
    /*
     arg1 : 存放rebinding結(jié)構(gòu)體的數(shù)組
     arg2 : 數(shù)組的長度
     */
    rebind_symbols(rebs, 1);
}
//函數(shù)指針,用保存原始的函數(shù)的地址
static void (*old_nslog)(NSString *format, ...);
//新的NSLog
void myNSLog(NSString *format, ...){
    format = [format stringByAppendingString:@"\n勾上了!"];
    //再調(diào)用原來的
    old_nslog(format); 
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    NSLog(@"點(diǎn)擊了屏幕!!");   
}
  1. 原理
  • APP運(yùn)行時(shí)踪古,MachO被dyld加載進(jìn)內(nèi)存
  • ASLR讓MachO被加載時(shí)內(nèi)存地址隨機(jī)分配
  • 蘋果的PIC位置與代碼獨(dú)立技術(shù),讓MachO調(diào)用系統(tǒng)庫函數(shù)時(shí)券腔,先在MachO表中的_DATA段建立一個(gè)指針指向外部庫函數(shù)伏穆,dyld加載MachO時(shí)知道外部庫函數(shù)的調(diào)用地址,會(huì)動(dòng)態(tài)的把_DATA段的指針指向外部庫函數(shù)
  • fishhook通過nslogBind.name = "NSLog" 就能替換庫函數(shù)纷纫,是因?yàn)镸achO的符號(hào)表里有NSLog等枕扫,可以通過符號(hào)表找到NSLog字符串
  1. 原理求證
  • 在 rebind_symbols(rebs, 1);處打個(gè)斷點(diǎn),進(jìn)入包內(nèi)容辱魁,找到MachO可執(zhí)行文件烟瞧,用MachOView打開找到懶加載和非懶加載兩個(gè)表诗鸭,如下:


    1.png

    得到NSLog的偏移量為0x8018

  • 斷點(diǎn)斷住后,用lldb輸入image list得到如下:
(lldb) image list
[  0] 48743862-C387-35A9-AC9E-973B65CCE0F4 0x0000000100688000 /Users/mac/Library/Developer/Xcode/DerivedData/001--fishHookDemo-gwgiujnhvjhvlsfgctoolqctiwnc/Build/Products/Debug-iphoneos/001--fishHookDemo.app/001--fishHookDemo

即MachO文件的起始地址是0x0000000100688000参滴,那么NSLog的地址是0x8018+0x0000000100688000

  • lldb調(diào)試讀取NSLog地址的內(nèi)存
(lldb) x 0x0000000100688000+0x8018  //memory read 0x0000000100688000+0x8018
0x100690018: 80 a6 4d 85 01 00 00 00 a8 61 4d 85 01 00 00 00  ..M......aM.....
0x100690028: a0 56 9f 8e 01 00 00 00 64 eb 68 00 01 00 00 00  .V......d.h.....
  • 得到內(nèi)容為0x01854da680,然后再dis -s 0x01854da680 輸出如下:
Foundation`NSLog:
    0x1854da680 <+0>:  sub    sp, sp, #0x20             ; =0x20 
    0x1854da684 <+4>:  stp    x29, x30, [sp, #0x10]
    0x1854da688 <+8>:  add    x29, sp, #0x10            ; =0x10 
    0x1854da68c <+12>: add    x8, x29, #0x10            ; =0x10 
    0x1854da690 <+16>: str    x8, [sp, #0x8]
    0x1854da694 <+20>: add    x1, x29, #0x10            ; =0x10 
    0x1854da698 <+24>: mov    x2, x30
    0x1854da69c <+28>: bl     0x18557bc68               ; _NSLogv
  • 過了斷點(diǎn)后再x 0x0000000100688000+0x8018 得到如下:
0x100690018: c8 dd 68 00 01 00 00 00 a8 61 4d 85 01 00 00 00  ..h......aM.....
0x100690028: a0 56 9f 8e 01 00 00 00 d8 7d 55 84 01 00 00 00  .V.......}U.....

得到地址0x010068ddc8,然后dis -s 0x010068ddc8 得到:

001--fishHookDemo`myNSLog:
    0x10068ddc8 <+0>:  sub    sp, sp, #0x30             ; =0x30 
    0x10068ddcc <+4>:  stp    x29, x30, [sp, #0x20]
    0x10068ddd0 <+8>:  add    x29, sp, #0x20            ; =0x20 
    0x10068ddd4 <+12>: mov    x8, #0x0
    0x10068ddd8 <+16>: stur   x8, [x29, #-0x8]
    0x10068dddc <+20>: sub    x9, x29, #0x8             ; =0x8 
    0x10068dde0 <+24>: str    x0, [sp, #0x10]
    0x10068dde4 <+28>: mov    x0, x9

即NSLog被myNSLog替換了

  1. 通過符號(hào)表强岸,查找字符串
  • MachO的Dynamic Symbol Table下的Indirect Symbols表和 Lazy Symbol Pointers表一一對(duì)應(yīng)


    2.png
  • _NSLog的Data 0x7A 是Symbols表的下標(biāo),0x7A的十進(jìn)制是122砾赔,那么找到Symbols表的#122位置處:


    3.png
  • 得到_NSLog在字符串表的偏移量是0x9B蝌箍,然后字符串表,表的起始地址是0xCEFC,加上偏移量0x9B得到0xcf97,在表中找到0xcf97果然找到NSLlog


    4.png

總過程如圖

image

三 基本防護(hù)

因?yàn)槲募虞d的順序,防護(hù)代碼寫在framework中的load函數(shù)中暴心,因?yàn)閒ramework中的load函數(shù)會(huì)被先調(diào)用妓盲,從而起到防護(hù)作用
文件加載順序:framework中的load -> ViewController的load ->AppDelegate的load


1.png

基本防護(hù)代碼:

#import "fishhook.h"
#import <objc/message.h>

@implementation hookMgr
//專門HOOK
+(void)load
{
    //內(nèi)部用到的交換代碼 寫在這里
    Method old = class_getInstanceMethod(objc_getClass("ViewController"), @selector(btnClick1:));
    Method new = class_getInstanceMethod(self, @selector(click1Hook:));
    method_exchangeImplementations(old, new);
    //基本防護(hù) 會(huì)檢測(cè)到外部的hook
    struct rebinding bd;
    bd.name = "method_exchangeImplementations";
    bd.replacement = myExchang;
    bd.replaced = (void *)&exchangeP; 
    struct rebinding bd2;
    bd2.name = "method_setImplementation";
    bd2.replacement = myExchang;
    bd2.replaced = (void *)&setIMP;
    
//    method_setImplementation
    
    struct rebinding rebindings[] = {bd,bd2};
    rebind_symbols(rebindings, 2);
}

//保留原來的交換函數(shù)
IMP _Nonnull (*setIMP)(Method _Nonnull m, IMP _Nonnull imp);
void (*exchangeP)(Method _Nonnull m1, Method _Nonnull m2);

//新的函數(shù)
void myExchang(Method _Nonnull m1, Method _Nonnull m2){
    NSLog(@"檢測(cè)到了HOOK!!!");
    //強(qiáng)制退出!
    exit(1);
}
-(void)click1Hook:(id)sendr{
    NSLog(@"原來APP的HOOK保留!!");
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市专普,隨后出現(xiàn)的幾起案子悯衬,更是在濱河造成了極大的恐慌,老刑警劉巖檀夹,帶你破解...
    沈念sama閱讀 206,126評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件筋粗,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡炸渡,警方通過查閱死者的電腦和手機(jī)娜亿,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來偶摔,“玉大人,你說我怎么就攤上這事促脉〕秸” “怎么了?”我有些...
    開封第一講書人閱讀 152,445評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵瘸味,是天一觀的道長宫仗。 經(jīng)常有香客問我,道長旁仿,這世上最難降的妖魔是什么藕夫? 我笑而不...
    開封第一講書人閱讀 55,185評(píng)論 1 278
  • 正文 為了忘掉前任,我火速辦了婚禮枯冈,結(jié)果婚禮上毅贮,老公的妹妹穿的比我還像新娘。我一直安慰自己尘奏,他們只是感情好滩褥,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,178評(píng)論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著炫加,像睡著了一般瑰煎。 火紅的嫁衣襯著肌膚如雪铺然。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 48,970評(píng)論 1 284
  • 那天酒甸,我揣著相機(jī)與錄音魄健,去河邊找鬼。 笑死插勤,一個(gè)胖子當(dāng)著我的面吹牛沽瘦,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播饮六,決...
    沈念sama閱讀 38,276評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼其垄,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了卤橄?” 一聲冷哼從身側(cè)響起绿满,我...
    開封第一講書人閱讀 36,927評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎窟扑,沒想到半個(gè)月后喇颁,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,400評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡嚎货,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,883評(píng)論 2 323
  • 正文 我和宋清朗相戀三年橘霎,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片殖属。...
    茶點(diǎn)故事閱讀 37,997評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡姐叁,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出洗显,到底是詐尸還是另有隱情外潜,我是刑警寧澤,帶...
    沈念sama閱讀 33,646評(píng)論 4 322
  • 正文 年R本政府宣布挠唆,位于F島的核電站处窥,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏玄组。R本人自食惡果不足惜滔驾,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,213評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望俄讹。 院中可真熱鬧哆致,春花似錦、人聲如沸患膛。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至驹溃,卻和暖如春城丧,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背豌鹤。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評(píng)論 1 260
  • 我被黑心中介騙來泰國打工亡哄, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人布疙。 一個(gè)月前我還...
    沈念sama閱讀 45,423評(píng)論 2 352
  • 正文 我出身青樓蚊惯,卻偏偏與公主長得像,于是被迫代替她去往敵國和親灵临。 傳聞我的和親對(duì)象是個(gè)殘疾皇子截型,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,722評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容