***********關於hook**********************************
首先我們說下hook,什么是hook?hook的英文已經說明了,hook在英文中是鈎的意思,計算機取其意叫鈎子,而我的理解叫截!
大家應該寫過r3下程序,估計也寫過一些r3的hook,例如有一個API是OpenProcess,功能是打開進程得到進程句柄,比如我們要結束一個進程,如果調用TerminateProcess這個API來結束進程,就必須知道進程句柄。
那么結束一個進程的偽代碼就是這樣
push PID
push 0
push 2035711 //權限
call OpenProcess
push 0
push eax
call TerminateProcess
這段代碼執行,如果正常的話,這個PID的進程應該就會被結束了,這里我們來設想一下,假設我們這里call openprocess做一下修改,變成這樣,
push PID
push 0
push 2035711 //權限
call myopen
push 0
push eax
call TerminateProcess
myopen這里是我自己寫的一個函數,這個函數跟OpenProcess一樣,也有三個參數,也有相同的返回值類型。在這個函數里,我把三個參數,傳遞給真正的OpenProcess,而把OpenProcess的返回值,做為myopen的返回值,那么,這套流程下來,肯定也是可以執行的,myopen函數類似這樣:
有童鞋要問了,這樣做執行是可以執行,但是何必費力做一個包裝函數,再調用原函數,這樣的意義是什么?
現在這套流程下來非常正常,我們做的這個包裝函數沒有意義,現在我們假設,如果有一個惡意進程PID=9527,你寫這個結束程序來結束這個PID=9527的進程,這個惡意進程卻給你安裝了這個包裝函數。但是,他稍微的修改了下,變成這樣:
嘿嘿,這樣下來,會怎么樣?你還能結束惡意進程嗎?
當然不能
因為你如果打開PID為9527的進程時候,得不到正確的句柄返回值,返回值為0。
這個方法,叫hook,我們也可以在OpenProcess的函數頭進行hook。
而我把這種方法,叫截,截獲后,可阻止,可改變,可放行!hook,無非是截獲流程,根據自己的需要替換,阻止,放行而已!
r3層的r0層的hook原理一樣,大道至簡,現在很多驅動hook一上來就說內核,ssdt,弄的大家一頭霧水,其實假傳萬卷書,真傳一句話,驅動hook就是截獲api在內核的執行流程,然后根據自己的需要替換,阻止,放行。 理論上你會r3的hook,你一定會r0的hook!
*********關於SSDT**********************************
明白了HOOK原理后,那么內核hook就很簡單了,只要我們在API函數執行流程走到內核后在內核流程中進行截斷,處理,就是內核hook了
我們在內核流程的位置選擇了SSDT表,那么,SSDT表是什么?
SSDT(System Services Descriptor Table),系統服務描述符表。這個表就是一個把ring3的Win32 API和ring0的內核API聯系起來。SSDT並不僅僅只包含一個龐大的地址索引表,它還包含着一些其它有用的信息,諸如地址索引的基地址、服務函數個數等。
現在我們以OpenProcess來說明,看下SSDT表在函數執行流程中起的作用!
函數的執行流程以OpenProcess是這樣.先說明,下面再解釋
*r3 OpenProcess進入ntdll.dll的NtOpenProcess或ZwOpenProcess函數(反正是同一個地址)
*進入內核
*進入Ntoskrnl.exe的ZwOpenProcess
*根據ZwOpenProcess的索引,找到SSDT表對應的地址,再根據SSDT表對應地址的數據(Ntoskrnl.exe的NtOpenProcess),執行函數。
*也就是Ntoskrnl.exe的NtOpenProcess才是真正的執行主體
根據上面OpenProcess的流程說明,進入內核后,OpenProcess是進入了Ntoskrnl.exe的ZwOpenProcess這個函數,根據這個函數的索引,在SSDT表查找到真正的內核執行體Ntoskrnl.exe的NtOpenProcess函數,然后執行。
首先,我們先找到SSDT表,下面我們來看一個被內核導出的結構KeServiceDescriptorTable.
struct KeServiceDescriptorTable
SSDT表的指針 //這個指向系統服務函數地址表
ServiceCounterTableBase;
NumberOfService; //服務函數的個數
TableBase
end KeServiceDescriptorTable
這里第一個字段就是SSDT表的指針,我們用windbg看一下,先dd KeServiceDescriptorTable
第一個字段是80502b8c,這個就是SSDT表的地址了
我們dd 80502b8c看看SSDT表
里面存放的都是一些NT函數地址。
之前說了Ntoskrnl.exe的ZwOpenProcess函數有個索引,根據索引在SSDT表里查找真正的內核執行體函數Ntoskrnl.exe的NtOpenProcess函數
我們看看ZwOpenProcess,用windbg查看,u nt!ZwOpenProcess
索引號是7Ah
那么Ntoskrnl.exe的NtOpenProcess函數應該存放的位置就是=80502b8ch(SSDT表的開始地址)+7Ah(索引)*4(每個函數的間隔),得到80502D74h
80502D74h處存放的地址是805C2296,這個應該是Ntoskrnl.exe的NtOpenProcess函數的地址,我們看下是不是
果然是的.
所以函數在由R3進R0后,要通過SSDT表的來選擇最終執行的內核函數,假設我們想在內核中HOOKOpenProcess這個函數,只需要修改80502d74處存放的地址,放入我們自己寫的newNtOpenProcess函數地址,在我們newNtOpenProcess函數中,進行了修改或替換或阻止或放行后執行真正的NtOpenProcess,這就是所謂的SSDThook
那么,我簡單說下ssdt表中 hook OpenProcess這個函數步驟
1.先得到Ntoskrnl.exe的NtOpenProcess函數的地址(用MmGetSystemRoutineAddress函數得到內核導出函數地址)
2.再得到SSDT表中Ntoskrnl.exe的NtOpenProcess函數應該存放的位置
(SSDT表的開始地址)+(索引)*4(每個函數的間隔)
SSDT表的開始地址=[KeServiceDescriptorTable->SSDT表的指針]
索引=[Ntoskrnl.exe的zwOpenProcess地址+1]
3.自己建立一個新函數,參數和返回值要和Ntoskrnl.exe的NtOpenProcess函數一模一樣
4.把自己的新函數地址寫到SSDT表中我們算出來的存放位置處,(mov [(SSDT表的開始地址)+(索引)*4(每個函數的間隔)],新函數地址)
下面是部分重要代碼:
執行效果如圖: