浅谈HookSSDT和和Resume(恢复)SSDT

   最近在学HookSSDT和针对Hook的ResumeSSDT,避免自己理解有所偏差,把它们写出来,希望大家不吝赐教。(虽然已经是过时了的技术,但是最起码了解其中的原理,嘿嘿嘿。)

  转载注明出处:http://www.cnblogs.com/littlepear/p/6664637.html

一  HookSSDT:

  我们以Hook NtOpenProcess函数为例。首先是寻找SSDT表,32位下已经导出KeServiceDescriptorTable,而64位下没有导出,所以我们先暴力寻找SSDT的地址。

  先讨论64位:

1.寻找SSDT表

  我们通过读取MSR的0xC0000082处的地址,,里面保存的是64位的syscall,当我们u一下这个地址,发现这个就是x64系统调用的入口KiSystemCall64,我们把它作为搜索起始地址。

  然后向下搜寻,以它的lea指令作为特征码,如图

   0x00238c47是它的偏移,KeServiceDescriptorTable的地址 = 0xfffff800`03e91cf2+0x00238c47+7 = 0xfffff800`040ca940。

  我们把SSDT保存在此结构体中。

  typedef struct _SYSTEM_SERVICE_DESCRIPTOR_TABLE_
  {
    PVOID ServiceTableBase; //SSDT(System Service Dispatch Table)服务表的基地址
    PVOID ServiceCounterTableBase; //用于checked builds,包含SSDT中每个服务被调用的次数
    PVOID NumberOfServices; //服务函数的个数,NumberOfService * 4就是整个地址表的大小 64位 0x191, 32位 0x11c
    PVOID ParamTableBase; //SSPT(System Service Parameter Table)的基地址
  }SYSTEM_SERVICE_DESCRIPTOR_TABLE, *PSYSTEM_SERVICE_DESCRIPTOR_TABLE;

2.寻找NtOpenProcess在SSDT表中的系统调用号。 

  NtOpenProcess和ZwOpenProcess在Ntoskrnl.exe和ntdll.dll中都有导出,那么它们之间有什么区别呢?

     先来看ntdll下的两个

   

  发现NtOpenProcess就是ZwOpenProcess的一个别名,我们记他们为ntdll!ZwProcess,它们只把调用号mov到eax中,然后syscall.

  看Ntoskrnl下的两个,

 

  又发现内核空间中的ZwOpenProcess只是NtOpenProcess的一个跳板,它只是把系统调用号(rsp)Mov到eax中,然后调用nt!KiSystemServiceLinkage,真正的实现是通过NtOpenProcess,调用nt!PsOpenProcess

 

  所以大体流程是: Kernel32.dll(API)--->ntdll.dll(Nt/Zw)--->用户模式转内核模式--->Ntoskrnl.exe(Nt)--->完成I/O请求(原路返回)

  此处参考博客:http://www.cnblogs.com/uAreKongqi/p/6597701.html

  然后64位调用号被rsp代替,所以我们只能从ntdll中查找ntdll!ZwOpenProcess,方法就是从ntdll导出表中查找到处函数,然后寻找调用号23h(函数地址+4),我们把它记为__NtOpenProcessIndex

3.保留原NtOpenProcess的偏移和地址。

  我们记__OldNtOpenProcessOffset = __ServiceTableBase[__NtOpenProcessIndex]表示64位下NtOpenProcess的偏移,__ServiceTableBase为SSDT的第一个参数,此偏移是相对于        __ServiceTableBase的,

  64位下,比如0x02e80205,最后一个数字为(函数参数-4),这里涉及到64位函数的调用约定和压参,不予讨论。我们需要__OldNtOpenProcessOffset >> 4+__ServiceTableBase获得函数的地址。

4.Hook NtOpenProcess函数。

  原理就是:将SSDT表中NtOpenProcess的偏移替换成自己的函数的偏移,但是这里就出现问题了,64位下,函数的地址是16位,到__ServiceTableBase的偏移已经远远超过8位,不能放在表里,那怎么办呢? 我们选择InlineHook,就是把一个不经常用的函数,这里选择KeBugCheckEx(这就是64位下这种方法过时的原因,谁知道KeBugCheckEx这个函数不用呢),替换掉NtOpenProcess的偏移,然后我们在KeBugCheckEx函数中实现跳跃到自己的函数中,这就解决问题啦。

 

   以上是64位的,32位需要注意,

第一点:Ntoskrnl.exe中导出了KeServiceDescriptorTable,不需要暴力找。

第二点:__NtOpenProcessIndex这次可以从Ntoskrnl.exe中找了,32位比较好,没用其他东西替代。

第三就是就是__ServiceTableBase[__NtOpenProcessIndex]中储存的是地址,而不是偏移,也不需要找像KeBugCheckEx的跳板函数,直接就可以放我函数的地址,比较方便。

细节看代码:

 1 #include <ntifs.h>
 2 
 3 #define SEC_IMAGE  0x001000000
 4 
 5 
 6 extern
 7 PIMAGE_NT_HEADERS
 8 NTAPI
 9 RtlImageNtHeader(PVOID BaseAddress);
