鉤子:(Hook)是Windows中提供的一種用以替換DOS下“中斷”的系統(tǒng)機(jī)制,中文譯為“掛鉤”或“鉤子”。鉤子在軟件中的應(yīng)用可以說(shuō)是很廣泛了,想當(dāng)年學(xué)習(xí)鉤子那會(huì)兒,什么IAT鉤子,INLINE鉤子......真是有點(diǎn)老??心瞎?.....
看多了網(wǎng)上的其他一些關(guān)于此話題的文章,感覺(jué)對(duì)于剛接觸的人不適用,所以今天把經(jīng)驗(yàn)與大家分享(高手就不用看了......呵呵.)
WINDOWS
HOOK有什么用呢?說(shuō)的明白點(diǎn)就是給特定的某一個(gè)事件,說(shuō)的具體點(diǎn)是給一個(gè)函數(shù)掛上一個(gè)鉤子(我們自己的函數(shù)),讓它在執(zhí)行前先執(zhí)行我們掛的鉤子(我們掛接的函數(shù)),從而達(dá)到攔截事件和函數(shù)調(diào)用等的目的.
IAT鉤子:IAT(Import
Address
Table)意思是導(dǎo)入地址表,有的朋友看不懂了,!什么是導(dǎo)入地址表.你可以去下載一個(gè)exescope,然后用它打開(kāi)一個(gè)EXE文件看看導(dǎo)入欄,一個(gè)程序在執(zhí)行時(shí),它所(靜態(tài)調(diào)用,即不用loadlibrary法)調(diào)用的函數(shù),在它被編譯成為一個(gè)可執(zhí)行文件時(shí),這些模塊的函數(shù)的地址就會(huì)被寫入導(dǎo)入表,IAT鉤子即是替換IAT表中的這些地址為自己的函數(shù)地址,那么當(dāng)程序調(diào)用到這個(gè)地址的時(shí)候就會(huì)跳到我們的函數(shù)里面來(lái),在這里替換并不是說(shuō)我們要去替換文件中的IAT表,而是要去替換內(nèi)存中的IAT表,一個(gè)可執(zhí)行文件運(yùn)行之后,它的程序主體會(huì)做為一個(gè)模塊被加載到內(nèi)存里,在需要調(diào)用函數(shù)的時(shí)候它會(huì)去IAT表中查詢所調(diào)用的函數(shù)地址,我們只需修改內(nèi)存中IAT表地址即可,具體修改方法很簡(jiǎn)單,這里不作介紹,那么怎么樣去修改呢,換句話說(shuō),我們?cè)趺粗朗裁磿r(shí)候去修改?這個(gè)時(shí)候就需要用到一個(gè)windows系統(tǒng)函數(shù)SetWindowsHookEx(方法當(dāng)然不只這一種,比如用遠(yuǎn)程注入也可以,有興趣可以去網(wǎng)上查詢),這個(gè)函數(shù)會(huì)在運(yùn)行時(shí)負(fù)責(zé)把我們的DLL文件帶到與我們所注冊(cè)的鉤子有關(guān)的所有程序中(注意進(jìn)程的用戶權(quán)限),這就是為什么用戶態(tài)的全局鉤要做成DLL(動(dòng)態(tài)鏈接庫(kù)的原因).
比如,我們用SetWindowsHookEx注冊(cè)一個(gè)鼠標(biāo)鉤子,并用一個(gè)A.DLL的模塊與之掛鉤,那么在WINDOWS系統(tǒng)中響應(yīng)鼠標(biāo)事件的所有程序會(huì)先加載A.DLL,在加載DLL初始化時(shí)(執(zhí)行DLLMAIN函數(shù))我們就可以先在內(nèi)存中找出IAT中的函數(shù)地址,再用WriteProcessMemory或memcpy修改為A.DLL模塊內(nèi)的某個(gè)函數(shù)(我們掛鉤的函數(shù)),那么這個(gè)程序在響應(yīng)鼠標(biāo)事件時(shí)會(huì)先執(zhí)行我們掛好的那個(gè)在A.DLL的某個(gè)函數(shù),這個(gè)時(shí)候大權(quán)就在我們手里了,我們可以讓它繼續(xù)執(zhí)行,也可以讓它立即返回?zé)o效.同理我們可以掛鉤所有響應(yīng)鍵盤事件的程序加載我們的模塊以達(dá)到監(jiān)視鍵盤記錄的作用,也可以掛鉤所有響應(yīng)消息的程序來(lái)掛鉤NtopenProcess和NtTerminateProcess來(lái)防止我們的程序被其他程序結(jié)束.也可以掛鉤諸多的API函數(shù)來(lái)監(jiān)視系統(tǒng)API的調(diào)用,不過(guò)在這里有個(gè)誤區(qū),SetWindowsHookEx只會(huì)負(fù)責(zé)把你的DLL加載到其他的執(zhí)行程序(不會(huì)執(zhí)行),所以我們的替換動(dòng)作必須在DLLMAIN函數(shù)中(或調(diào)用)完成.還有一點(diǎn)要注意IAT
HOOK修改的只是IAT表而已,并不是函數(shù)本身,而下面這中方法就是直接修改函數(shù)本身實(shí)現(xiàn)HOOK,同理,都可以用SetWindowsHookEx注冊(cè)一個(gè)鉤子把我們的鉤子模塊帶到其他進(jìn)程。那么它是怎么實(shí)現(xiàn)HOOK的呢?我們需要準(zhǔn)備一個(gè)5個(gè)字節(jié)的BYTE(或char)變量,然后把它的第一個(gè)字節(jié)設(shè)為0xE9(16進(jìn)制),然后把(我們的函數(shù)地址-原函數(shù)地址-5)(long類型)寫入從第2個(gè)字節(jié)開(kāi)始后的4個(gè)字節(jié),我們都知道LONG類型所占的空間剛好為4個(gè)字節(jié)(在這眾多類型里面,不管它的類型怎么變,它都有以字節(jié)為單位的大小,在我看來(lái),把一個(gè)變量叫做int
也好 long 也好,純粹是為了編寫程序方便和好記,因?yàn)槲覀兺耆梢园裪nt x 定義為 BYTE
x[2]),再把這5個(gè)字節(jié)復(fù)制到內(nèi)存中以原函數(shù)(要掛鉤的那個(gè)函數(shù))地址為起始點(diǎn)的5個(gè)字節(jié),這么做的意義是什么呢?可能有的人不知道0xE9
相當(dāng)于匯編里的Jmp指令,(當(dāng)然有點(diǎn)反匯編基礎(chǔ)的人都知道如0xC3 = ret,
0xE9=Jmp,、、很多)在匯編里jmp是一個(gè)跳轉(zhuǎn)指令,在這里就是讓它跳轉(zhuǎn)至后面的4個(gè)字節(jié)指示的位置(我們的函數(shù)地址),從而達(dá)到HOOK的目的,這就是為什么叫INLINE
HOOK為5字節(jié)跳轉(zhuǎn)法,同樣的這種方法不僅僅適用于用戶態(tài),它還適用于核心態(tài),這就是SDT INLINE
HOOK。
在系統(tǒng)內(nèi)核有一個(gè)內(nèi)核文件的加載的鏡像(內(nèi)核模塊),NTOSKRNL或ntkrnlpa及ntkrnlmp、ntkrnlup、ntkrpamp都是OS內(nèi)核文件,它提供了一整套核心態(tài)函數(shù),供用戶態(tài)和核心態(tài)調(diào)用,我們?cè)谟脩魬B(tài)調(diào)用的函數(shù)大多數(shù)在最后都進(jìn)入了核心態(tài)如kernel32.dll的OpenProcess,在調(diào)用OpenProcess,以后會(huì)進(jìn)入Ntdll.dll中的NtOpenProcess然后調(diào)用系統(tǒng)函數(shù)調(diào)用號(hào)進(jìn)入核心態(tài)的NtOpenProcess,所以核心態(tài)的鉤子才是王道,核心態(tài)的鉤子有SSDT
HOOK和SDT INLINE
HOOK,上面說(shuō)了,內(nèi)核導(dǎo)出了一系列的函數(shù)供用戶態(tài)調(diào)用,那么導(dǎo)出的這個(gè)函數(shù)表就是SSDT(系統(tǒng)服務(wù)描述表),它的地址可由內(nèi)核導(dǎo)出的一個(gè)變量
KeServiceDescriptorTable 查詢,每4個(gè)字節(jié)(long 大?。橐粋€(gè)地址,在SSDT
HOOK時(shí)我們只需要修改SSDT表中的地址為我們的地址即可,相當(dāng)簡(jiǎn)單.
例:修改NtOpenProcess:
*(ULONG*)(KeServiceDescriptorTable+(0x7A*4))=(ULONG)MyOpenProcess
0x7A為NtOpenProcess的系統(tǒng)調(diào)用號(hào),每個(gè)調(diào)用號(hào)占4個(gè)字節(jié),KeServiceDescriptorTable+(0x7A*4)就代表了NtOpenProcess地址的存放位置,MyOpenProcess為我們自定義的函數(shù),這樣系統(tǒng)在執(zhí)行NtOpenProcess的時(shí)候就會(huì)跳到MyOpenProcess里。還有一種就是Inline
Hook它和用戶態(tài)的一樣直接修改函數(shù)前5個(gè)字節(jié)即可,這里不再贅述。但是在核心態(tài)的inline
hook比較危險(xiǎn),這涉及到多線程調(diào)用,有興趣的朋友可以去查閱該方面資料。
已經(jīng)講了這幾種HOOK
的實(shí)現(xiàn)原理,那么我們?cè)趺磥?lái)預(yù)防Hook呢。在用戶態(tài)我們可以掛接(inlinehook)LoadLibraryExW來(lái)判斷,這個(gè)資料在網(wǎng)上很多,朋友們可以自己去找,還有一點(diǎn)就是,網(wǎng)上的方法不能防止遠(yuǎn)程注入HOOK,在LoadLibrary的時(shí)候加上判斷TED或PEB就可以防止了。上述原理有不懂的或具體實(shí)現(xiàn)方法可聯(lián)系我。(2008)