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








