六 Hock原理分析

nx_001.jpeg

上篇文章MachO文件解析已經詳細介紹了MachO嫉到,并且由MachO引出了dyld沃暗,再由dyld講述了App的啟動流程,而在App的啟動流程中又說到了一些關鍵的名稱如:LC_LOAD_DYLINKER何恶、LC_LOAD_DYLIB以及objc的回調函數_dyld_objc_notify_register等等孽锥。

這篇文章我們來了解一下,符號表细层、fishhook相關的內容惜辑。

用到的工具:fishhook

接下來本文會從以下幾點進行闡述:

  • HOOK概述
  • fishHook的簡單使用
  • fishHook原理探究
  • fishHook源碼分析

1.HOOK概述

HOOK,中文譯為“掛鉤”或“鉤子”疫赎。在iOS逆向中是指改變程序運行流程的一種技術盛撑。通過hook可以讓別人的程序執(zhí)行自己所寫的代碼。在逆向中經常使用這種技術虚缎。所以在學習過程中撵彻,我們重點要了解其原理钓株,這樣能夠對惡意代碼進行有效的防護实牡。

1.1 Hook 流程圖

六 Hock流程圖.png

如上圖,這就是我們HOOK代碼大概流程轴合。

1.2 HOOK的方式

1.****Method Swizzld
利用OC的Runtime特性创坞,動態(tài)改變SEL(方法編號)和IMP(方法實現)的對應關系,達到OC方法調用流程改變的目的受葛。主要用于OC方法题涨。

2.fishhook
它是Facebook提供的一個動態(tài)修改鏈接mach-O文件的工具。利用MachO文件加載原理总滩,通過修改懶加載和非懶加載兩個表的指針達到C函數HOOK的目的纲堵。

3.Cydia Substrate
Cydia Substrate 原名為 Mobile Substrate ,它的主要作用是針對OC方法闰渔、C函數以及函數地址進行HOOK操作席函。當然它并不是僅僅針對iOS而設計的,安卓一樣可以用冈涧。
官方地址:http://www.cydiasubstrate.com/

1.3 Cydia Substrate簡介

Cydia Substrate的原名為MobileHooker茂附,顧名思義用于HOOK。它定義一系列的宏和函數督弓,底層調用objcruntimefishhook來替換系統(tǒng)或者目標應用的函數.

其中有兩個函數:
MSHookMessageEx:主要作用于Objective-C方法营曼。

void MSHookMessageEx(Class class, SEL selector, IMP replacement, IMP result) 

MSHookFunction:主要作用于C和C++函數。

void MSHookFunction(voidfunction,void* replacement,void** p_original)  

Logos語法的%hook 就是對此函數做了一層封裝愚隧。

1.4 Cydia Substrate特點

1.MobileLoader:MobileLoader用于加載第三方dylib在運行的應用程序中蒂阱。啟動時MobileLoader會根據規(guī)則把指定目錄的第三方的動態(tài)庫加載進去,第三方的動態(tài)庫也就是我們寫的破解程序.

2.safe mode: 破解程序本質是dylib,寄生在別人進程里录煤。 系統(tǒng)進程一旦出錯虱痕,可能導致整個進程崩潰,崩潰后就會造成iOS癱瘓。所以CydiaSubstrate引入了安全模式,在安全模 式下所有基于CydiaSubstratede 的三方dylib都會被禁用辐赞,便于查錯與修復部翘。

2.fishHook的簡單使用

fishHook代碼地址:fishhook

struct rebinding {
  const char *name;//需要HOOK的函數名稱,C字符串
  void *replacement;//新函數的地址
  void **replaced;//原始函數地址的指針响委!
};

關鍵函數:

FISHHOOK_VISIBILITY
int rebind_symbols(struct rebinding rebindings[], 
                   size_t rebindings_nel);
參數一:存放rebinding結構體的數組(可以同時交換多個函數)
參數二:rebindings數組的長度     

FISHHOOK_VISIBILITY
int rebind_symbols_image(void *header,
                         intptr_t slide,
                         struct rebinding rebindings[],
                         size_t rebindings_nel);

hook系統(tǒng)的NSLog函數fishhook簡單使用代碼
運行代碼新思,點擊屏幕,會發(fā)現我們的代碼執(zhí)行了赘风,

