Hook原理--逆向開發

今天咱們將繼續講解逆向開發工程另外一個重要內容--Hook原理講解。Hook,能夠中文譯爲「掛鉤」或者「鉤子」,逆向開發中改變程序運行的一種技術。按照以下過程進行講解git

  1. Hook概述
  2. Hook技術方式
  3. fishhook原理及實例
  4. 符號表查看函數名稱
  5. 總結

1、Hook概述

在逆向開發中是指改變程序運行流程的技術,經過Hook可讓本身的代碼運行在別人的程序中。須要瞭解其Hook原理,這樣就可以對惡意代碼攻擊進行有效的防禦。github

 

2、Hook技術方式

2.1 Method Swizzle方式

Method Swizzle 上次已經講到,是利用OC的Runtime的特性,去動態改變SEL(方法編號)與IMP(方法實現)的對應關係,達到OC方法調用流程更改的目的。也是主要用於OC方法。算法

2.2 Cydia Substrate方式

Cydia Substrate 原名叫作Mobile SubStrate,主要做用爲針對C函數,OC函數以及函數的地址進行Hook操做。而且有個很大的優點,Cydia Substrate 並非僅僅是針對iOS設計,Andriod同樣也可使用。數組

2.2.1

Cydia Substrate定義了一系列的函數和宏,底層調用了objc的runtime和fishHook來替代目標函數或者系統方法。安全

其中有兩個函數app

  • MSHookMessageEx主要用於OC方法
void MSHookMessageEx(Class class, SEL selector, IMP replacement, IMP result)
  • MSHookFunction主要用於C++和C函數
void MSHookFunction(voidfunction,void* replacement,void** p_original)

2.2.2 MobileLoader

MobileLoader主要用於加載第三方dylib運行的應用程序中。啓動時MobileLoader會根據指定的第三方動態庫加載進去,第三方動態庫也是咱們寫的破解程序。函數

2.2.3 safe mode

破解程序的本質在於dylib,寄生於別人程序進程中。可是系統進程一旦出現錯誤,可能會致使整個進程崩潰,也可能會致使iOS程序崩潰。在Cydia Substrate 中引入了安全模式,若是一旦錯誤,三方的dylib會被禁用,便於查錯和修復。工具

2.3 fishHook

fishHook是Facebook提供一種動態修改連接Mach-O文件的工具。此利用Mach-O文件加載原理,經過修改非懶加載和懶加載兩個表的指針達到C函數的Hook的目的。測試

今天咱們主要講解第三種方式fishHook達到更改程序的目的。spa

 

3、fishhook原理及實例

3.1 概述

fishhook的源碼地址爲https://github.com/facebook/fishhook

fishhook的主要方法有兩個還有一個結構體

查看代碼結構爲,將紅色圈起來部分移入到代碼中,便可使用fishhook來hook代碼。

 

 3.2 實例

3.2.1 Demo1實例1

// rebinding 結構體的定義 // struct rebinding { // const char *name; // 須要 HOOK 的函數名稱,字符串 // void *replacement; // 替換的新函數(函數指針,也就是函數名稱) // void **replaced; // 保存原始函數指針變量/地址的指針(它是一個二級指針!) // }; // C 語言傳參是值/址傳遞的,把它的值/址穿過去,就能夠在函數內部修改函數指針變量的值

- (void)viewDidLoad {
    [super viewDidLoad];
     NSLog(@"123"); //rebinding結構體
    struct rebinding nslog;
    nslog.name = "NSLog";// 函數名稱
    nslog.replacement = myNslog; // 新的函數指針
    nslog.replaced = (void *)&sys_nslog;// 保存原始函數地址的變量的指針
    //rebinding結構體數組
    struct rebinding rebs[1] = {nslog};
    /**
     * 存放rebinding結構體的數組
     * 數組的長度
     */
    rebind_symbols(rebs, 1);
}
//---------------------------------更改NSLog-----------
//函數指針,用來保存原始的函數地址 (C 語言語法,函數指針類型變量)
static void(*sys_nslog)(NSString * format,...);
//定義一個新的函數
void myNslog(NSString * format,...){
    format = [format stringByAppendingString:@"勾上了!\n"];
    //調用原始的
    sys_nslog(format);
}

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    NSLog(@"點擊了屏幕!!");
}

上面的代碼運行結果以下:

3.2.2 Demo2實例2

void func(const char * str){
    NSLog(@"%s",str);
}

