ssdt_hook NtOpenProcess

 
 
獲取ssdt表中全部函數的地址
for (int i = 0; i < KeServiceDescriptorTable->NumberOfServices; i++)
{
    KdPrint(("NumberOfService[%d]-------%X\n", i, KeServiceDescriptorTable->ServiceTableBase[i]));
}
 
須要這樣定義
typedef struct _ServiceDescriptorTable {
unsigned int* ServiceTableBase; //System Service Dispatch Table 的基地址  
unsigned int* ServiceCounterTable;
//包含着 SSDT 中每一個服務被調用次數的計數器。這個計數器通常由sysenter 更新。 
unsigned int NumberOfServices;//由 ServiceTableBase 描述的服務的數目。  
unsigned char* ParamTableBase; //包含每一個系統服務參數字節數表的基地址-系統服務參數表 
}*PServiceDescriptorTable;  
 
extern "C" extern PServiceDescriptorTable KeServiceDescriptorTable;
 
流程:
一、在ssdt_hook()函數中保存要hook函數的(NtOpenProcess)地址
二、將原來ssdt中所要hook的函數地址換成咱們本身的函數地址
三、在UnHookSsdt中恢復ssdt中原來的函數地址
 
當驅動加載成功後,首先執行DriverEntry裏面的ssdt_hook()函數,此時咱們用CE打開咱們保護的進程,
就會執行到我本身定義的函數MyNtOpenProcess()
最後卸載驅動,執行Driver_Unload()裏面的UnHookSsdt()函數
 
 
做用:
防止被其餘進程用OpenProcess打開,例如Cheat Engine
 
注意:
修改地址的時候,都應該先去掉頁面保護,再恢復頁面保護
使用了PsLookupProcessByProcessId後,必須用ObDereferenceObject回收!
PsLookupProcessByProcessId獲取指定進程的EPROCESS結構,目的就是獲取進程名
 
總結:
ssdt_hook的代碼都是這樣,
ssdt_hook()函數裏面先保存要hook的地址,接着修改成本身定義函數的地址,
UnSsdt_hook()函數裏面就是還原地址
並且本身定義函數裏面要還原以前那個函數
 
VOID UnHookSsdt()
{
PageProtectOff();
KeServiceDescriptorTable->ServiceTableBase[122] = O_NtOpenProcess; //恢復ssdt中原來的函數地址
PageProtectOn();
}
 
NTSTATUS HookSsdt()
{
// 一、在ssdt_hook()函數中保存要hook函數的(NtOpenProcess)地址
O_NtOpenProcess = KeServiceDescriptorTable->ServiceTableBase[122];
PageProtectOff();
// 二、將原來ssdt中所要hook的函數地址換成咱們本身的函數地址
KeServiceDescriptorTable->ServiceTableBase[122] = (unsigned int)MyNtOpenProcess;
//  此時咱們用CE打開被保護的進程,就會調用咱們本身的函數
PageProtectOn();
 
return STATUS_SUCCESS;
}
 
效果:
 
