fishhook的原理及實例

1. Hook的方式

Hook是改變程序運行流程的一種方式祭芦,通過Hook可以讓自己的代碼運行在別人的程序中孔厉。需要了解其Hook原理墓律,這樣就能夠?qū)阂獯a攻擊進(jìn)行有效的防護(hù)蒂窒。

1.1 Method Swizzle

Method Swizzle 是利用OC的Runtime的特性躁倒,去動態(tài)改變SEL(方法編號)與IMP(方法實現(xiàn))的對應(yīng)關(guān)系,達(dá)到OC方法調(diào)用流程更改的目的洒琢。也是主要用于OC方法秧秉。

1.2 Cydia Substrate

Cydia Substrate 原名叫做Mobile SubStrate,主要作用為針對C函數(shù)衰抑,OC函數(shù)以及函數(shù)的地址進(jìn)行Hook操作象迎。并且有個很大的優(yōu)勢,Cydia Substrate 并不是僅僅是針對iOS設(shè)計呛踊,Andriod一樣也可以使用砾淌。Cydia Substrate定義了一系列的函數(shù)和宏,底層調(diào)用了objc的runtime和fishHook來替代目標(biāo)函數(shù)或者系統(tǒng)方法谭网。

其中有兩個函數(shù)
MSHookMessageEx主要用于OC方法汪厨;
MSHookFunction主要用于C++和C函數(shù)。

MobileLoader:主要用于加載第三方dylib運行的應(yīng)用程序中蜻底。啟動時MobileLoader會根據(jù)指定的第三方動態(tài)庫加載進(jìn)去骄崩,第三方動態(tài)庫也是我們寫的破解程序聘鳞。
safe mode:破解程序的本質(zhì)在于dylib,寄生于別人程序進(jìn)程中要拂。但是系統(tǒng)進(jìn)程一旦出現(xiàn)錯誤抠璃,可能會導(dǎo)致整個進(jìn)程崩潰,也可能會導(dǎo)致iOS程序崩潰脱惰。在Cydia Substrate 中引入了安全模式搏嗡,如果一旦錯誤,三方的dylib會被禁用拉一,便于查錯和修復(fù)采盒。

1.3 fishHook

fishHook是Facebook提供一種動態(tài)修改鏈接Mach-O文件的工具。此利用Mach-O文件加載原理蔚润,通過修改非懶加載和懶加載兩個表的指針達(dá)到C函數(shù)的Hook的目的磅氨。

今天我們主要介紹第三種方式fishHook達(dá)到更改程序的目的。

2. fishhook的原理及實例

fishhook的源碼地址嫡纠,fishhook的主要方法有兩個還有一個結(jié)構(gòu)體:

查看代碼結(jié)構(gòu)為烦租,將紅色圈起來部分移入到代碼中,即可使用fishhook來hook代碼除盏。

2.1 實例1

// rebinding 結(jié)構(gòu)體的定義
//    struct rebinding {
//        const char *name; // 需要 HOOK 的函數(shù)名稱叉橱,字符串
//        void *replacement; // 替換的新函數(shù)(函數(shù)指針,也就是函數(shù)名稱)
//        void **replaced; //  保存原始函數(shù)指針變量/地址的指針(它是一個二級指針!)
//    };
// C 語言傳參是值/址傳遞的者蠕,把它的值/址穿過去窃祝,就可以在函數(shù)內(nèi)部修改函數(shù)指針變量的值
 
- (void)viewDidLoad {
    [super viewDidLoad];
     NSLog(@"123");
    //rebinding結(jié)構(gòu)體
    struct rebinding nslog;
    nslog.name = "NSLog";// 函數(shù)名稱
    nslog.replacement = myNslog; // 新的函數(shù)指針
    nslog.replaced = (void *)&sys_nslog;// 保存原始函數(shù)地址的變量的指針
    //rebinding結(jié)構(gòu)體數(shù)組
    ] = {nslog};
    /**
     * 存放rebinding結(jié)構(gòu)體的數(shù)組
     * 數(shù)組的長度
     */
    rebind_symbols(rebs, );
}
//---------------------------------更改NSLog-----------
//函數(shù)指針,用來保存原始的函數(shù)地址 (C 語言語法踱侣,函數(shù)指針類型變量)
static void(*sys_nslog)(NSString * format,...);
//定義一個新的函數(shù)
void myNslog(NSString * format,...){
    format = [format stringByAppendingString:@"勾上了粪小!\n"];
    //調(diào)用原始的
    sys_nslog(format);
}
 
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    NSLog(@"點擊了屏幕!泻仙!");
}

上面的代碼運行結(jié)果如下:

2.2 實例2

void func(const char * str){
    NSLog(@"%s",str);
}
 