hook C 函數fishhook 系統(tǒng)C函數
運行代碼夹囚,我們會發(fā)現,我們的hook方法失效了邀窃,這是為什么么呢荸哟?下面我們來一起探究下吧。瞬捕。鞍历。。

3.fishHook原理探究

在上篇文章已經提到了在dyld啟動app的第二個步驟就是加載共享緩存庫肪虎,共享緩存庫包括Foundation框架劣砍,NSLog是被包含在Foundation框架的。有了這個貢獻緩存庫扇救,就可以解決多個app共同調用一個庫等問題了刑枝。

六 Hock流程圖.png

3.1 fishHook 加載流程

首先,我們想一下OC為什么可以hook呢迅腔?C為什么不能hook装畅?

OC為什么可以hook? 因為OC底層使用的Runtime技術沧烈,通過運行時去找到方法的實現掠兄,所以OC可以hook。

C為什么不能hook掺出?
C語言函數通常是靜態(tài)的匿级,編譯之后锅尘,從匯編代碼變成了內存地址。它都是通過內存地址去找的,在編譯的時候就綁定了的铭段,所以hook不了筛欢。

那么問題來了闯冷,為什么問題來了,為什么fishhook可以hook到C方法呢铐维?
原因是:iOS系統(tǒng)實現了一個動態(tài)緩存庫技術,一些公共的系統(tǒng)庫放進內存中的某個地方慎菲,當某個iOS項目啟動后嫁蛇,machO文件會在Data段創(chuàng)建一個指針,dyld動態(tài)將machO中Data段中這個指針指向外部函數露该,這里的指針指向內部函數的調用睬棚,指向外部函數的地址,而這個指針也就是我們通常說的符號解幼;這也是為什么fishhook中函數名為rebind_symbols(重新綁定符號)抑党,實際上是修改這個指針指向外部函數的地址,這也就是為什么修改不了內部函數和自定義函數撵摆,只能修改machO外部函數(在符號表中能找到的函數)底靠。由于蘋果實現了ASLR技術(不了解ASLR,看這篇逆向學習筆記8——ASLR),所以這些動態(tài)緩存庫函數在APP項目的內存地址不確定特铝,每次啟動APP的時候都會有相應的變化暑中,這是C語言的動態(tài)表現。

通過MacOView分析鲫剿,我們知道了iOS應用啟動時的啟動流程:

  1. 啟動APP會執(zhí)行dyld鳄逾,加載程序
  2. 進入dyld:main函數
  3. 配置一些環(huán)境
  4. 加載共享緩存庫
  5. 實例化主程序
  6. 加載動態(tài)庫
  7. 鏈接主程序

通過以上分析,我們可以利用dyld加載的時候對C函數進行修改牵素。

簡單總結下就是:

  • 在MachO文件中有個PIC(貢獻緩存庫)严衬,它在Data段創(chuàng)建了一個指針,這個指針指向外部函數笆呆。
  • 當我們調用C方法、函數的時候粱挡,這個指針就會起加載(綁定)這個外部的C函數赠幕。
  • 而我們的fishhook正是利用了這一步驟進行hook的。

注意:
fishhook 修改的是內存的地址

下面询筏,我們使用MachOView來看一下吧
這里我們代碼寫的少榕堰,所以就直接用 2fishhook hook系統(tǒng)C函數這個案例來講解了。

首先嫌套,我們來看看NSLog的地址在什么時候被加載的逆屡,也就是NSLog到底在哪里。

1.使用MachOView查看踱讨,并使用驗證

// 在viewDidLoad中添加以下兩句代碼魏蔗,斷點斷到第一句代碼
- (void)viewDidLoad {
    [super viewDidLoad];
    NSLog(@"測試1");
    NSLog(@"測試1");
}

1.在第一個NSLog使用斷點斷住,在Project中痹筛,得到當前APP的 MachO文件莺治。使用MachOView進行分析廓鞠。我們可以找到如下內容。

六 加載流程1.png

懶加載表 非懶加載表

2.獲得當前NSLog的偏移量谣旁。

3.在LLDB中使用 image list列出當前加載的鏡像床佳。第一個地址為當前MachO文件在內存中的首地址