cpp代碼:
  1 #ifdef __cplusplus
  2 extern "C"
  3 {
  4 #endif
  5 #include <ntddk.h>
  6 #ifdef __cplusplus
  7 }
  8 #endif
  9 
 10 typedef struct _ServiceDescriptorTable {
 11     unsigned int* ServiceTableBase; //System Service Dispatch Table 的基地址  
 12     unsigned int* ServiceCounterTable;
 13     //包含着 SSDT 中每一個服務被調用次數的計數器。這個計數器通常由sysenter 更新。 
 14     unsigned int NumberOfServices;//由 ServiceTableBase 描述的服務的數目。  
 15     unsigned char* ParamTableBase; //包含每一個系統服務參數字節數表的基地址-系統服務參數表 
 16 }*PServiceDescriptorTable;  
 17 
 18 extern "C" extern PServiceDescriptorTable KeServiceDescriptorTable;
 19 
 20 typedef NTSTATUS(*MYNTOPENPROCESS)(
 21     OUT PHANDLE             ProcessHandle,
 22     IN ACCESS_MASK          AccessMask,
 23     IN POBJECT_ATTRIBUTES   ObjectAttributes,
 24     IN PCLIENT_ID           ClientId );//定義一個函數指針,用於下面對O_NtOpenProcess進行強制轉換
 25 
 26 ULONG O_NtOpenProcess = 0; 
 27 
 28 extern "C" NTSTATUS
 29     PsLookupProcessByProcessId(
 30     IN HANDLE ProcessId,
 31     OUT PEPROCESS *Process
 32     );
 33 
 34 void PageProtectOff()//關閉頁面保護
 35 {
 36     __asm{
 37         cli
 38             mov  eax,cr0
 39             and  eax,not 10000h
 40             mov  cr0,eax
 41     }
 42 }
 43 void PageProtectOn()//打開頁面保護
 44 {
 45     __asm{
 46         mov  eax,cr0
 47             or   eax,10000h
 48             mov  cr0,eax
 49             sti
 50     }
 51 }
 52 
 53 // 判斷是否打開的是本身想保護的進程
 54 BOOLEAN ProtectProcess(HANDLE ProcessId,char *str_ProtectObjName)
 55 {
 56     NTSTATUS status;
 57     PEPROCESS process_obj;
 58 
 59     if(!MmIsAddressValid(str_ProtectObjName))//這個條件是用來判斷目標進程名是否有效
 60     {
 61         return FALSE;
 62     }
 63     if(ProcessId == 0)//這個條件是用來排除System Idle Process進程的干擾
 64     {
 65         return FALSE;
 66     }
 67     status=PsLookupProcessByProcessId(ProcessId, &process_obj);//這句用來獲取目標進程的EPROCESS結構
 68     if(!NT_SUCCESS(status))
 69     {
 70         KdPrint(("我錯了,這個是錯誤號:%X---這個是進程ID:%d\n",status,ProcessId));
 71         return FALSE;
 72     }
 73     if(!strcmp((char *)process_obj + 0x174, str_ProtectObjName))//進行比較
 74     {
 75         ObDereferenceObject(process_obj);//對象計數器減1,爲了恢復對象管理器計數,便於回收
 76         return TRUE;
 77     }
 78     ObDereferenceObject(process_obj);
 79     return FALSE;
 80     //使用了PsLookupProcessByProcessId後,必須用ObDereferenceObject回收!
 81     //PsLookupProcessByProcessId獲取指定進程的EPROCESS結構,目的就是獲取進程名
 82 }
 83 NTSTATUS MyNtOpenProcess (
 84     __out PHANDLE ProcessHandle,
 85     __in ACCESS_MASK DesiredAccess,
 86     __in POBJECT_ATTRIBUTES ObjectAttributes,
 87     __in_opt PCLIENT_ID ClientId
 88     )
 89 {
 90     if(ProtectProcess(ClientId->UniqueProcess,"notepad.exe"))    // 若是打開的進程是目標進程
 91     {
 92         KdPrint(("%s打開文件失敗\n",(char *)PsGetCurrentProcess()+0x174));
 93         return STATUS_UNSUCCESSFUL;    // 這是一個關鍵,設置STATUS_UNSUCCESSFUL,CE就會提示打開不成功
 94     }
 95     
 96     return ((MYNTOPENPROCESS)O_NtOpenProcess)(ProcessHandle,//處理完本身的任務後,調用原來的函數,讓其它進程正常工做
 97         DesiredAccess,
 98         ObjectAttributes,
 99         ClientId);
100 }
101 
102 
103 VOID UnHookSsdt()
104 {
105     PageProtectOff();
106     KeServiceDescriptorTable->ServiceTableBase[122] = O_NtOpenProcess; //恢復ssdt中原來的函數地址
107     PageProtectOn();
108 }
109 NTSTATUS HookSsdt()
110 {
111     // 一、在ssdt_hook()函數中保存要hook函數的(NtOpenProcess)地址
112     O_NtOpenProcess = KeServiceDescriptorTable->ServiceTableBase[122];
113     PageProtectOff();
114     // 二、將原來ssdt中所要hook的函數地址換成咱們本身的函數地址
115     KeServiceDescriptorTable->ServiceTableBase[122] = (unsigned int)MyNtOpenProcess;
116     // 此時咱們用CE打開被保護的進程,就會調用咱們本身的函數
117     PageProtectOn();
118     
119     return STATUS_SUCCESS;
120 }
121 VOID DriverUnload(PDRIVER_OBJECT pDriverObject)
122 {
123     UnHookSsdt();
124     KdPrint(("Driver Unload Success !\n"));
125 }
126 
127 extern "C" NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegistryPath )
128 {
129     KdPrint(("Welcome to My Driver\n"));
130     pDriverObject->DriverUnload = DriverUnload;
131     /* 全部函數的地址
132     for (int i = 0; i < KeServiceDescriptorTable->NumberOfServices; i++)
133     {
134         KdPrint(("NumberOfService[%d]-------%X\n", i, KeServiceDescriptorTable->ServiceTableBase[i]));
135     }*/
136     HookSsdt();
137     return STATUS_SUCCESS;
138 }
相關文章
相關標籤/搜索