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;
 
流程:
1、在ssdt_hook()函数中保存要hook函数的(NtOpenProcess)地址
2、将原来ssdt中所要hook的函数地址换成我们自己的函数地址
3、在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()
{
// 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;
}
 
效果:
 
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 }

 

posted @ 2013-09-21 21:49  JoyChou  阅读(1347)  评论(2编辑  收藏  举报