4.通過首地址加上當前的偏移量,我們可以獲得如下NSLog在內存中的位置榄审。


六 NSLog共享緩存1.png

5.由于iOS是小端模式砌们,我們的地址從右往左讀,如上圖第二個lldb的內容搁进,最后我們會看到libdyld.dylib`dyld_stub_binder:怨绣。上圖中有體現。

6.我們的斷點在往下走一步拷获,會發(fā)現我們獲取MachO文件的首地址內存發(fā)生了變化篮撑。上圖中有體現。

7.這時我們查看一下當前的地址匆瓜,看看有什么赢笨?
六 NSLog共享緩存2.png

,如圖驮吱,我們的NSLog被打印出來了茧妒。

到這里,說明了我們的NSLog在我們的系統(tǒng)共享緩存區(qū)里左冬,第一次沒使用的時候需要綁定桐筏,第二次直接去找地址,不用綁定拇砰。

2.使用匯編的方式查看
1.同上面的第1梅忌,2,3步除破,通過Debug -> Debug WorkFlow -> Always Show Disassembly 調試牧氮,如下圖:

六 匯編分析NSLog.png

我們同樣可以得到 libdyld.dylib`dyld_stub_binder:函數

4.fishHook源碼分析

4.1、fishhook的總體思路

Facebook的開源庫fishhook就可以完美的實現這個任務瑰枫。
先上一張官網原理圖:

fishhook流程.png

總體來說踱葛,步驟是這樣的:

  1. 先找到四張表Lazy Symbol Pointer Table、Indirect Symbol Table光坝、Symbol Table尸诽、String Table。
  2. MachO有個規(guī)律:Lazy Symbol Pointer Table中第index行代表的函數和Indirect Symbol Table中第index行代表的函數是一樣的盯另。
  3. Indirect Symbol Table中value值表示Symbol Table的index性含。
  4. 找到Symbol Table的中對應index的對象,其data代表String Table的偏移值土铺。
  5. 用String Table的基值胶滋,也就是第一行的pFile值板鬓,加上Symbol Table的中取到的偏移值,就能得到Indirect Symbol Table中value(這個value代表函數的偏移值)代表的函數名了究恤。

4.2俭令、源碼分析

fishhook的源碼總共只有250行左右,所以結合MachO慢慢看部宿,其實一點也不費勁抄腔,接下來,我們簡單的分析一下吧理张。

1.fishhook為維護一個鏈表赫蛇,用來儲存需要hook的所有函數。

// 給需要rebinding的方法結構體開辟出對應的空間
// 生成對應的鏈表結構(rebindings_entry)雾叭,并將新的entry插入頭部
static int prepend_rebindings(struct rebindings_entry **rebindings_head,
                              struct rebinding rebindings[],
                              size_t nel)

2.根據linkedit的基值悟耘,找到對應的三張表:symbol_table、string_table和indirect_symtab织狐。

// 找到linkedit的頭地址
// linkedit_base其實就是MachO的頭地址T萦住!移迫!可以通過查看linkedit_base值和image list命令查看驗證M摇!3瘛(文末附有驗證圖)
/**********************************************************
 Linkedit虛擬地址 = PAGEZERO(64位下1G) + FileOffset
 MachO地址 = PAGEZERO + ASLR
 上面兩個公式是已知的 得到下面這個公式
 MachO文件地址 = Linkedit虛擬地址 - FileOffset + ASLR(slide)
**********************************************************/
uintptr_t linkedit_base = (uintptr_t)slide + linkedit_segment->vmaddr - linkedit_segment->fileoff;
// 獲取symbol_table的真實地址
nlist_t *symtab = (nlist_t *)(linkedit_base + symtab_cmd->symoff);
// 獲取string_table的真實地址
char *strtab = (char *)(linkedit_base + symtab_cmd->stroff);
// Get indirect symbol table (array of uint32_t indices into symbol table)
// 獲取indirect_symtab的真實地址
uint32_t *indirect_symtab = (uint32_t *)(linkedit_base + dysymtab_cmd->indirectsymoff);

3.最核心的一個步驟邪媳,查找并且替換目標函數。

