ssdt_hook NtOpenProcess
获取ssdt表中所有函数的地址
for (int i = 0; i < KeServiceDescriptorTable->NumberOfServices; i++)
{
KdPrint(("NumberOfService[%d]-------%X\n", i, KeServiceDescriptorTable->ServiceTableBase[i]));
}
![](http://images0.cnblogs.com/blog/416607/201309/21214726-e85d1a57c1914b2ea812e3b319ec1ebc.png)
需要这样定义
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;
流程:
1、在ssdt_hook()函数中保存要hook函数的(NtOpenProcess)地址
2、将原来ssdt中所要hook的函数地址换成我们自己的函数地址
3、在UnHookSsdt中恢复ssdt中原来的函数地址
当驱动加载成功后,首先执行DriverEntry里面的ssdt_hook()函数,此时我们用CE打开我们保护的进程,
就会执行到我自己定义的函数MyNtOpenProcess()
最后卸载驱动,执行Driver_Unload()里面的UnHookSsdt()函数
![](http://images0.cnblogs.com/blog/416607/201309/21214804-182fd5aefe67408f971f50380de4c24c.png)
作用:
防止被其他进程用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()
{
// 1、在ssdt_hook()函数中保存要hook函数的(NtOpenProcess)地址
O_NtOpenProcess = KeServiceDescriptorTable->ServiceTableBase[122];
PageProtectOff();
// 2、将原来ssdt中所要hook的函数地址换成我们自己的函数地址
KeServiceDescriptorTable->ServiceTableBase[122] = (unsigned int)MyNtOpenProcess;
// 此时我们用CE打开被保护的进程,就会调用我们自己的函数
PageProtectOn();
return STATUS_SUCCESS;
}
效果:
![](http://images0.cnblogs.com/blog/416607/201309/21214844-24f7de2da1aa4515bec8fb787c237d4e.png)
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 // 1、在ssdt_hook()函数中保存要hook函数的(NtOpenProcess)地址 112 O_NtOpenProcess = KeServiceDescriptorTable->ServiceTableBase[122]; 113 PageProtectOff(); 114 // 2、将原来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 }