名字起得好,Inline hook,乍一聽,似乎很高深。此處的Inline,我以為,意指將匯編代碼直接寫入內(nèi)核API的內(nèi)存區(qū)域。Inline
Hook不像用戶態(tài)Hook或SSDT hook(用C語言就足夠),它需要在程序中嵌入?yún)R編代碼(Inline
Assembly)以操作堆棧和執(zhí)行內(nèi)核API對應(yīng)的部分匯編指令。當然,這些都須以驅(qū)動的形式進行。
所謂API
Hook,就是用自己寫的函數(shù)去替代系統(tǒng)API的“職位”,此后,自己寫的函數(shù)便掌握了以前由被hook的API所“經(jīng)手”的一切“事宜”。
Windows系統(tǒng)分用戶態(tài)和內(nèi)核態(tài),API也就有了用戶級和內(nèi)核級兩大類。想要比較底層、徹底地做點事情,當然要hook內(nèi)核API了(不過hook用
戶態(tài)API也有諸多用途)。
Hook內(nèi)核API比較常見的是SSDT hook,一句話——Windows把需要調(diào)用的內(nèi)核API地址全都存在了一個表中(System Service
Dispatch Table),
要想hook一個內(nèi)核API,比較簡單的辦法就是把該內(nèi)核API在表(SSDT)中保存的地址修改為自己撰寫的函數(shù)地址。這個道理類似于把
"Windows"先生的"內(nèi)核API電話簿"給篡改了,當老先生想要打電話給"被hook的api先生"時,他找到的"電話號碼"其實已被我們篡改,撥
通電話,我們的"函數(shù)小子"開始應(yīng)答,信息過濾自此開始。
非常不幸,ICESword等檢測工具可以輕松判斷SSDT是否被篡改,并且會以適當?shù)姆绞酵ㄖ脩簦ū热鐧z索結(jié)果的字體變紅)。
Inline
Hook要比SSDT Hook來得更徹底一點。如果說SSDT
Hook只是把某位"內(nèi)核API先生"綁架,然后用我們的“自己人”來接管其工作,而ICESword卻可以從其他聯(lián)系途徑找到被綁架的"內(nèi)核API先生
"并“報警”,那么——Inline Hook可以說是給"內(nèi)核API先生"動了手術(shù),讓他成為"我們陣營的一分子"。Inline
Hook通過硬編碼的方式向內(nèi)核API的內(nèi)存空間(通常是開始的一段字節(jié),且一般在第一個call之前,這么做是為了防止堆棧混亂)寫入跳轉(zhuǎn)語句,這樣,
該API只要被調(diào)用,程序就會跳轉(zhuǎn)到我們的函數(shù)中來,我們在自己寫的函數(shù)里需要完成3個任務(wù):
1)重新調(diào)整當前堆棧。程序流程在剛剛跳轉(zhuǎn)的時候,內(nèi)核API并沒有執(zhí)行完,而我們的函數(shù)需要根據(jù)其結(jié)果來進行信息過濾,所以我們需要保證內(nèi)核API能在順利執(zhí)行完畢后返回到我們的函數(shù)中來,這就要求對當前堆棧做一個調(diào)整。
2)
執(zhí)行遺失的指令。我們向內(nèi)核API地址空間些如跳轉(zhuǎn)指令(jmp
xxxxxxxx)時,勢必要覆蓋原先的一些匯編指令,所以我們一定要保證這些被覆蓋的指令能夠順利執(zhí)行(否則,你的及其就要BSOD了,呵呵,Blue
Screen Of
Death)。關(guān)于這部分指令的執(zhí)行,一般是將其放在我們的函數(shù)中,讓我們的函數(shù)“幫助”內(nèi)核API執(zhí)行完被覆蓋的指令,然后再跳回內(nèi)核API中被覆蓋內(nèi)
后后的地址繼續(xù)執(zhí)行剩余內(nèi)容。跳回去的時候,一定要算好是跳回到什么地址,是內(nèi)核API起始地址后的第幾個字節(jié)。
一個朋友曾提出把內(nèi)核API的被覆蓋內(nèi)容還原,然后執(zhí)行之——這種方法,我沒有試驗,但我認為應(yīng)該不會很穩(wěn)定,因為內(nèi)核里常有線程切換,如果你把內(nèi)核API還原,萬一自己函數(shù)的線程被掛起,而又有線程要調(diào)用給API,這就會出現(xiàn)“Hook 遺漏”。
3)信息過濾。這個就不用多說了,內(nèi)核API順利執(zhí)行并返回到我們的函數(shù)中,我們自然要根據(jù)其結(jié)果做一些信息過濾,這部分內(nèi)容因被hook的API以及Hook目的的不同而不同。
Inline hook的工作流程:
1)驗證內(nèi)核API的版本(特征碼匹配)。
2)撰寫自己的函數(shù),要完成以上三項任務(wù)。
2)獲取自己函數(shù)的地址,覆蓋內(nèi)核API內(nèi)存,供跳轉(zhuǎn)。
Inline Hook的缺點:
1) 不夠通用。各個windows版本中,內(nèi)核API的開始一段不盡相同,要想通吃,就要多寫幾個版本或者做一個特征碼搜索(因為有的內(nèi)核API在各個版本中非常相似,只是在“特征碼”之前或之后加一點東西)。
2) 已被一些檢測工具列入檢測范圍,如果直接從內(nèi)核API第一個字節(jié)開始覆蓋,那么很容易被檢測,如果把覆蓋范圍往后推,并加以變形,也許能抵擋一氣。具體情況,我才疏學(xué)淺,尚未試驗。
上文權(quán)且當作是以下兩文的讀書筆記:
1) kernel inline hook 繞過vice檢測——xfocus上的文章
2) 實現(xiàn)kernel-mode inline function hook的簡單方法(http://www.phpfav.com/?p=35)——5eCur!ty上的文章
大家可以去參看原文,文章1中的代碼可以用文章2的方法優(yōu)化一下。