// 在四張表(section,symtab,strtab,indirect_symtab)中循環(huán)查找
// 直到找到對應的rebindings->name,將原先的函數復制給新的地址荡陷,將新的函數地址賦值給原先的函數
static void perform_rebinding_with_section(struct rebindings_entry *rebindings,
                                           section_t *section,
                                           intptr_t slide,
                                           nlist_t *symtab,
                                           char *strtab,
                                           uint32_t *indirect_symtab)

在了解了fishhook的簡單使用之后雨效,我們就可以做一些基本的防護的內容了,參見代碼

關于幾個名詞的解釋亲善。

幾個名詞(pFile 设易、offset 、File Offset)的解釋

  1. 首先蛹头,這三個都是表示相對于MachO的內存偏移,只不過其含義被細分了戏溺。
  2. pFile 和 offset含義相近渣蜗,不過offset更詳細,能夠對應上具體某一個符號(DATA? TEXT?)旷祸。比如文件里面有許多類耕拷,類里面有許多的屬性,pFile就代表各個類的偏移值托享,offset代表各個屬性的偏移值骚烧。
  3. File Offset 這個存在于Segment的字段中浸赫。用于從Segment快速找到其代表的「表」真正的偏移值。

參考文章:
作者:一縷清風揚萬里
原文地址:http://www.reibang.com/p/95896fb96a03

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末赃绊,一起剝皮案震驚了整個濱河市既峡,隨后出現的幾起案子,更是在濱河造成了極大的恐慌碧查,老刑警劉巖运敢,帶你破解...
    沈念sama閱讀 218,941評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異忠售,居然都是意外死亡传惠,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 93,397評論 3 395
  • 文/潘曉璐 我一進店門稻扬,熙熙樓的掌柜王于貴愁眉苦臉地迎上來卦方,“玉大人,你說我怎么就攤上這事泰佳∨慰常” “怎么了?”我有些...
    開封第一講書人閱讀 165,345評論 0 356
  • 文/不壞的土叔 我叫張陵乐纸,是天一觀的道長衬廷。 經常有香客問我,道長汽绢,這世上最難降的妖魔是什么吗跋? 我笑而不...
    開封第一講書人閱讀 58,851評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮宁昭,結果婚禮上跌宛,老公的妹妹穿的比我還像新娘。我一直安慰自己积仗,他們只是感情好疆拘,可當我...
    茶點故事閱讀 67,868評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著寂曹,像睡著了一般哎迄。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上隆圆,一...
    開封第一講書人閱讀 51,688評論 1 305
  • 那天漱挚,我揣著相機與錄音,去河邊找鬼渺氧。 笑死旨涝,一個胖子當著我的面吹牛,可吹牛的內容都是我干的侣背。 我是一名探鬼主播白华,決...
    沈念sama閱讀 40,414評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼慨默,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了弧腥?” 一聲冷哼從身側響起厦取,我...
    開封第一講書人閱讀 39,319評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎鸟赫,沒想到半個月后蒜胖,有當地人在樹林里發(fā)現了一具尸體,經...
    沈念sama閱讀 45,775評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡抛蚤,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年台谢,在試婚紗的時候發(fā)現自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片岁经。...
    茶點故事閱讀 40,096評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡朋沮,死狀恐怖,靈堂內的尸體忽然破棺而出缀壤,到底是詐尸還是另有隱情樊拓,我是刑警寧澤,帶...
    沈念sama閱讀 35,789評論 5 346
  • 正文 年R本政府宣布塘慕,位于F島的核電站筋夏,受9級特大地震影響,放射性物質發(fā)生泄漏图呢。R本人自食惡果不足惜条篷,卻給世界環(huán)境...
    茶點故事閱讀 41,437評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望蛤织。 院中可真熱鬧赴叹,春花似錦、人聲如沸指蚜。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽摊鸡。三九已至绽媒,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間免猾,已是汗流浹背些椒。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評論 1 271
  • 我被黑心中介騙來泰國打工掸刊, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人赢乓。 一個月前我還...
    沈念sama閱讀 48,308評論 3 372
  • 正文 我出身青樓经宏,卻偏偏與公主長得像,于是被迫代替她去往敵國和親房轿。 傳聞我的和親對象是個殘疾皇子粤攒,可洞房花燭夜當晚...
    茶點故事閱讀 45,037評論 2 355