10 
11 extern
12 char* PsGetProcessImageFileName(PEPROCESS EProcess);
13 
14 typedef
15 NTSTATUS(*pfnNtOpenProcess)(
16     _Out_    PHANDLE            ProcessHandle,
17     _In_     ACCESS_MASK        DesiredAccess,
18     _In_     POBJECT_ATTRIBUTES ObjectAttributes,
19     _In_opt_ PCLIENT_ID         ClientId
20     );
21 
22 typedef struct _SYSTEM_SERVICE_DESCRIPTOR_TABLE_
23 {
24     PVOID    ServiceTableBase;                    //SSDT(System Service Dispatch Table)服务表的基地址
25     PVOID    ServiceCounterTableBase;            //用于checked builds,包含SSDT中每个服务被调用的次数
26     PVOID    NumberOfServices;                    //服务函数的个数,NumberOfService * 4就是整个地址表的大小    64位 0x191, 32位 0x11c 
27     PVOID    ParamTableBase;                        //SSPT(System Service Parameter Table)的基地址
28 }SYSTEM_SERVICE_DESCRIPTOR_TABLE, *PSYSTEM_SERVICE_DESCRIPTOR_TABLE;
29 
30 BOOLEAN    GetSSDTAddressInWin7_x64(ULONG64* SSDTAddress);
31 BOOLEAN GetSSDTAddressInWin7_x86(ULONG32* SSDTAddress);
32 VOID DriverUnload(PDRIVER_OBJECT DriverObject);
33 BOOLEAN    GetSSDTFunctionIndexFromExportTableOfNtdllByFunctionName(CHAR* szFuntionName, ULONG32* SSDTFunctionIndex);
34 PVOID
35 GetExportVariableAddressFromNtosKrnlExportTableByVariableName(WCHAR* wzVariableName);
36 BOOLEAN     Ring0MappingPEFile(WCHAR* szFileFullPath, PVOID* MappingBaseAddress, ULONG_PTR* MappingViewSize);
37 ULONG32    CalcFunctionOffsetInSSDT(PVOID ServiceTableBase, PVOID FunctionAddress, ULONG32 ParamterCount);
38 VOID    HookSSDTInWin7_x64(PVOID ServiceTableBase, ULONG32 SSDTFunctionIndex, PVOID MyFunctionAddress,
39     PVOID OldFuntionAddress, ULONG32 OldFunctionParamterCount, UCHAR* OldFunctionCode, ULONG32 PatchCodeLength);
40 VOID    HookSSDTInWin7_x86(PVOID ServiceTableBase, ULONG32 SSDTFunctionIndex, ULONG32 MyFunctionAddress);
41 VOID InlineHook(ULONG64 OldFuntionAddress, ULONG64 MyFunctionAddress, UCHAR* OldFunctionCode, ULONG32 PatchCodeLength);
42 NTSTATUS MyOpenProcess(
43     _Out_    PHANDLE            ProcessHandle,
44     _In_     ACCESS_MASK        DesiredAccess,
45     _In_     POBJECT_ATTRIBUTES ObjectAttributes,
46     _In_opt_ PCLIENT_ID         ClientId
47     );
48 VOID WPOFF();
49 VOID WPON();
50 
51 VOID UnHookSSDTInWin7_x64(PVOID ServiceTableBase, ULONG32 SSDTFunctionIndex, ULONG32 OldFunctionOffset, PVOID OldFunctionAddress,
52     UCHAR* OldFunctionCode, ULONG32 PatchCodeLength);
53 VOID UnHookSSDTInWin7_x86(PVOID ServiceTableBase, ULONG32 SSDTFunctionIndex, ULONG32 OldFunctionAddress);
54 VOID UnlineHook(PVOID OldFunctionAddress, CHAR* OldFunctionCode, ULONG32 PatchCodeLength);
HookSSDT.h
  1 #include "HookSSDT.h"
  2 #include <ntimage.h>
  3 #include <Ntstrsafe.h>
  4 
  5 ULONG32   __NtOpenProcessIndex = 0;
  6 PVOID      __ServiceTableBase = NULL;
  7 ULONG32      __OldNtOpenProcessOffset = 0;
  8 pfnNtOpenProcess      __OldNtOpenProcessAddress = NULL;  //这里无所谓,PVOID也可以
  9 BOOLEAN      __IsHook = FALSE;
 10 UCHAR      __OldCode[15] = { 0 };
 11 
 12 NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegisterPath)
 13 {
 14     NTSTATUS    Status = STATUS_UNSUCCESSFUL;
 15     char        szFunctionName[] = "ZwOpenProcess";
 16     ULONG_PTR    SSDTAddress = 0;    //保存整个SSDT基地址            KeServiceDescriptorTable
 17     ULONG32        TempOffset = 0;
 18     DriverObject->DriverUnload = DriverUnload;
 19     
 20 #ifdef _WIN64
 21     if (GetSSDTAddressInWin7_x64(&SSDTAddress) == FALSE)
 22     {
 23         return Status;
 24     }
 25 #else
 26     if (GetSSDTAddressInWin7_x86(&SSDTAddress) == FALSE)
 27     {
 28         return Status;
 29     }
 30 #endif
 31 
 32     DbgPrint("SSDT:%p
", SSDTAddress);                                    //0x23h
 33     if (GetSSDTFunctionIndexFromExportTableOfNtdllByFunctionName(szFunctionName, &__NtOpenProcessIndex) == FALSE)
 34     {
 35         return Status;
 36     }
 37      
 38     __ServiceTableBase = ((PSYSTEM_SERVICE_DESCRIPTOR_TABLE)SSDTAddress)->ServiceTableBase;
 39 #ifdef _WIN64
 40     __OldNtOpenProcessOffset = ((PULONG32)__ServiceTableBase)[__NtOpenProcessIndex]; 
 41     TempOffset = __OldNtOpenProcessOffset >> 4;    //抹掉最右边的一位
 42     __OldNtOpenProcessAddress = (PVOID)((ULONG64)__ServiceTableBase + TempOffset);
 43     HookSSDTInWin7_x64(__ServiceTableBase, __NtOpenProcessIndex, MyOpenProcess, KeBugCheckEx, 5, __OldCode, 15);
 44 #else
 45     __OldNtOpenProcessAddress = (pfnNtOpenProcess)(((PULONG32)__ServiceTableBase)[__NtOpenProcessIndex]);
 46     /*kd > u 0x84016ba1
 47         nt!NtOpenProcess:
 48     84016ba1 8bff            mov     edi, edi
 49         84016ba3 55              push    ebp
 50         84016ba4 8bec            mov     ebp, esp
 51         84016ba6 51              push    ecx
 52         84016ba7 51              push    ecx
 53         84016ba8 64a124010000    mov     eax, dword ptr fs : [00000124h]
 54         84016bae 8a803a010000    mov     al, byte ptr[eax + 13Ah]
 55         84016bb4 8b4d14          mov     ecx, dword ptr[ebp + 14h]*/
 56 
 57     //0x00145dc8
 58 
 59     HookSSDTInWin7_x86(__ServiceTableBase, __NtOpenProcessIndex, (ULONG32)MyOpenProcess);//强制转换后,MyOpenProcess才可以传,真奇怪
 60 #endif
 61     return STATUS_SUCCESS;
 62 }
 63 
 64 VOID DriverUnload(PDRIVER_OBJECT DriverObject)
 65 {
 66     DbgPrint("ByeBye,Driver!
");
 67 
 68     if (__IsHook)
 69     {
 70 #ifdef _WIN64
 71 
 72         UnHookSSDTInWin7_x64(__ServiceTableBase, __NtOpenProcessIndex, __OldNtOpenProcessOffset, KeBugCheckEx,
 73             __OldCode, 15);
 74 #else
 75         UnHookSSDTInWin7_x86(__ServiceTableBase, __NtOpenProcessIndex, __OldNtOpenProcessAddress);
 76 #endif
 77 
 78         __IsHook = FALSE;
 79     }
 80 }
 81 
 82 BOOLEAN    GetSSDTAddressInWin7_x64(ULONG64* SSDTAddress)
 83 {
 84     //rdmsr c0000082
 85     CHAR*    StartSearchAddress = (char*)__readmsr(0xc0000082);            
 86     CHAR*    EndSearchAddress = StartSearchAddress + PAGE_SIZE; //4KB
 87     CHAR*    i = NULL;
 88     UCHAR    v1 = 0, v2 = 0, v3 = 0;
 89     //必须用UCHAR类型,因为Char的范围是 -128~127   0x80-0x7F
 90     INT64    Offset = 0;
 91     *SSDTAddress = NULL;
 92     for (i = StartSearchAddress; i < EndSearchAddress; i++)
 93     {
 94         if (MmIsAddressValid(i) && MmIsAddressValid(i + 1) && MmIsAddressValid(i + 2))
 95         {
 96             v1 = *i;
 97             v2 = *(i + 1);
 98             v3 = *(i + 2);
 99             if (v1 == 0x4c && v2 == 0x8d && v3 == 0x15)
100             {
101                 // 4c8d15238f4700
102                 memcpy(&Offset, i+3, 4);
103                 *SSDTAddress = Offset + (ULONG64)i+7;
104                 break;
105             }
106         }
107     }
108     if (*SSDTAddress == NULL)
109     {
110         return FALSE;
111     }
112     return TRUE;
113 }
114 
115 BOOLEAN GetSSDTAddressInWin7_x86(ULONG32* SSDTAddress)
116 {
117     //32位下Ntoskrnl.exe有导出 KeServiceDescriptorTable,直接查找即可
118     *SSDTAddress = NULL;
119     *SSDTAddress = (ULONG32)GetExportVariableAddressFromNtosKrnlExportTableByVariableName(L"KeServiceDescriptorTable");
120     if (*SSDTAddress != NULL)
121     {
122         return TRUE;
123     }
124     return FALSE;
125 }
126 
127 PVOID
128 GetExportVariableAddressFromNtosKrnlExportTableByVariableName(WCHAR* wzVariableName)
129 {
130     //通过导出变量名字从NtosKrnl中获得导出变量地址
131     UNICODE_STRING    uniVariableName;
132     PVOID            VariableAddress = NULL;
133 
134     if (wzVariableName&&wcslen(wzVariableName) > 0)
135     {
136         RtlUnicodeStringInit(&uniVariableName, wzVariableName);
137         //从Ntos模块的导出表中获得导出变量的地址
138         VariableAddress = MmGetSystemRoutineAddress(&uniVariableName);
139     }
140     return VariableAddress;
141 }
142 
143 BOOLEAN    GetSSDTFunctionIndexFromExportTableOfNtdllByFunctionName(CHAR* szFuntionName, ULONG32* SSDTFunctionIndex)
144 {
145     WCHAR            szFileFullPath[] = L"\SystemRoot\System32\ntdll.dll";    //C:Windows 
146     ULONG_PTR        MappingViewSize = 0;
147     PVOID            MappingBaseAddress = 0;
148     BOOLEAN            IsOk = FALSE;
149     PIMAGE_NT_HEADERS    Image_Nt_Headers = NULL;
150     PIMAGE_EXPORT_DIRECTORY        ImageExportDirectory = NULL;    //导出表
151     //因为不识别DWORD,所以用UINT32
152     UINT32*            AddressOfFunctions = NULL;
153     UINT32*            AddressOfNames = NULL;
154     UINT16*            AddressOfNameOrdinals = NULL;
155     int                i = 0;
156     char*            v1 = NULL;
157     ULONG32            OrdinalOfFunction = 0;
158     PVOID            AddressOfFunction = 0;
159 #ifdef _WIN64
160     /*
161     0:004> u zwopenprocess
162     ntdll!NtOpenProcess:
163     00000000`774ddc10 4c8bd1          mov     r10,rcx
164     00000000`774ddc13 b823000000      mov     eax,23h
165     00000000`774ddc18 0f05            syscall
166     00000000`774ddc1a c3              ret
167     00000000`774ddc1b 0f1f440000      nop     dword ptr [rax+rax]
168     */
169     ULONG32            Offset_SSDTFunctionIndex = 4;
170 #else
171     /*
172     0:004> u zwopenprocess
173     ntdll!NtOpenProcess:
174     00000000`774ddc10 4c8bd1          mov     r10,rcx
175     00000000`774ddc13 b823000000      mov     eax,23h
176     00000000`774ddc18 0f05            syscall
177     00000000`774ddc1a c3              ret
178     00000000`774ddc1b 0f1f440000      nop     dword ptr [rax+rax]
179     */
180     ULONG32            Offset_SSDTFunctionIndex = 1;
181 #endif
182     
183 
184     *SSDTFunctionIndex = -1;
185     IsOk = Ring0MappingPEFile(szFileFullPath, &MappingBaseAddress, &MappingViewSize);
186     if (IsOk == FALSE)
187     {
188         return FALSE;
189     }
190     else
191     {
192         __try {
193             Image_Nt_Headers = RtlImageNtHeader(MappingBaseAddress);    //extern进来
194             if (Image_Nt_Headers&&Image_Nt_Headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress)
195             {
196                 ImageExportDirectory = (PIMAGE_EXPORT_DIRECTORY)((char*)MappingBaseAddress
197                     + Image_Nt_Headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
198 
199                 AddressOfFunctions = (UINT32*)((char*)MappingBaseAddress + ImageExportDirectory->AddressOfFunctions);
200                 //函数的地址(RVA)
201                 AddressOfNames = (UINT32*)((char*)MappingBaseAddress + ImageExportDirectory->AddressOfNames);;
202                 //函数名字的地址(RVA)
203                 AddressOfNameOrdinals = (UINT16*)((char*)MappingBaseAddress + ImageExportDirectory->AddressOfNameOrdinals);
204                 //有名字的序号的首地址(RVA)
205                 for (i = 0; i < ImageExportDirectory->NumberOfNames; i++)
206                 {
207                     v1 = (char*)((char*)MappingBaseAddress + AddressOfNames[i]); //可以这样写 ImageExportDirectory->AddressOfNames + i * 4
208                     if (_stricmp(szFuntionName, v1) == 0)
209                     {
210                         OrdinalOfFunction = AddressOfNameOrdinals[i];
211                         AddressOfFunction = (PVOID)((char*)MappingBaseAddress + AddressOfFunctions[OrdinalOfFunction]);//AddressOfFunctions[AddressOfNameOrdinals[i]]
212                         *SSDTFunctionIndex = *(ULONG32*)((char*)AddressOfFunction + Offset_SSDTFunctionIndex);
213                         break;
214                     }
215                 }
216             }
217         }
218         __except(EXCEPTION_EXECUTE_HANDLER)
219         {}
220 
221     }
222     ZwUnmapViewOfSection(NtCurrentProcess(), MappingBaseAddress);
223     if (*SSDTFunctionIndex == -1)
224     {
225         return FALSE;
226     }
227     return TRUE;
228 }
229                             //函数需要,所以传双字            二维指针
230 BOOLEAN     Ring0MappingPEFile(WCHAR* szFileFullPath, PVOID* MappingBaseAddress, ULONG_PTR* MappingViewSize)
231 {
232     NTSTATUS            Status;
233     UNICODE_STRING        Temp;
234     OBJECT_ATTRIBUTES    oa;
235     HANDLE                hFile = NULL;
236     HANDLE                hSection = NULL;
237     IO_STATUS_BLOCK        IoStatusBlock;
238 
239     if (!szFileFullPath&&MmIsAddressValid(szFileFullPath))
240     {
241         return FALSE;
242     }
243     if (!MappingBaseAddress&&MmIsAddressValid(MappingBaseAddress))
244     {
245         return FALSE;
246     }
247     RtlUnicodeStringInit(&Temp, szFileFullPath);
248     InitializeObjectAttributes(&oa,    //out
249         &Temp,                    //in ObjectName
250         OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,//被系统在和ObjectName比较匹配时不区分大小写||此句柄只能用于内核模式下
251         NULL,                    //与ObjectName参数匹配的根目录对象,如果ObjectName是对象的全路径则设置此参数为NULL
252         NULL                    //驱动程序可以使用NULL用于创建一个具有默认安全描述符的对象
253         );
254     //打开文件,获得文件句柄
255     Status = IoCreateFile(&hFile,
256         GENERIC_READ | SYNCHRONIZE, //可读|同步
257         &oa,
258         &IoStatusBlock,            //返回I/O请求的完成情况
259         NULL,
260         FILE_ATTRIBUTE_NORMAL,
261         FILE_SHARE_READ,
262         FILE_OPEN,
263         FILE_SYNCHRONOUS_IO_NONALERT,
264         NULL,
265         0,
266         CreateFileTypeNone,
267         NULL,
268         IO_NO_PARAMETER_CHECKING
269         );
270     if (!NT_SUCCESS(Status))
271     {
272         return    FALSE;
273     }
274     oa.ObjectName = NULL;
275     Status = ZwCreateSection(&hSection,
276         SECTION_QUERY | SECTION_MAP_READ,
277         &oa,
278         NULL,
279         PAGE_WRITECOPY,
280         SEC_IMAGE,//内存按1M对齐 0x1000 000
281         hFile
282         );
283     ZwClose(hFile);
284     if (!NT_SUCCESS(Status))
285     {
286         return FALSE;
287     }
288     Status = ZwMapViewOfSection(hSection,
289         NtCurrentProcess(),
290         MappingBaseAddress,
291         0,
292         0,
293         0,
294         MappingViewSize,
295         ViewUnmap,            //不能被映射到子进程中
296         0,
297         PAGE_WRITECOPY
298         );
299     ZwClose(hSection);
300     if (!NT_SUCCESS(Status))
301     {
302         return FALSE;
303     }
304     return TRUE;
305 }
306 
307 ULONG32    CalcFunctionOffsetInSSDT(PVOID ServiceTableBase, PVOID FunctionAddress, ULONG32 ParamterCount)
308 {
309     //完全没必要像下面这样折腾,就是一个做个SSDT表中类似的地址,有时间自己写一个
310     ULONG32  Offset = 0;
311     CHAR     Temp = 0;
312     CHAR     Bits[4] = { 0 };
313     int      i = 0;
314     Offset = (ULONG32)((ULONG64)FunctionAddress - (ULONG64)ServiceTableBase);
315     Offset = Offset << 4;
316     if (ParamterCount > 4)
317     {
318         ParamterCount = ParamterCount-4;     //NtReadFile  9个参数  和参数压栈有关
319     }
320     else
321     {
322         ParamterCount = 0;
323     }                                    
324     memcpy(&Temp, &Offset, 1);        // 1010 0010    <<4-----> 0010 0000 后面处理参数
325 #define SETBIT(x,y) x|=(1<<y)         //将X的第Y位置1
326 #define CLRBIT(x,y) x&=~(1<<y)        //将X的第Y位清0
327 #define GETBIT(x,y) (x & (1 << y))    //取X的第Y位,返回0或非0
328 
329     for (i = 0; i < 4; i++)
330     {
331         Bits[i] = GETBIT(ParamterCount, i);
332         if (Bits[i])
333         {
334             SETBIT(Temp, i);
335         }
336         else
337         {
338             CLRBIT(Temp, i);
339         }
340     }
341     memcpy(&Offset, &Temp, 1);
342     return Offset;
343 }
344 
345 //write protect 第17位
346 VOID WPOFF()
347 {
348     _disable();
349     __writecr0(__readcr0() & (~(0x10000)));
350 
351 }
352 
353 VOID WPON()
354 {
355     __writecr0(__readcr0() ^ 0x10000);
356     _enable();
357 }
358 
359 VOID    HookSSDTInWin7_x64(PVOID ServiceTableBase, ULONG32 SSDTFunctionIndex, PVOID MyFunctionAddress,
360     PVOID OldFuntionAddress, ULONG32 OldFunctionParamterCount, UCHAR* OldFunctionCode, ULONG32 PatchCodeLength)
361 {
362     ULONG32        MyOffset = 0;
363     WPOFF();
364     InlineHook(OldFuntionAddress, MyFunctionAddress, OldFunctionCode, PatchCodeLength);
365     WPON();
366 
367     MyOffset = CalcFunctionOffsetInSSDT(ServiceTableBase, OldFuntionAddress, OldFunctionParamterCount);
368     WPOFF();
369     ((PULONG32)ServiceTableBase)[SSDTFunctionIndex] = MyOffset;
370     WPON();
371 
372     __IsHook = TRUE;
373 }
374 
375 VOID    HookSSDTInWin7_x86(PVOID ServiceTableBase, ULONG32 SSDTFunctionIndex, ULONG32 MyFunctionAddress)
376 {
377     WPOFF();
378     ((PULONG32)ServiceTableBase)[SSDTFunctionIndex] = (ULONG32)MyFunctionAddress;
379     WPON();
380 
381     __IsHook = TRUE;
382 }
383 
384 VOID InlineHook(ULONG64 OldFuntionAddress, ULONG64 MyFunctionAddress, UCHAR* OldFunctionCode, ULONG32 PatchCodeLength)
385 {
386     CHAR PatchCode[] = "xFFx25x00x00x00x00xFFxFFxFFxFFxFFxFFxFFxFF";  //神坑啊,脑残啊,写成PatchCode 到memcpy才崩溃
387     ULONG64 Temp = MyFunctionAddress;
388     memcpy(OldFunctionCode, (PVOID)OldFuntionAddress, PatchCodeLength); //保存原来的函数指令
389     memcpy(PatchCode + 6, &Temp, 8);
390     DbgPrint("%s
", PatchCode);
391     memset((PVOID)OldFuntionAddress, 0x90, PatchCodeLength);  //先全部打上NOP(计组)
392     memcpy((PVOID)OldFuntionAddress, PatchCode, 14);
393 }
394 
395 
396 //SSDT HOOK的替换函数如何对访问进行过滤”比“如何实现SSDT HOOK”要复杂多了,详见ediary   HookNtOpenProcess后的事情
397 NTSTATUS MyOpenProcess(
398     _Out_    PHANDLE            ProcessHandle,
399     _In_     ACCESS_MASK        DesiredAccess,
400     _In_     POBJECT_ATTRIBUTES ObjectAttributes,
401     _In_opt_ PCLIENT_ID         ClientId
402     )
403 {
404     //EnumProcessByForce.exe
405     //调用OpenProcess---->去NtDll导出表中寻找ntdll!NtOpenProcess或者ntdll!ZwOpenProcess 导出表有名称的索引---->切入内核-->跳板nt!ZwOpenProcess  Ntoskernl.exe(NtOpenProcess mov eax,23h SSDT[23h])
406     // ---->KeCheckBugEx ---->Jmp MyOpenProcess
407     PEPROCESS    EProcess = PsGetCurrentProcess(); //EnumProcessByForce.exe
408     if (EProcess != NULL && MmIsAddressValid(EProcess))
409     {
410         char *szProcessImageFileName = PsGetProcessImageFileName(EProcess);
411         if (strstr(szProcessImageFileName, "EnumProcess") != 0)
412         {
413             return STATUS_ACCESS_DENIED;    //黑名单中返回
414         }
415     }
416     __OldNtOpenProcessAddress(ProcessHandle, DesiredAccess, ObjectAttributes, ClientId); //白名单
417                                                     //OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, i)
418     //return STATUS_SUCCESS;      死循环
419     //return STATUS_UNSUCCESSFUL;  阻塞      很有趣
420 }
421 
422 VOID UnHookSSDTInWin7_x64(PVOID ServiceTableBase, ULONG32 SSDTFunctionIndex, ULONG32 OldFunctionOffset, PVOID OldFunctionAddress,
423     UCHAR* OldFunctionCode, ULONG32 PatchCodeLength)
424 {
425     WPOFF();
426     UnlineHook(OldFunctionAddress, OldFunctionCode, PatchCodeLength);
427     WPON();
428 
429     WPOFF();
430     ((PULONG32)ServiceTableBase)[SSDTFunctionIndex] = (ULONG32)OldFunctionOffset;
431     WPON();
432 }
433 
434 VOID UnlineHook(PVOID OldFunctionAddress, CHAR* OldFunctionCode, ULONG32 PatchCodeLength)
435 {
436     memcpy((PVOID)OldFunctionAddress, OldFunctionCode, PatchCodeLength);
437 }
438 
439 VOID UnHookSSDTInWin7_x86(PVOID ServiceTableBase, ULONG32 SSDTFunctionIndex, ULONG32 OldFunctionAddress)
440 {
441     WPOFF();
442     ((PULONG32)ServiceTableBase)[SSDTFunctionIndex] = (ULONG32)OldFunctionAddress;
443     WPON();
444 }
HookSSDT.c

ResumeSSDT:

 原理:因为我们Hook的是模块中的NtOpenProcess, 所以我们可以寻找Ntoskrnl.exe文件中NtOpenProcess的地址,再替换掉已经被替换掉的。

先谈64位:

  1.找SSDT表和调用号和Hook的过程一样。

  2.关键是找NtOpenProcess的真正地址。

  有两种方法:

  1.因为NtOpenProcess已经在Ntoskrnl.exe中导出了,所以我们直接从导出表中找到它的函数地址,只不过这个地址是文件中的,需要转换成在内存中的,那怎么转换呢?

  我们首先要了解这个文件中的函数地址是怎么回事,《WindowsPE权威指南》上92页上有讲,IMAGE_OPTIONAL_HEADER32.ImageBase的地址是映像基地址的优先装入地址,exe文件被装入到起始地址为0x400000h的虚拟内存地址处。

再看《WindowsPE权威指南》80页上,链接器在产生可执行文件的时候,都是对应ImageBase(32位下是0x400000, 64位下是0x00000001`40000000)来生成机器码的,好比其中的一个函数NtOpenProcess,直接查看ntoskrnl.exe导出表中它的地址,也就是它在产生可执行文件的时候,所有东西都是对照这个地址生成机器码的,并且这个地址是它假想映射到内存的地址,即按0x1000对齐过的地址。

PS:  用PECheck小工具查看NtOpenProcess,注意偏移值和上述假想地址-ImageBase相等

但是对于EXE来说,每个文件使用的都是独立的虚拟地址空间,所以,优先装入的地址通常不会被其他模块占据,也就是说,如果再来新的模块,前面那个值被占领了,操作系统会做出调整,找到合适的地址,这个地址就是真正的内存中的模块基地址。

那好了,我们可以来计算真正的内存中的地址。我们先计算文件中函数的偏移,即 0x00000001`403473d0-0x00000001`40000000, 再加上真正的模块基地址ModuleBase,不就得到了真正的函数地址了?

然后再和现在内存中SSDT 0x23h的位置比较,看看是否被Hook了。

  2.第二种找NtOpenProcess的方法,就是通过将内存中SSDT->ServiceTableBase的偏移(RVA)转换为文件中文件中它的偏移(FOA),然后通过调用号再找到文件中NtOpenProcess的地址,然后转换为内存中的地址方法和上述步骤一样。 那么怎么将RVA转换为FVA呢?

  《WindowsPE权威指南》93页上,

    (1) 首先判断RVA落在哪个节内。

   (2) 求出该节的起始 RVA0 = IMAGE_SRCTION_HEADER->VirtualAddress

   (3) 求出偏移量Offset = RVA-RVA0.          这个偏移在文件中和内存中都是一样的(因为对齐是在节的数据后面补0,而不是前面)。

   (4) 求出FOA = IMAGE_SECTION_HEADER.PointerToRawData+Offset

 好了,64位的两种方法就介绍完了,32位的话,有几个地方需要注意:

  1.Ntoskrnl.exe在32位下有几种不同的模式,

  参考博客:http://www.tuicool.com/articles/UrqIZv

  所以要判断当下系统是哪一个。

   2.就是NtOpenProcess在SSDT表中以地址的形式保存,就是和64位的一般区别了。

  细节看代码吧:

  1 #include <ntifs.h>
  2 
  3 #define SEC_IMAGE  0x001000000
  4 
  5 extern
  6 PIMAGE_NT_HEADERS
  7 NTAPI
  8 RtlImageNtHeader(PVOID BaseAddress);
  9 
 10 typedef enum _SYSTEM_INFORMATION_CLASS_
 11 {
 12     SystemBasicInformation = 0x0,
 13     SystemProcessorInformation = 0x1,
 14     SystemPerformanceInformation = 0x2,
 15     SystemTimeOfDayInformation = 0x3,
 16     SystemPathInformation = 0x4,
 17     SystemProcessInformation = 0x5,
 18     SystemCallCountInformation = 0x6,
 19     SystemDeviceInformation = 0x7,
 20     SystemProcessorPerformanceInformation = 0x8,
 21     SystemFlagsInformation = 0x9,
 22     SystemCallTimeInformation = 0xa,
 23     SystemModuleInformation = 0xb,
 24     SystemLocksInformation = 0xc,
 25     SystemStackTraceInformation = 0xd,
 26     SystemPagedPoolInformation = 0xe,
 27     SystemNonPagedPoolInformation = 0xf,
 28     SystemHandleInformation = 0x10,
 29     SystemObjectInformation = 0x11,
 30     SystemPageFileInformation = 0x12,
 31     SystemVdmInstemulInformation = 0x13,
 32     SystemVdmBopInformation = 0x14,
 33     SystemFileCacheInformation = 0x15,
 34     SystemPoolTagInformation = 0x16,
 35     SystemInterruptInformation = 0x17,
 36     SystemDpcBehaviorInformation = 0x18,
 37     SystemFullMemoryInformation = 0x19,
 38     SystemLoadGdiDriverInformation = 0x1a,
 39     SystemUnloadGdiDriverInformation = 0x1b,
 40     SystemTimeAdjustmentInformation = 0x1c,
 41     SystemSummaryMemoryInformation = 0x1d,
 42     SystemMirrorMemoryInformation = 0x1e,
 43     SystemPerformanceTraceInformation = 0x1f,
 44     SystemObsolete0 = 0x20,
 45     SystemExceptionInformation = 0x21,
 46     SystemCrashDumpStateInformation = 0x22,
 47     SystemKernelDebuggerInformation = 0x23,
 48     SystemContextSwitchInformation = 0x24,
 49     SystemRegistryQuotaInformation = 0x25,
 50     SystemExtendServiceTableInformation = 0x26,
 51     SystemPrioritySeperation = 0x27,
 52     SystemVerifierAddDriverInformation = 0x28,
 53     SystemVerifierRemoveDriverInformation = 0x29,
 54     SystemProcessorIdleInformation = 0x2a,
 55     SystemLegacyDriverInformation = 0x2b,
 56     SystemCurrentTimeZoneInformation = 0x2c,
 57     SystemLookasideInformation = 0x2d,
 58     SystemTimeSlipNotification = 0x2e,
 59     SystemSessionCreate = 0x2f,
 60     SystemSessionDetach = 0x30,
 61     SystemSessionInformation = 0x31,
 62     SystemRangeStartInformation = 0x32,
 63     SystemVerifierInformation = 0x33,
 64     SystemVerifierThunkExtend = 0x34,
 65     SystemSessionProcessInformation = 0x35,
 66     SystemLoadGdiDriverInSystemSpace = 0x36,
 67     SystemNumaProcessorMap = 0x37,
 68     SystemPrefetcherInformation = 0x38,
 69     SystemExtendedProcessInformation = 0x39,
 70     SystemRecommendedSharedDataAlignment = 0x3a,
 71     SystemComPlusPackage = 0x3b,
 72     SystemNumaAvailableMemory = 0x3c,
 73     SystemProcessorPowerInformation = 0x3d,
 74     SystemEmulationBasicInformation = 0x3e,
 75     SystemEmulationProcessorInformation = 0x3f,
 76     SystemExtendedHandleInformation = 0x40,
 77     SystemLostDelayedWriteInformation = 0x41,
 78     SystemBigPoolInformation = 0x42,
 79     SystemSessionPoolTagInformation = 0x43,
 80     SystemSessionMappedViewInformation = 0x44,
 81     SystemHotpatchInformation = 0x45,
 82     SystemObjectSecurityMode = 0x46,
 83     SystemWatchdogTimerHandler = 0x47,
 84     SystemWatchdogTimerInformation = 0x48,
 85     SystemLogicalProcessorInformation = 0x49,
 86     SystemWow64SharedInformationObsolete = 0x4a,
 87     SystemRegisterFirmwareTableInformationHandler = 0x4b,
 88     SystemFirmwareTableInformation = 0x4c,
 89     SystemModuleInformationEx = 0x4d,
 90     SystemVerifierTriageInformation = 0x4e,
 91     SystemSuperfetchInformation = 0x4f,
 92     SystemMemoryListInformation = 0x50,
 93     SystemFileCacheInformationEx = 0x51,
 94     SystemThreadPriorityClientIdInformation = 0x52,
 95     SystemProcessorIdleCycleTimeInformation = 0x53,
 96     SystemVerifierCancellationInformation = 0x54,
 97     SystemProcessorPowerInformationEx = 0x55,
 98     SystemRefTraceInformation = 0x56,
 99     SystemSpecialPoolInformation = 0x57,
100     SystemProcessIdInformation = 0x58,
101     SystemErrorPortInformation = 0x59,
102     SystemBootEnvironmentInformation = 0x5a,
103     SystemHypervisorInformation = 0x5b,
104     SystemVerifierInformationEx = 0x5c,
105     SystemTimeZoneInformation = 0x5d,
106     SystemImageFileExecutionOptionsInformation = 0x5e,
107     SystemCoverageInformation = 0x5f,
108     SystemPrefetchPatchInformation = 0x60,
109     SystemVerifierFaultsInformation = 0x61,
110     SystemSystemPartitionInformation = 0x62,
111     SystemSystemDiskInformation = 0x63,
112     SystemProcessorPerformanceDistribution = 0x64,
113     SystemNumaProximityNodeInformation = 0x65,
114     SystemDynamicTimeZoneInformation = 0x66,
115     SystemCodeIntegrityInformation = 0x67,
116     SystemProcessorMicrocodeUpdateInformation = 0x68,
117     SystemProcessorBrandString = 0x69,
118     SystemVirtualAddressInformation = 0x6a,
119     SystemLogicalProcessorAndGroupInformation = 0x6b,
120     SystemProcessorCycleTimeInformation = 0x6c,
121     SystemStoreInformation = 0x6d,
122     SystemRegistryAppendString = 0x6e,
123     SystemAitSamplingValue = 0x6f,
124     SystemVhdBootInformation = 0x70,
125     SystemCpuQuotaInformation = 0x71,
126     SystemNativeBasicInformation = 0x72,
127     SystemErrorPortTimeouts = 0x73,
128     SystemLowPriorityIoInformation = 0x74,
129     SystemBootEntropyInformation = 0x75,
130     SystemVerifierCountersInformation = 0x76,
131     SystemPagedPoolInformationEx = 0x77,
132     SystemSystemPtesInformationEx = 0x78,
133     SystemNodeDistanceInformation = 0x79,
134     SystemAcpiAuditInformation = 0x7a,
135     SystemBasicPerformanceInformation = 0x7b,
136     SystemQueryPerformanceCounterInformation = 0x7c,
137     SystemSessionBigPoolInformation = 0x7d,
138     SystemBootGraphicsInformation = 0x7e,
139     SystemScrubPhysicalMemoryInformation = 0x7f,
140     SystemBadPageInformation = 0x80,
141     SystemProcessorProfileControlArea = 0x81,
142     SystemCombinePhysicalMemoryInformation = 0x82,
143     SystemEntropyInterruptTimingInformation = 0x83,
144     SystemConsoleInformation = 0x84,
145     SystemPlatformBinaryInformation = 0x85,
146     SystemThrottleNotificationInformation = 0x86,
147     SystemHypervisorProcessorCountInformation = 0x87,
148     SystemDeviceDataInformation = 0x88,
149     SystemDeviceDataEnumerationInformation = 0x89,
150     SystemMemoryTopologyInformation = 0x8a,
151     SystemMemoryChannelInformation = 0x8b,
152     SystemBootLogoInformation = 0x8c,
153     SystemProcessorPerformanceInformationEx = 0x8d,
154     SystemSpare0 = 0x8e,
155     SystemSecureBootPolicyInformation = 0x8f,
156     SystemPageFileInformationEx = 0x90,
157     SystemSecureBootInformation = 0x91,
158     SystemEntropyInterruptTimingRawInformation = 0x92,
159     SystemPortableWorkspaceEfiLauncherInformation = 0x93,
160     SystemFullProcessInformation = 0x94,
161     SystemKernelDebuggerInformationEx = 0x95,
162     SystemBootMetadataInformation = 0x96,
163     SystemSoftRebootInformation = 0x97,
164     SystemElamCertificateInformation = 0x98,
165     SystemOfflineDumpConfigInformation = 0x99,
166     SystemProcessorFeaturesInformation = 0x9a,
167     SystemRegistryReconciliationInformation = 0x9b,
168     MaxSystemInfoClass = 0x9c,
169 } SYSTEM_INFORMATION_CLASS;
170 
171 
172 typedef struct _SYSTEM_MODULE_INFORMATION
173 {
174     ULONG Reserved[2];
175 #ifdef _WIN64
176     ULONG Reserved2[2];
177 #endif 
178 
179     PVOID Base;
180     ULONG Size;
181     ULONG Flags;
182     USHORT Index;
183     USHORT Unknown;
184     USHORT LoadCount;
185     USHORT ModuleNameOffset;
186     CHAR   ImageName[256];
187 }SYSTEM_MODULE_INFORMATION,*PSYSTEM_MODULE_INFORMATION;
188 
189 typedef struct
190 {
191     ULONG ulNumberOfModules;
192     SYSTEM_MODULE_INFORMATION smi;        //我只取Ntoskrnl一个
193 }MODULES,*PMODULES;
194 
195 
196 typedef struct _SYSTEM_SERVICE_DESCRIPTOR_TABLE_
197 {
198     PVOID    ServiceTableBase;                    //SSDT(System Service Dispatch Table)服务表的基地址
199     PVOID    ServiceCounterTableBase;            //用于checked builds,包含SSDT中每个服务被调用的次数
200     PVOID    NumberOfServices;                    //服务函数的个数,NumberOfService * 4就是整个地址表的大小    64位 0x191, 32位 0x11c 
201     PVOID    ParamTableBase;                        //SSPT(System Service Parameter Table)的基地址
202 }SYSTEM_SERVICE_DESCRIPTOR_TABLE, *PSYSTEM_SERVICE_DESCRIPTOR_TABLE;
203 
204 extern
205 NTSTATUS
206 ZwQuerySystemInformation(
207     IN ULONG SystemInformationClass,
208     IN PVOID SystemInformation,
209     IN ULONG SystemInformationLength,
210     OUT PULONG ReturnLength);
211 
212 void chartowchar(char* src, WCHAR* dst);
213 
214 VOID UnloadDriver(PDRIVER_OBJECT DriverObject);
215 
216 BOOLEAN GetModuleInfoByModuleName(PVOID* ModuleBase, ULONG64* ModuleSize);
217 
218 
219 
220 BOOLEAN GetSSDTAddressInWin7_x64(ULONG64* SSDTAddress);
221 
222 BOOLEAN    GetSSDTAddressInWin7_x86(ULONG32* SSDTAddress);
223 
224 PVOID    GetExportVariableAddressFromNtoskrnlExportTableByVariableName(WCHAR* wzVariableName);
225 
226 BOOLEAN GetSSDTFunctionIndexFromExportTableOfNtdllByFunctionName(CHAR* szFuntionName, ULONG* SSDTFunctionIndex);
227 
228 VOID WPOFF();
229 
230 VOID WPON();
231 
232 BOOLEAN    Ring0MappingPEFile(WCHAR* szFileFullPath, PVOID* MappingBaseAddress, ULONG_PTR* MappingViewSize);
233 
234 BOOLEAN ResumeSSDTInWin7(ULONG_PTR SSDTAddress, ULONG_PTR ModuleBase, ULONG32 SSDTFunctionIndex, ULONG32 ParameterCount);
235 
236 BOOLEAN ReadingFileInRing0Space(WCHAR* wzFileFullPath, PVOID* szBuffer);
237 
238 VOID CharToWchar(PCHAR src, PWCHAR dst);
ResumeSSDT.h
  1 #include "ResumeSSDT.h"
  2 #include <ntstrsafe.h>
  3 #include <ntimage.h>
  4 
  5 PVOID __NtosModuleBaseAddress = 0;
  6 PVOID __NtosModuleSize = 0;
  7 ULONG __NtOpenProcessIndex = 0;
  8 char  __szNtosName[15] = { 0 };
  9 WCHAR __wzNtosName[15] = { 0 };
 10 NTSTATUS DriverEntry(PDRIVER_OBJECT DriverEntry, PUNICODE_STRING RegisterPath)
 11 {
 12 
 13     ULONG_PTR    SSDTAddress = 0;
 14     char        szFunctionName[] = "NtOpenProcess";
 15     DriverEntry->DriverUnload = UnloadDriver;    
 16     if (GetModuleInfoByModuleName(
 17         &__NtosModuleBaseAddress, &__NtosModuleSize) == FALSE)
 18     {
 19         return STATUS_UNSUCCESSFUL;
 20     }
 21     DbgPrint("_Ntos:%p", __NtosModuleBaseAddress);
 22 
 23 
 24 #ifdef _WIN64
 25     if (GetSSDTAddressInWin7_x64(&SSDTAddress) == FALSE)
 26     {
 27         DbgPrint("U
");
 28         return STATUS_UNSUCCESSFUL;
 29     }
 30 #else
 31     if (GetSSDTAddressInWin7_x86(&SSDTAddress) == FALSE)
 32     {
 33         return STATUS_UNSUCCESSFUL;
 34     }
 35 #endif
 36     if (GetSSDTFunctionIndexFromExportTableOfNtdllByFunctionName(szFunctionName, &__NtOpenProcessIndex) == FALSE)
 37     {
 38         return STATUS_UNSUCCESSFUL;
 39     }
 40 
 41     if (ResumeSSDTInWin7(SSDTAddress, __NtosModuleBaseAddress, __NtOpenProcessIndex, 4) == TRUE)
 42     {
 43         DbgPrint("Success
");
 44         return STATUS_SUCCESS;
 45     }
 46 
 47     return STATUS_UNSUCCESSFUL;
 48 }
 49 
 50 VOID UnloadDriver(PDRIVER_OBJECT DriverObject)
 51 {
 52     DbgPrint("UnloadDriver Success!
");
 53 }
 54 
 55 //下面这个函数是根据模块名字得到模块信息
 56 BOOLEAN GetModuleInfoByModuleName(PVOID* ModuleBase, ULONG64* ModuleSize)
 57 {
 58     NTSTATUS    Status = STATUS_SUCCESS;
 59     ULONG        ulReturnLength = 0;
 60     PVOID        szBufferData = 0;
 61 
 62     Status = ZwQuerySystemInformation(SystemModuleInformation,NULL, 0, &ulReturnLength);
 63     if (Status != STATUS_INFO_LENGTH_MISMATCH) //此返回值的意思是 返回的长度不等于你要求的长度,因为我们传0,所以正好判断一下是否读取成功
 64     {
 65         return FALSE;
 66     }
 67     szBufferData = ExAllocatePool(PagedPool, ulReturnLength);    //一般数据可以用PagedPool,ShellCode用NoPagedPool
 68     if (szBufferData == NULL)
 69     {
 70         return FALSE;
 71     }
 72     Status = ZwQuerySystemInformation(SystemModuleInformation, szBufferData, ulReturnLength, &ulReturnLength);  
 73     if (!NT_SUCCESS(Status))
 74     {
 75         ExFreePool(szBufferData);
 76         return FALSE;
 77     }
 78     for (int i = 0; i < ((PMODULES)szBufferData)->ulNumberOfModules; i++)
 79     {
 80         if (strstr(((PMODULES)szBufferData)->smi.ImageName,"ntoskrnl.exe") != NULL)
 81         {
 82             strcpy(__szNtosName, "ntoskrnl.exe");
 83             *ModuleBase = ((PMODULES)szBufferData)->smi.Base;
 84             *ModuleSize = ((PMODULES)szBufferData)->smi.Size;
 85             break;
 86         }
 87         else if (strstr(((PMODULES)szBufferData)->smi.ImageName, "ntkrnlpa.exe") != NULL)
 88         {
 89             strcpy(__szNtosName, "ntkrnlpa.exe");
 90             *ModuleBase = ((PMODULES)szBufferData)->smi.Base;
 91             *ModuleSize = ((PMODULES)szBufferData)->smi.Size;
 92             break;
 93         }
 94         else if (strstr(((PMODULES)szBufferData)->smi.ImageName, "ntkrnlmp.exe") != NULL)
 95         {
 96             strcpy(__szNtosName, "ntkrnlmp.exe");
 97             *ModuleBase = ((PMODULES)szBufferData)->smi.Base;
 98             *ModuleSize = ((PMODULES)szBufferData)->smi.Size;
 99             break;
100         }
101         else if (strstr(((PMODULES)szBufferData)->smi.ImageName, "ntkrpamp.exe") != NULL)
102         {
103             strcpy(__szNtosName, "ntkrpamp.exe");
104             *ModuleBase = ((PMODULES)szBufferData)->smi.Base;
105             *ModuleSize = ((PMODULES)szBufferData)->smi.Size;
106             break;
107         }
108     }
109     chartowchar(__szNtosName, __wzNtosName);
110     if (szBufferData != NULL)
111     {
112         ExFreePool(szBufferData);
113         szBufferData = NULL;
114     }
115     if (*ModuleBase != 0)
116     {
117         return TRUE;
118     }
119     return FALSE;
120 }
121 
122 
123 //BOOLEAN GetNtosModule(PVOID* ModuleBase, ULONG64* ModuleSize)
124 //{
125 //    NTSTATUS    Status = STATUS_SUCCESS;
126 //    ULONG        ulReturnLength = 0;
127 //    PVOID        szBufferData = 0;
128 //
129 //    Status = ZwQuerySystemInformation(SystemModuleInformation,NULL, 0, &ulReturnLength);
130 //    if (Status != STATUS_INFO_LENGTH_MISMATCH) //此返回值的意思是 返回的长度不等于你要求的长度,因为我们传0,所以正好判断一下是否读取成功
131 //    {
132 //        return FALSE;
133 //    }
134 //    szBufferData = ExAllocatePool(PagedPool, ulReturnLength);    //一般数据可以用PagedPool,ShellCode用NoPagedPool
135 //    if (szBufferData == NULL)
136 //    {
137 //        return FALSE;
138 //    }
139 //    Status = ZwQuerySystemInformation(SystemModuleInformation, szBufferData, ulReturnLength, &ulReturnLength);  
140 //    if (!NT_SUCCESS(Status))
141 //    {
142 //        ExFreePool(szBufferData);
143 //        return FALSE;
144 //    }
145 //    for (int i = 0; i < ((PMODULES)szBufferData)->ulNumberOfModules; i++)
146 //    {
147 //            strcpy(__szNtosName, ((PMODULES)szBufferData)->smi.ImageName);                //依据的原理就是ZwQuerySystemInformation读的第一个模块就是Ntos系列的,这样不用比对,直接取第一个,大大方便了32位的编程
148 //            CharToWchar(__szNtosName, __wzNtosName);
149 //            *ModuleBase = ((PMODULES)szBufferData)->smi.Base;
150 //            *ModuleSize = ((PMODULES)szBufferData)->smi.Size;
151 //            break;
152 //    }
153 //    if (szBufferData != NULL)
154 //    {
155 //        ExFreePool(szBufferData);
156 //        szBufferData = NULL;
157 //    }
158 //    if (*ModuleBase != 0)
159 //    {
160 //        return TRUE;
161 //    }
162 //    return FALSE;
163 //}
164 //char*转 wchar*  
165 //输入窄字符串首地址,输出宽字符串,buffer 需要已经分配好空间  
166 
167 void chartowchar(char* src, WCHAR* dst)
168 {
169     UNICODE_STRING ustring;
170     ANSI_STRING astring;
171     RtlInitAnsiString(&astring, src);
172     RtlAnsiStringToUnicodeString(&ustring, &astring, TRUE);
173     wcscpy(dst, ustring.Buffer);
174     RtlFreeUnicodeString(&ustring);
175 }
176 
177 BOOLEAN GetSSDTAddressInWin7_x64(ULONG64* SSDTAddress)
178 {
179     CHAR*    StartSearchAddress = (char*)__readmsr(0xc0000082);
180     CHAR*    EndSearchAddress = StartSearchAddress + PAGE_SIZE;
181     CHAR*    i = NULL;
182     UCHAR    v1 = 0, v2 = 0, v3 = 0;
183     INT64    Offset = 0;
184     *SSDTAddress = NULL;
185     for (i = StartSearchAddress; i < EndSearchAddress; i++)
186     {
187         if (MmIsAddressValid(i) && MmIsAddressValid(i + 1) && MmIsAddressValid(i + 2))
188         {
189             v1 = *i;
190             v2 = *(i + 1);
191             v3 = *(i + 2);
192             if (v1 == 0x4c && v2 == 0x8d && v3 == 0x15)
193             {
194                 memcpy(&Offset, i + 3, 4);
195                 *SSDTAddress = Offset + (ULONG64)i + 7;
196                 return TRUE;
197             }
198         }
199     }
200     return FALSE;
201 }
202 
203 BOOLEAN    GetSSDTAddressInWin7_x86(ULONG32* SSDTAddress)
204 {
205     //直接查找KeServiceDescriptorTable
206     *SSDTAddress = (ULONG32)GetExportVariableAddressFromNtoskrnlExportTableByVariableName(L"KeServiceDescriptorTable");
207     if (*SSDTAddress != 0)
208     {
209         return TRUE;
210     }
211     return FALSE;
212 }
213 
214 PVOID    GetExportVariableAddressFromNtoskrnlExportTableByVariableName(WCHAR* wzVariableName)
215 {
216     UNICODE_STRING    uniVariableName;
217     PVOID            VariableAddress = NULL;
218     if (wzVariableName&&wcslen(wzVariableName) > 0)
219     {
220         RtlUnicodeStringInit(&uniVariableName, wzVariableName);
221         VariableAddress = MmGetSystemRoutineAddress(&uniVariableName);
222     }
223     return VariableAddress;
224 }
225 
226 BOOLEAN GetSSDTFunctionIndexFromExportTableOfNtdllByFunctionName(CHAR* szFuntionName, ULONG* SSDTFunctionIndex)
227 {
228     WCHAR        szFileFullPath[] = L"\SystemRoot\System32\ntdll.dll";
229     ULONG32        Offset_SSDTFunctionIndex = 0;
230     PVOID        MappingBaseAddress = 0;
231     BOOLEAN        IsOk = FALSE;
232     ULONG_PTR    MappingViewSize = 0;
233     PIMAGE_NT_HEADERS    Image_Nt_Headers = NULL;
234     PIMAGE_EXPORT_DIRECTORY        ImageExportDirectory = NULL;
235     //因为不识别DWORD,所以用UINT32
236     UINT32*            AddressOfFunctions = NULL;
237     UINT32*            AddressOfNames = NULL;
238     UINT16*            AddressOfNameOrdinals = NULL;
239     int                i = 0;
240     char*            v1 = NULL;
241     ULONG32            OrdinalOfFunction = 0;
242     PVOID            AddressOfFunction = 0;
243 #ifdef _WIN64
244     Offset_SSDTFunctionIndex = 4;
245 #else
246     Offset_SSDTFunctionIndex = 1;
247 #endif
248     *SSDTFunctionIndex = -1;
249     IsOk = Ring0MappingPEFile(szFileFullPath, &MappingBaseAddress, &MappingViewSize);
250     if (IsOk == FALSE)
251     {
252         return FALSE;
253     }
254     else
255     {
256         __try
257         {
258             Image_Nt_Headers = RtlImageNtHeader(MappingBaseAddress);
259             if (Image_Nt_Headers&&Image_Nt_Headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress)
260             {
261                 ImageExportDirectory = (PIMAGE_EXPORT_DIRECTORY)((char*)MappingBaseAddress
262                     + Image_Nt_Headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
263 
264                 AddressOfFunctions = (UINT32*)((char*)MappingBaseAddress + ImageExportDirectory->AddressOfFunctions);
265                 //函数的地址(RVA)
266                 AddressOfNames = (UINT32*)((char*)MappingBaseAddress + ImageExportDirectory->AddressOfNames);;
267                 //函数名字的地址(RVA)
268                 AddressOfNameOrdinals = (UINT16*)((char*)MappingBaseAddress + ImageExportDirectory->AddressOfNameOrdinals);
269                 //有名字的序号的首地址(RVA)
270                 for (i = 0; i < ImageExportDirectory->NumberOfNames; i++)
271                 {
272                     v1 = (char*)((char*)MappingBaseAddress + AddressOfNames[i]); //可以这样写 ImageExportDirectory->AddressOfNames + i * 4
273                     if (_stricmp(szFuntionName, v1) == 0)
274                     {
275                         OrdinalOfFunction = AddressOfNameOrdinals[i];
276                         AddressOfFunction = (PVOID)((char*)MappingBaseAddress + AddressOfFunctions[OrdinalOfFunction]);//AddressOfFunctions[AddressOfNameOrdinals[i]]
277                         *SSDTFunctionIndex = *(ULONG32*)((char*)AddressOfFunction + Offset_SSDTFunctionIndex);
278                         break;
279                     }
280                 }
281             }
282         }
283         __except (EXCEPTION_EXECUTE_HANDLER)
284         {}
285     }
286     ZwUnmapViewOfSection(NtCurrentProcess(), MappingBaseAddress);
287     if (*SSDTFunctionIndex == -1)
288     {
289         return FALSE;
290     }
291     return TRUE;
292 }
293 
294 BOOLEAN    Ring0MappingPEFile(WCHAR* szFileFullPath, PVOID* MappingBaseAddress, ULONG_PTR* MappingViewSize)
295 {
296     UNICODE_STRING        v1;
297     OBJECT_ATTRIBUTES    oa;
298     NTSTATUS            Status;
299     HANDLE                hFile = NULL;
300     HANDLE                hSection = NULL;
301     IO_STATUS_BLOCK        IoStatusBlock;
302     if (!szFileFullPath&&MmIsAddressValid(szFileFullPath))
303     {
304         return FALSE;
305     }
306     if (!MappingBaseAddress&&MmIsAddressValid(MappingBaseAddress))
307     {
308         return FALSE;
309     }
310     RtlUnicodeStringInit(&v1, szFileFullPath);
311     InitializeObjectAttributes(&oa,
312         &v1,
313         OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
314         NULL,
315         NULL
316         );
317     Status = IoCreateFile(&hFile,
318         GENERIC_READ | SYNCHRONIZE,
319         &oa,
320         &IoStatusBlock,
321         NULL,
322         FILE_ATTRIBUTE_NORMAL,
323         FILE_SHARE_READ,
324         FILE_OPEN,
325         FILE_SYNCHRONOUS_IO_NONALERT,
326         NULL,
327         0,
328         CreateFileTypeNone,
329         NULL,
330         IO_NO_PARAMETER_CHECKING);
331     if (!NT_SUCCESS(Status))
332     {
333         return FALSE;
334     }
335     oa.ObjectName = NULL;
336     Status = ZwCreateSection(&hSection,
337         SECTION_QUERY | SECTION_MAP_READ,
338         &oa,
339         NULL,
340         PAGE_WRITECOPY,
341         SEC_IMAGE,
342         hFile);
343     ZwClose(hFile);
344     if (!NT_SUCCESS(Status))
345     {
346         return FALSE;
347     }
348     Status = ZwMapViewOfSection(hSection,
349         NtCurrentProcess(),
350         MappingBaseAddress,
351         0,
352         0,
353         0,
354         MappingViewSize,
355         ViewUnmap,            //不能被映射到子进程中
356         0,
357         PAGE_WRITECOPY
358         );
359     ZwClose(hSection);
360     if (!NT_SUCCESS(Status))
361     {
362         return FALSE;
363     }
364     return TRUE;
365 }
366 
367 
368 BOOLEAN ResumeSSDTInWin7(ULONG_PTR SSDTAddress, ULONG_PTR ModuleBase, ULONG32 SSDTFunctionIndex, ULONG32 ParameterCount)
369 {
370     PUCHAR                    RVAOfSSDTBase = 0;
371     PVOID                    szBuffer = NULL;
372     PVOID                    PresupposeOfImageBase = 0;
373     PVOID                    AddressOfSSDTBaseInFile = 0;
374     PVOID                    Temp = 0;
375     CHAR                    TempByte = 0;
376     CHAR                    Bits[4] = { 0 };
377     ULONG32                    HookedOffset = 0;
378     PIMAGE_DOS_HEADER        Image_Dos_Header = NULL;
379     PIMAGE_NT_HEADERS        Image_Nt_Headers = NULL;
380     PIMAGE_OPTIONAL_HEADER    OptionalHeader = NULL;
381     PIMAGE_SECTION_HEADER    SectionHeader = NULL;
382     WCHAR        wzFileFullPath[0x100] = L"\SystemRoot\System32\"; //  C:\  
383     int                        i = 0;
384     wcscat(wzFileFullPath, __wzNtosName);
385     RVAOfSSDTBase = (PUCHAR)(((PSYSTEM_SERVICE_DESCRIPTOR_TABLE)SSDTAddress)->ServiceTableBase) - (PUCHAR)ModuleBase;
386     if (ReadingFileInRing0Space(wzFileFullPath, &szBuffer) == FALSE)
387     {
388         return FALSE;
389     }
390     Image_Dos_Header = (PIMAGE_DOS_HEADER)szBuffer;
391     Image_Nt_Headers = (PIMAGE_NT_HEADERS)(Image_Dos_Header->e_lfanew + (PUCHAR)szBuffer);
392     OptionalHeader = &(Image_Nt_Headers->OptionalHeader);
393     PresupposeOfImageBase = OptionalHeader->ImageBase;    //64位为0x00000001`40000000,假想值,希望EXE文件加载到内存后就是这个值,并且文件中所有的机器码都是按照这个地址对齐的
394 
395     SectionHeader = (PIMAGE_SECTION_HEADER)((char*)Image_Nt_Headers + sizeof(IMAGE_NT_HEADERS));
396     for (i = 0; i < Image_Nt_Headers->FileHeader.NumberOfSections; i++)
397     {
398         if (RVAOfSSDTBase >= SectionHeader[i].VirtualAddress && RVAOfSSDTBase < (SectionHeader[i].VirtualAddress + SectionHeader[i].SizeOfRawData))
399         {                                                                                //内存映像中的RVA
400             AddressOfSSDTBaseInFile = (PVOID)((PUCHAR)szBuffer + (RVAOfSSDTBase - (PUCHAR)(SectionHeader[i].VirtualAddress)) + (SectionHeader[i].PointerToRawData));
401             break;
402         }                                                //0xfffff7fe`c3e5a040
403     }
404     Temp = (PUCHAR)(((PULONG_PTR)AddressOfSSDTBaseInFile)[SSDTFunctionIndex]) - (PUCHAR)PresupposeOfImageBase + (PUCHAR)ModuleBase;
405 
406 #ifdef _WIN64
407     //重定位函数地址     内存中的函数地址 = 预想的函数基地址 - 预想的模块基地址 + 真实的模块基地址  预想的基地址是由操作系统自己完成,链接器在产生可执行文件的时候,是对应ImageBase来生成机器码的
408     Temp = (PUCHAR)Temp - (PUCHAR)(((PSYSTEM_SERVICE_DESCRIPTOR_TABLE)SSDTAddress)->ServiceTableBase);
409     Temp = (ULONG32)Temp << 4;
410     //处理参数个数
411 
412     if (ParameterCount > 4)
413     {
414         ParameterCount = ParameterCount - 4;
415     }
416     else
417     {
418         ParameterCount = 0;
419     }
420     memcpy(&TempByte, &Temp, 1);
421 #define SETBIT(x, y) x |= (1 << y)         //将X的第Y位置1
422 #define CLRBIT(x,y) x&=~(1<<y)        //将X的第Y位清0
423 #define GETBIT(x,y) (x & (1 << y))    //取X的第Y位,返回0或非0
424     for (i = 0; i < 4; i++)
425     {
426         Bits[i] = GETBIT(ParameterCount, i);
427         if (Bits[i])
428         {
429             SETBIT(TempByte, i);
430         }
431         else
432         {
433             CLRBIT(TempByte, i);
434         }
435     }
436     memcpy(&Temp, &TempByte, 1);
437 #endif // _WIN64
438     //获得当前已经被Hook了的地址
439     HookedOffset = ((PULONG32)((PSYSTEM_SERVICE_DESCRIPTOR_TABLE)SSDTAddress)->ServiceTableBase)[SSDTFunctionIndex];
440     if (Temp != HookedOffset)
441     {
442         WPOFF();
443         ((PLONG32)((PSYSTEM_SERVICE_DESCRIPTOR_TABLE)SSDTAddress)->ServiceTableBase)[SSDTFunctionIndex] = (ULONG32)Temp;
444         WPON();
445     }
446     if (szBuffer != NULL)
447     {
448         ExFreePool(szBuffer);
449         szBuffer = NULL;
450     }
451     return TRUE;
452 }
453 
454 
455 
456 BOOLEAN ReadingFileInRing0Space(WCHAR* wzFileFullPath, PVOID* szBuffer)
457 {
458     NTSTATUS            Status;
459     UNICODE_STRING        Temp;
460     OBJECT_ATTRIBUTES    oa;
461     HANDLE                hFile;
462     IO_STATUS_BLOCK        IoStatusBlock;
463     LARGE_INTEGER        liReturnLength = { 0 };
464     FILE_STANDARD_INFORMATION    fsi = { 0 };
465     if (wzFileFullPath == NULL&&*szBuffer != NULL)
466     {
467         return FALSE;
468     }
469     RtlUnicodeStringInit(&Temp, wzFileFullPath);
470     InitializeObjectAttributes(&oa, &Temp, OBJ_CASE_INSENSITIVE, NULL, NULL);
471     Status = ZwCreateFile(&hFile,
472         SYNCHRONIZE,        //异步
473         &oa,
474         &IoStatusBlock,
475         NULL,
476         FILE_ATTRIBUTE_NORMAL,
477         FILE_SHARE_READ,
478         FILE_OPEN,
479         FILE_SYNCHRONOUS_IO_NONALERT,
480         NULL,
481         0);
482     if (!NT_SUCCESS(Status))
483     {
484         return FALSE;
485     }
486     Status = ZwQueryInformationFile(hFile,
487         &IoStatusBlock,
488         &fsi,
489         sizeof(FILE_STANDARD_INFORMATION),
490         FileStandardInformation);
491     if (!NT_SUCCESS(Status))
492     {
493         ZwClose(hFile);
494         return FALSE;
495     }
496     *szBuffer = ExAllocatePool(PagedPool, fsi.EndOfFile.LowPart);
497     if (*szBuffer == NULL)
498     {
499         ZwClose(hFile);
500         return FALSE;
501     }
502     Status = ZwReadFile(hFile,
503         NULL,
504         NULL,
505         NULL,
506         &IoStatusBlock,
507         *szBuffer,
508         fsi.EndOfFile.LowPart,
509         &liReturnLength,
510         NULL);
511 
512     if (!NT_SUCCESS(Status))
513     {
514         ExFreePool(*szBuffer);
515         ZwClose(hFile);
516         return FALSE;
517     }
518     ZwClose(hFile);
519     return TRUE;
520 }
521 
522 
523 
524 
525 VOID WPOFF()
526 {
527     _disable();
528     __writecr0(__readcr0() & (~(0x10000)));
529 
530 }
531 VOID WPON()
532 {
533     __writecr0(__readcr0() ^ 0x10000);
534     _enable();
535 }
ResumeSSDT.c

这几个终于做完了,做驱动的代码,我感觉有个坑,因为内核的地址都比较大,都达到0xFFFF8000_00000000以上了,所以一般如果表示成十进制有符号数,都是负数了,你如果直接和某个数加,如果这个数是ULONG类型的,则那个地址必须转换了,就出错了,看下面的例子:

 PointerToRawData是ULONG类型,如果前面几个变量用PCHAR的话,根据C语言的默认的强制类型转换规则,char,short --> int --> unsigned --> long --> double <-- float。 内核层的地址都成负数了,一加肯定错了,坑了好几次,引以为戒吧。

最后如果我哪里有理解错的地方,欢迎大家指正,我将虚心求教。

原文地址:https://www.cnblogs.com/littlepear/p/6664637.html