- (void)viewDidLoad {
    [super viewDidLoad];
    //rebinding結(jié)構(gòu)體
    struct rebinding nslog;
    nslog.name = "func";
    nslog.replacement = new_func;
    nslog.replaced = (void *)&old_func;
    //rebinding結(jié)構(gòu)體數(shù)組
    ] = {nslog};
    /**
     * 存放rebinding結(jié)構(gòu)體的數(shù)組
     * 數(shù)組的長度
     */
    rebind_symbols(rebs, );
}
//---------------------------------更改NSLog-----------
//函數(shù)指針
static void(*old_func)(const char * str);
//定義一個新的函數(shù)
void new_func(const char * str){
      NSLog(@"%s + 1",str);
}
 
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    func("哈哈");
}

運行結(jié)果如下:

從上面可以看出自定義的交換方法為什么交換不了呢糕再?首先可以肯定的是代碼是OK的,下面我們講解原理玉转,為什么自定義的方法不行呢?

3. 原理探究

系統(tǒng)內(nèi)核分別加載Mach-O文件殴蹄、dyld動態(tài)連接器究抓,首先通過ASLR技術(shù)(地址空間布局隨機(jī)化)加載可執(zhí)行文件呀潭,MachO文件被加載的時候是隨機(jī)地址兄猩,加載MachO文件完成后敬惦,dyld開始加載依賴的動態(tài)庫豫领,調(diào)試時通過命令 image List 可看到相關(guān)的類庫鸠窗。

PIC(Promrammable Interrupt Controller)位置代碼獨立擦盾,由外設(shè)發(fā)出中斷請求需要中斷控制器來處理除嘹。如果MachO內(nèi)部需要調(diào)用系統(tǒng)的庫函數(shù)時展鸡,先在_DATA段中建立一個指針,指向外部函數(shù)畅卓,dyld會動態(tài)的進(jìn)行綁定擅腰,將MachO中的DATA段中的指針,指向外部函數(shù)(DYLD會告訴MachO要依賴的外部庫的位置)翁潘。_DATA段中建立的指針就是符號(symbols)趁冈,它是幫你指向內(nèi)部的函數(shù)調(diào)用,指向外部的函數(shù)地址拜马。所以渗勘,fishhook的rebind_symbols(重新綁定符號)函數(shù),它就是將你指向系統(tǒng)的NSLog的符號俩莽,給重新進(jìn)行綁定旺坠,變?yōu)橹赶蚰銉?nèi)部的函數(shù),這樣子就達(dá)到修改的目的了扮超;這也是fishhook的底層原理取刃。這也就是為什么使用fishhook時我們內(nèi)部的函數(shù)修改不了,自定義的函數(shù)修改不了的原因瞒津,只能修改MachO外部的函數(shù)蝉衣。

Mach-O文件內(nèi)部調(diào)用系統(tǒng)函數(shù)時:
1)Mach-O _data段建立了一個指針(也就是符號,實現(xiàn)指向內(nèi)部的函數(shù)調(diào)用巷蚪,指向了外部的函數(shù)地址)病毡,指向了外部函數(shù)(dyld),可讀可寫屁柏,當(dāng)Mach-O被加載進(jìn)去啦膜,就會指向所指的函數(shù)。
2)Dyld會動態(tài)的綁定淌喻,將Mach-O中的data 段中指針指向了外部的函數(shù)僧家,也是Dyld為什么叫做動態(tài)綁定的原因。

這也回答了上面的問題裸删,為什么內(nèi)部/自定義的函數(shù)不能修改八拱,只能修改Mach-O文件的外部函數(shù),如果是另外一個動態(tài)庫或者需要動態(tài)符號綁定的就可以(符號表中能找到才可以實現(xiàn))

利用第一個Demo來測試涯塔,運行起來肌稻,然后查看可執(zhí)行文件,通過MachoView工具:

從圖2看出offset偏移地址為3028匕荸,也就是NSLog函數(shù)文件的偏移地址爹谭,懶加載此表時在Mach-O文件偏移地址+函數(shù)偏移的地址。

下面以Demo1查看榛搔,在Demo1打斷點诺凡,查看Mach-O函數(shù)偏移地址东揣,通過指令image list 第一個就是Mach-O內(nèi)容和地址(本人上篇博客地址即可)

Mach-O在內(nèi)存的偏移地址也就是Mach-O的真實地址,發(fā)現(xiàn)為 0x000000010a9c5000

通過上面紅色加重算法腹泌,計算Mach-O文件Data段的函數(shù)指針

發(fā)現(xiàn)執(zhí)行完只有就會被綁定嘶卧。NSLog函數(shù)文件就會被綁定。

下面再看一下真屯,對于屏幕點擊的脸候,hook如下

前提是我們?nèi)コ齎iewDidLoad方法里面的NSLog(@“123”)這句代碼,運行代碼绑蔫,最后將斷點斷在touchesBegan里面运沦,此時開始看地址和內(nèi)容

截圖的前兩次打印是程序運行時,但是未曾點擊touchesBegan配深,后兩次是點擊屏幕時斷點進(jìn)入到了里面携添,再看內(nèi)容,打印的對象是NSLog還是myNslog篓叶,通過上面發(fā)現(xiàn)是myNslog烈掠,說明Hook成功。

通過上面可看出缸托,fishhook能夠Hook c函數(shù)左敌,是因為Mach-O文件特點,PIC位置代碼獨立造就了靜態(tài)語言C也有動態(tài)的部分俐镐,之后通過Dyld進(jìn)行動態(tài)綁定的時機(jī)矫限,在這其中我們就可以做手腳,替換自定義的方法佩抹。

fishhook是根據(jù)方法字符串的名字“NSLog”叼风,它是怎么找到的呢?下面將講解利用符號表查看函數(shù)名稱字符串棍苹。

4. 符號表查看函數(shù)名稱

再次查看Mach-O文件无宿,查看懶加載表中的NSLog函數(shù)

懶加載表是和動態(tài)符號表是一一對應(yīng)關(guān)系,通過上面發(fā)現(xiàn)NSLog函數(shù)時第一個枢里,而對應(yīng)的Dynamic Symbol table也是第一個孽鸡,打開Dynamic Symbol table

查看Dynamic Symbol Table 第一個也是NSLog,查看Data值為7A栏豺,對應(yīng)的十進(jìn)制為122梭灿,然后到Symbols Table里面查看122,如下:

查看Symbols Table的data值為0000009B冰悠,然后在String Table Index去看函數(shù)偏移值為0000009B的內(nèi)容,如下:

為什么選擇00004F94查看NSLog呢配乱,我們從上面得知Symbols Table的data值為0000009B溉卓,然后加上String Table的函數(shù)第一個地址為00004F04皮迟,然后將0000009B + 00004F04 = 0X4F9F,最后看00004F94里面包含了0X4F9F桑寨,藍(lán)色內(nèi)容看出是NSLog內(nèi)容伏尼,也就是找到啦。完美N疚病1住!

以上過程可以在fishhook中g(shù)ithub上有說明圖:

上面的說明圖也就是通過符號表查看函數(shù)名稱以及反過來也可以逆查的過程沙咏。配上說明圖辨图,方便大家熟悉流程。

5. 總結(jié)

上面講述了Hook的幾種技術(shù)方式以及fishhook的原理探究肢藐,以及如何讓別人的app實現(xiàn)自己的代碼故河。下面我們對此總結(jié)一下,寫了一個本篇博客的整個過程便于大家整理吆豹,希望對大家有所幫助加深理解鱼的。

原文地址:
https://www.bbsmax.com/A/1O5E3rQ3z7/
http://www.reibang.com/p/bc1c000afdba
https://mp.weixin.qq.com/s/-uBmPtpupzoDnqKx9U-P2Q
感謝!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末痘煤,一起剝皮案震驚了整個濱河市凑阶,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌衷快,老刑警劉巖宙橱,帶你破解...
    沈念sama閱讀 211,265評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異烦磁,居然都是意外死亡养匈,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評論 2 385
  • 文/潘曉璐 我一進(jìn)店門都伪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來呕乎,“玉大人,你說我怎么就攤上這事陨晶♀剩” “怎么了?”我有些...
    開封第一講書人閱讀 156,852評論 0 347
  • 文/不壞的土叔 我叫張陵先誉,是天一觀的道長湿刽。 經(jīng)常有香客問我,道長褐耳,這世上最難降的妖魔是什么诈闺? 我笑而不...
    開封第一講書人閱讀 56,408評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮铃芦,結(jié)果婚禮上雅镊,老公的妹妹穿的比我還像新娘襟雷。我一直安慰自己,他們只是感情好仁烹,可當(dāng)我...
    茶點故事閱讀 65,445評論 5 384
  • 文/花漫 我一把揭開白布耸弄。 她就那樣靜靜地躺著,像睡著了一般卓缰。 火紅的嫁衣襯著肌膚如雪计呈。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,772評論 1 290
  • 那天征唬,我揣著相機(jī)與錄音捌显,去河邊找鬼。 笑死鳍鸵,一個胖子當(dāng)著我的面吹牛苇瓣,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播偿乖,決...
    沈念sama閱讀 38,921評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼击罪,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了贪薪?” 一聲冷哼從身側(cè)響起媳禁,我...
    開封第一講書人閱讀 37,688評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎画切,沒想到半個月后竣稽,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,130評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡霍弹,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,467評論 2 325
  • 正文 我和宋清朗相戀三年毫别,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片典格。...
    茶點故事閱讀 38,617評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡岛宦,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出耍缴,到底是詐尸還是另有隱情砾肺,我是刑警寧澤,帶...
    沈念sama閱讀 34,276評論 4 329
  • 正文 年R本政府宣布防嗡,位于F島的核電站变汪,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏蚁趁。R本人自食惡果不足惜裙盾,卻給世界環(huán)境...
    茶點故事閱讀 39,882評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧闷煤,春花似錦童芹、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,740評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽署咽。三九已至近顷,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間宁否,已是汗流浹背窒升。 一陣腳步聲響...
    開封第一講書人閱讀 31,967評論 1 265
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留慕匠,地道東北人饱须。 一個月前我還...
    沈念sama閱讀 46,315評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像台谊,于是被迫代替她去往敵國和親蓉媳。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,486評論 2 348