Inline Hook在之前文章有較多概念性描述,本文則側(cè)重介紹如何去實(shí)現(xiàn)一個(gè)Inline Hook,并且關(guān)注一些實(shí)現(xiàn)過(guò)程中會(huì)遇到的困難與挑戰(zhàn)。
1.1 實(shí)現(xiàn)原理
HOOK是什么,通過(guò)前面幾章的介紹,相信讀者都有個(gè)比較具體的了解。通俗點(diǎn)理解,就是攔截指定函數(shù)或者具體函數(shù)某條匯編指令的功能。注入GOT HOOK之類(lèi)的方法,只能針對(duì)函數(shù)頭進(jìn)行HOOK。如果需要針對(duì)函數(shù)的特定位置進(jìn)行HOOK,那么Inline Hook則可以派上用場(chǎng)。
Inline Hook直接修改要HOOK位置的指令,讓其跳轉(zhuǎn)到樁函數(shù)中。在樁函數(shù)中,會(huì)處理寄存器等信息,并調(diào)用相應(yīng)HOOK點(diǎn)用戶(hù)自定義的樁函數(shù)。在處理完用戶(hù)自定義的樁函數(shù)后,則會(huì)跳轉(zhuǎn)執(zhí)行原指令。
圖1. Inline Hook原理圖
如圖1所示,Inline Hook的核心原理。這里說(shuō)明一下幾個(gè)關(guān)鍵點(diǎn):
(1) 跳轉(zhuǎn)指令的構(gòu)建、從原指令跳轉(zhuǎn)過(guò)去的底層樁函數(shù),涉及系統(tǒng)匯編層,和Inline Hook的平臺(tái)關(guān)系較大,既是ARM和THUMB、X86等均都有所不同;64位和32位也有所不同。本文實(shí)現(xiàn)以32位的ARM為樣例實(shí)現(xiàn)。
(2) 從底層樁函數(shù)跳轉(zhuǎn)回原函數(shù),既原理圖中第3步跳轉(zhuǎn),去執(zhí)行原指令2的時(shí)候,有個(gè)關(guān)鍵的點(diǎn):如果原指令2涉及到PC操作,則需要進(jìn)行指令修復(fù)。比如說(shuō)是ADD R3, PC, R3, 兩處指令的PC完全不一樣,肯定不能直接復(fù)制,需要針對(duì)修復(fù)相應(yīng)PC值。本文為了方便讀者入門(mén),沒(méi)有針對(duì)指令進(jìn)行修復(fù)操作,既是有個(gè)限制:HOOK點(diǎn)位置,原指令2不能有涉及到PC的操作。如果讀者后續(xù)對(duì)指令修復(fù)有興趣,可能自行實(shí)現(xiàn),本文的代碼框架能很好支持這個(gè)擴(kuò)展。
(3) Inline Hook的指令覆蓋順序,原指令2的覆蓋建議留在最后實(shí)現(xiàn)。既是完成了底層樁函數(shù)構(gòu)造、原函數(shù)構(gòu)造后,再一次性填寫(xiě)跳轉(zhuǎn)指令覆蓋原指令2。這樣的好處是防止HOOK一些頻繁執(zhí)行的函數(shù)可能導(dǎo)致的崩潰。在Inline Hook的過(guò)程中走入了HOOK邏輯,而樁函數(shù)或者原函數(shù)可能未構(gòu)造成功導(dǎo)致崩潰。
大概的原理知道后,下面給出一個(gè)實(shí)現(xiàn)的流程圖,如圖2。通過(guò)該流程圖,讀者可以快速了解到Inline Hook的實(shí)現(xiàn)框架流程主要是這么3個(gè):構(gòu)造stub、構(gòu)造原函數(shù)、覆蓋原指令。圖3示意了樣例要HOOK的IBored中的一條函數(shù)指令,對(duì)應(yīng)圖4則示意了Inline Hook實(shí)現(xiàn)之后的底層匯編指令結(jié)構(gòu)。
1.2 實(shí)現(xiàn)流程
圖2. InlineHook實(shí)現(xiàn)流程圖
圖3. HOOK位置的指令
圖4. Inline Hook實(shí)現(xiàn)后的邏輯
1.3 實(shí)現(xiàn)代碼
按照實(shí)現(xiàn)流程圖,這里按照流程講解下4個(gè)流程代碼。
首先是備份hook點(diǎn)的信息,如下代碼所示,主要是原指令的備份
接著是構(gòu)造stub。底層stub采用了匯編編寫(xiě),整片代碼在ihookstub.s中。如下代碼所示,主要是malloc一塊內(nèi)容用于填充shellcode,同時(shí)針對(duì)用戶(hù)自定義的_hookstub_function_addr_s函數(shù)地址進(jìn)行修改填充。備份相應(yīng)代碼地址到INLINE_HOOK_INFO中。(代碼為了粘貼美觀,去掉相應(yīng)注釋?zhuān)趯?shí)際代碼文件里面,會(huì)有相應(yīng)注釋片段。)
然后是構(gòu)建原來(lái)的指令塊,這里也需要malloc一塊空間來(lái)填充指令。前8個(gè)bytes則是原指令直接填充。本文一開(kāi)始提到的指令修復(fù),如果需要?jiǎng)t是在這個(gè)位置進(jìn)行擴(kuò)展。后8個(gè)bytes用于填充跳轉(zhuǎn)指令,跳轉(zhuǎn)地址則是HOOK地址+8。通過(guò)BuildArmJumpCode函數(shù)構(gòu)建簡(jiǎn)單的指令跳轉(zhuǎn)函數(shù),
LDR PC, [PC, #-4]
Addr
該跳轉(zhuǎn)指令范圍是32位,不過(guò)對(duì)于32位系統(tǒng)來(lái)說(shuō),則是全地址跳轉(zhuǎn)。構(gòu)造原指令的同時(shí),將原指令地址,填充到stub中使之可實(shí)現(xiàn)示意圖中的第3步跳轉(zhuǎn)。
最后則是Inline Hook的最后一步,重構(gòu)HOOK位置的指令,直接填充一個(gè)跳轉(zhuǎn)指令。該跳轉(zhuǎn)指令是跳轉(zhuǎn)到BuildStub構(gòu)建的stub中。
1.4 小結(jié)
本文介紹了Inline Hook的原理,并通過(guò)流程圖和代碼直觀地描述和說(shuō)明Inline Hook的執(zhí)行過(guò)程,配合IBored校驗(yàn)代碼的正確性和應(yīng)用場(chǎng)景的舉例。本篇幅重點(diǎn)是讓讀者了解到Inline Hook的思想和原理,針對(duì)THUMB、X86等平臺(tái)上的Inline Hook擴(kuò)展,有興趣的讀者基于本篇幅的了解去實(shí)現(xiàn)相信難度不會(huì)太大。








