經過兩個星期的折騰,SSDT HOOK終於成功了,在這裡首先感謝論壇裡的一位大神,真的是非常感謝,他的ID是什麼記不得了,加了他的好友,記得他的名字下面寫著列寧兩個字,呵呵很有趣的名字啊,想加的人可以看一看我發的文章。
這裡閑扯淡兩句,論壇裡的大神層級的人物還是不少的,我們不能用等級來衡量一個人的知識水平,就像那天看到一個急聘c++進階程式員的文章,兩星級以上的使用者優先錄取,我覺著吧,這是不明智的舉動,我認識的那位核心大神就是五褲衩的褲衩級使用者。有人說的對,褲衩級的大神多得是,星級的菜鳥也到處都是。
作為一位大神,其實你一個你認為很不經意的舉動,你認為很簡單的一個回答說不定就能協助一個菜鳥少走一大段路程,所以當一個菜鳥勞煩你一些事情的時候如果你能夠稍稍再多付出一點,收到的不僅僅是感謝,還會有一種協助的快感。
閑話就不扯了,本菜鳥要發表言論了。
經過第一個核心程式的編寫,我明顯的覺得自己在一步一步的成熟,我第一次寫的是HOOK分發函數截獲鍵盤記錄,如果有興趣的朋友看我另一篇部落格,現在我寫的是掛鈎SSDT表在R0層HOOK API函數。
在我寫驅動HOOK之前,我是由看黒防的雜誌得到的想法,我也想自己動手試試SSDT HOOK,菜鳥麼,重在動手練習。我查閱資料,翻看書籍,自己寫或者是借鑒別人成功的代碼,寫了一些SSDT HOOK的代碼,但是編譯神馬的都通過了,就是一旦運行不是藍屏就是死機,於是反覆查資料改代碼,最終還是沒能通過,於是我就去論壇發帖,一個文章掛在論壇上一個星期沒有人回帖,我也只好鬱悶的結了,正好有些錯誤經過改動和原始碼也不一樣,就又重寫了一下發了新帖,果然當天晚上就遇到那個“列寧”的大神,他仔細的看了,真仔細的看了,給My Code提出了五點錯誤。我仔細看了一下,發現了一個嚴重的邏輯錯誤,難怪藍屏,呵呵,還是不仔細啊,除此之外“列寧”作為一個經驗豐富的核心程式設計者指出了一些由於經驗不足導致的小錯誤,使我受益匪淺。在此再次感謝。
以下是我修改後的HOOK的代碼,和上次一樣,為了方便,我任然沒有寫卸載函數,我是用的是暴力修改CR0寄存器的方法,所以穩定性有待考證,經過我的測試還是會有藍屏的情況出現,不過作為菜鳥寫的代碼,確實也實現了這段代碼應該有的功能,在此,我就貼出來讓大家瞧瞧,不要笑話啊,畢竟是菜鳥,呵呵。
#include <ntddk.h> </p><p>typedef struct _ServiceDescriptorEnty //定義結構<br />{<br /> unsigned int *ServiceTableBase;<br /> unsigned int *ServiceCounterTableBase;<br /> unsigned int NumberOfServices;<br /> unsigned char *ParamTableBase;<br />}ServiceDescriptorTableEntry, *PServiceDescriptorTableEntry; </p><p>typedef NTSTATUS (__stdcall *NTOPENPROCESS)(OUT PHANDLE ProcessHandle,IN ACCESS_MASK AccessMask,IN POBJECT_ATTRIBUTES ObjectAttributes,IN PCLIENT_ID ClientId); //定義函數</p><p>NTOPENPROCESS RealNtOpenProcess; </p><p>extern PServiceDescriptorTableEntry KeServiceDescriptorTable; </p><p>NTSTATUS MyNtOpenProcess(PHANDLE ProcessHandle,ACCESS_MASK DesiredAccess,POBJECT_ATTRIBUTES ObjectAttributes,PCLIENT_ID ClientId);</p><p>VOID DriverUnload(PDRIVER_OBJECT DriverObject) //卸載函數<br />{<br /> DbgPrint("succeed!");<br />}</p><p>NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)<br />{<br /> ULONG Address;<br /> ULONG_PTR RealOPServiceAddress;<br /> _asm //取消ssdt的保護<br /> {<br /> cli<br /> mov eax,cr0<br /> and eax,not 10000h<br /> mov cr0,eax<br /> }<br /> Address=(ULONG)KeServiceDescriptorTable->ServiceTableBase+0x7A*4;//得到真真實位址<br /> *((ULONG*)Address)=(ULONG)MyNtOpenProcess;//替換為自己回呼函數的地址<br /> RealOPServiceAddress = *(ULONG*)Address; //儲存真是地址<br /> RealNtOpenProcess = (NTOPENPROCESS)RealOPServiceAddress;//根據論壇上一位大神的的說法,兩次寄存器的操作之間的代碼要盡量少,因為調用的函數也有可能使用寄存器,改變寄存器的值</p><p> _asm //關閉保護<br /> {<br /> cli<br /> mov eax,cr0<br /> or eax,10000h<br /> mov cr0,eax<br /> sti<br /> } </p><p> DriverObject->DriverUnload=DriverUnload;<br /> return STATUS_SUCCESS;<br />} </p><p>NTSTATUS MyNtOpenProcess(PHANDLE ProcessHandle,ACCESS_MASK DesiredAccess,POBJECT_ATTRIBUTES ObjectAttributes,PCLIENT_ID ClientId)<br />{<br /> NTSTATUS rc=NULL;<br /> ULONG dwPID;<br /> //rc=(NTSTATUS)(REALZWOPENPROCESS)RealZwOpenProcess(ProcessHandle,DesiredAccess,ObjectAttributes,ClientId);<br /> if(ClientId!=NULL) //判讀是否是制定的PID<br /> {<br /> dwPID=(ULONG)ClientId->UniqueProcess;<br /> if(dwPID==1884)<br /> {<br /> DbgPrint("PID 1884 has been accessed,need forbidden");<br /> ProcessHandle=0;<br /> rc=STATUS_ACCESS_DENIED; //返回失敗控制代碼<br /> }<br /> }<br /> else<br /> rc=(NTSTATUS)(NTOPENPROCESS)RealNtOpenProcess(ProcessHandle,DesiredAccess,ObjectAttributes,ClientId );//如果不是則調用原來的NtOpenProcess地址<br /> return rc;<br />}<br />