- (void)viewDidLoad {
    [super viewDidLoad];
    //rebinding結構體
    struct rebinding nslog;
    nslog.name = "func";
    nslog.replacement = new_func;
    nslog.replaced = (void *)&old_func;
    //rebinding結構體數組
    struct rebinding rebs[1] = {nslog};
    /**
     * 存放rebinding結構體的數組
     * 數組的長度
     */
    rebind_symbols(rebs, 1);
}
//---------------------------------更改NSLog-----------
//函數指針
static void(*old_func)(const char * str);
//定義一個新的函數
void new_func(const char * str){
      NSLog(@"%s + 1",str);
}

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    func("哈哈");
}

運行結果以下:

從上面能夠看出自定義的交換方法爲何交換不了呢?首先能夠確定的是代碼是OK的,下面咱們講解原理,爲何自定義的方法不行呢?

 

 3.3 原理探究

Mach-O文件是如何加載的?

Dyld工具動態加載,加載MachO文件完成後,開始加載依賴的動態庫,也就是經過上篇博客的image List 可看到相關的類庫。

PIC(Promrammable Interrupt Controller)位置代碼獨立,由外設發出中斷請求須要中斷控制器來處理。

Mach-O文件內部調用系統函數時:

  • Mach-O _data段創建了一個指針(也就是符號,實現指向內部的函數調用,指向了外部的函數地址),指向了外部函數(dyld),可讀可寫,當Mach-O被加載進去,就會指向所指的函數。
  • Dyld會動態的綁定,將Mach-O中的data 段中指針指向了外部的函數,也是Dyld爲何叫作動態綁定的緣由。

這也回答了上面的問題,爲何內部/自定義的函數不能修改,只能修改Mach-O文件的外部函數,若是是另一個動態庫或者須要動態符號綁定的就能夠(符號表中能找到才能夠實現)

 

下面咱們是真實查看內容,經過實例

利用第一個Demo來測試,運行起來,而後查看可執行文件,經過MachoView工具

 

從圖2看出offset偏移地址爲3028,也就是NSLog函數文件的偏移地址,懶加載此表時在Mach-O文件偏移地址+函數偏移的地址。

下面以Demo1查看,在Demo1打斷點,查看Mach-O函數偏移地址,經過指令image list 第一個就是Mach-O內容和地址(本人上篇博客地址便可)

Mach-O在內存的偏移地址也就是Mach-O的真實地址,發現爲 0x000000010a9c5000

經過上面紅色加劇算法,計算Mach-O文件Data段的函數指針

發現執行完只有就會被綁定。NSLog函數文件就會被綁定。

下面再看一下,對於屏幕點擊的,hook以下

前提是咱們去除ViewDidLoad方法裏面的NSLog(@「123」)這句代碼,運行代碼,最後將斷點斷在touchesBegan裏面,此時開始看地址和內容

截圖的前兩次打印是程序運行時,可是不曾點擊touchesBegan,後兩次是點擊屏幕時斷點進入到了裏面,再看內容,打印的對象是NSLog仍是myNslog,經過上面發現是myNslog,說明Hook成功。

經過上面可看出,fishhook可以Hook c函數,是由於Mach-O文件特色,PIC位置代碼獨立造就了靜態語言C也有動態的部分,以後經過Dyld進行動態綁定的時機,在這其中咱們就能夠作手腳,替換自定義的方法。

fishhook是根據方法字符串的名字「NSLog」,它是怎麼找到的呢?下面將講解利用符號表查看函數名稱字符串。

 

4、符號表查看函數名稱

 再次查看Mach-O文件,查看懶加載表中的NSLog函數

懶加載表是和動態符號表是一一對應關係,經過上面發現NSLog函數時第一個,而對應的Dynamic Symbol table也是第一個,打開Dynamic Symbol table

查看Dynamic Symbol Table 第一個也是NSLog,查看Data值爲7A,對應的十進制爲122,而後到Symbols Table裏面查看122,以下:

 

查看Symbols Table的data值爲0000009B,而後在String Table Index去看函數偏移值爲0000009B的內容,以下:

 

 爲何選擇00004F94查看NSLog呢,咱們從上面得知Symbols Table的data值爲0000009B,而後加上String Table的函數第一個地址爲00004F04,而後將0000009B + 00004F04 = 0X4F9F,最後看00004F94裏面包含了0X4F9F,藍色內容看出是NSLog內容,也就是找到啦。完美!!!

以上過程能夠在fishhook中github上有說明圖:

 

上面的說明圖也就是經過符號表查看函數名稱以及反過來也能夠逆查的過程。配上說明圖,方便你們熟悉流程。

 

5、總結

上面講述了Hook的幾種技術方式以及fishhook的原理探究,以及如何讓別人的app實現本身的代碼。下面咱們對此總結一下,寫了一個本篇博客的整個過程便於你們整理,但願對你們有所幫助加深理解。

相關文章
相關標籤/搜索