决赛打五天,是真的顶级,但是五天比一年学的东西都多…

本题解题附件自取

2024腾讯游戏安全竞赛决赛题解

分析

自行加载loader.sys, 找到用户名为administrator的KEY,作为答案提交(1分)

Key 和 User 默认读 C:\card.txt,如果找不到或者是错误,那么加载会失败,于是想到 hook NtCreateFile 获取到文件句柄,再 hook NtReadFile 找到文件内容写入的地址。

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
#include <ntifs.h>
#include <ntdef.h>
#include <ntstatus.h>
#include <ntddk.h>
#define MAX_BACKTRACE_DEPTH 20
#define SYMBOL L"\\??\\xia0ji2333"
#define kprintf(format, ...) DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, format, ##__VA_ARGS__)

UINT64 BaseAddr=NULL, DLLSize=0;

void DeleteDevice(PDRIVER_OBJECT pDriver) {
kprintf(("Line %d:xia0ji233: start delete device\n"), __LINE__);
if (pDriver->DeviceObject) {
UNICODE_STRING Sym;
RtlInitUnicodeString(&Sym, SYMBOL);//CreateFile
kprintf(("Line %d:xia0ji233: Delete Symbol\n"), __LINE__);
IoDeleteSymbolicLink(&Sym);
kprintf(("Line %d:xia0ji233: Delete Device\n"), __LINE__);
IoDeleteDevice(pDriver->DeviceObject);
}
kprintf(("Line %d:xia0ji233: end delete device\n"), __LINE__);
}

HANDLE FileHandler = NULL;

char newcode[] = {
0x48,0xB8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//mov rax,xxx
0xFF,0xE0//jmp rax
};
char oldcode[] = {
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,
};

char newcode2[] = {
0x48,0xB8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//mov rax,xxx
0xFF,0xE0//jmp rax
};
char oldcode2[] = {
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,
};

char* target;
char* target2;
KIRQL WPOFFx64()
{
KIRQL irql = KeRaiseIrqlToDpcLevel();
UINT64 cr0 = __readcr0();
cr0 &= 0xfffffffffffeffff;
__writecr0(cr0);
_disable();
return irql;
}

void WPONx64(KIRQL irql)
{
UINT64 cr0 = __readcr0();
cr0 |= 0x10000;
_enable();
__writecr0(cr0);
KeLowerIrql(irql);
}

NTSTATUS Unhook() {
KIRQL irql = WPOFFx64();
for (int i = 0; i < sizeof(newcode); i++) {
target[i] = oldcode[i];
}
WPONx64(irql);
return STATUS_SUCCESS;
}

NTSTATUS Unhook2() {
KIRQL irql = WPOFFx64();
for (int i = 0; i < sizeof(newcode2); i++) {
target2[i] = oldcode2[i];
}
WPONx64(irql);
return STATUS_SUCCESS;
}

NTSTATUS Hook() {
KIRQL irql = WPOFFx64();
for (int i = 0; i < sizeof(newcode); i++) {
target[i] = newcode[i];
}
WPONx64(irql);
return STATUS_SUCCESS;
}

NTSTATUS Hook2() {
KIRQL irql = WPOFFx64();
for (int i = 0; i < sizeof(newcode2); i++) {
target2[i] = newcode2[i];
}
WPONx64(irql);
return STATUS_SUCCESS;
}

PDRIVER_OBJECT g_Object = NULL;
typedef struct _LDR_DATA_TABLE_ENTRY {
LIST_ENTRY InLoadOrderLinks;
LIST_ENTRY InMemoryOrderLinks;
LIST_ENTRY InInitializationOrderLinks;
PVOID DllBase;
PVOID EntryPoint;//驱动的进入点 DriverEntry
ULONG SizeOfImage;
UNICODE_STRING FullDllName;//驱动的满路径
UNICODE_STRING BaseDllName;//不带路径的驱动名字
ULONG Flags;
USHORT LoadCount;
USHORT TlsIndex;
union {
LIST_ENTRY HashLinks;
struct {
PVOID SectionPointer;
ULONG CheckSum;
};
};
union {
struct {
ULONG TimeDateStamp;
};
struct {
PVOID LoadedImports;
};
};
} LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;



typedef NTSTATUS (* FuncPtr) (
_Out_ PHANDLE FileHandle,
_In_ ACCESS_MASK DesiredAccess,
_In_ POBJECT_ATTRIBUTES ObjectAttributes,
_Out_ PIO_STATUS_BLOCK IoStatusBlock,
_In_opt_ PLARGE_INTEGER AllocationSize,
_In_ ULONG FileAttributes,
_In_ ULONG ShareAccess,
_In_ ULONG CreateDisposition,
_In_ ULONG CreateOptions,
_In_reads_bytes_opt_(EaLength) PVOID EaBuffer,
_In_ ULONG EaLength
);
typedef NTSTATUS (* FuncPtr2 )(
_In_ HANDLE FileHandle,
_In_opt_ HANDLE Event,
_In_opt_ PIO_APC_ROUTINE ApcRoutine,
_In_opt_ PVOID ApcContext,
_Out_ PIO_STATUS_BLOCK IoStatusBlock,
_Out_writes_bytes_(Length) PVOID Buffer,
_In_ ULONG Length,
_In_opt_ PLARGE_INTEGER ByteOffset,
_In_opt_ PULONG Key
);

ULONG myCreateFile(_Out_ PHANDLE FileHandle,
_In_ ACCESS_MASK DesiredAccess,
_In_ POBJECT_ATTRIBUTES ObjectAttributes,
_Out_ PIO_STATUS_BLOCK IoStatusBlock,
_In_opt_ PLARGE_INTEGER AllocationSize,
_In_ ULONG FileAttributes,
_In_ ULONG ShareAccess,
_In_ ULONG CreateDisposition,
_In_ ULONG CreateOptions,
_In_reads_bytes_opt_(EaLength) PVOID EaBuffer,
_In_ ULONG EaLength) {

Unhook();
FuncPtr func = (FuncPtr)target;

NTSTATUS s = func(FileHandle,DesiredAccess,ObjectAttributes,IoStatusBlock,AllocationSize,FileAttributes,ShareAccess,CreateDisposition,CreateOptions,EaBuffer,EaLength);
if (!wcscmp(ObjectAttributes->ObjectName->Buffer, L"\\??\\C:\\card.txt")) {
kprintf(("call NtCreateFile(%p,%p,%S,%p,%p,%p,%p,%p,%p,%p,%p)\n"), FileHandle,DesiredAccess,ObjectAttributes->ObjectName->Buffer,IoStatusBlock,AllocationSize,FileAttributes,ShareAccess,CreateDisposition,CreateOptions,EaBuffer,EaLength);
DbgBreakPoint();
FileHandler = *FileHandle;
}

//DbgBreakPoint();


Hook();

return s;
}

ULONG myReadFile(
_In_ HANDLE FileHandle,
_In_opt_ HANDLE Event,
_In_opt_ PIO_APC_ROUTINE ApcRoutine,
_In_opt_ PVOID ApcContext,
_Out_ PIO_STATUS_BLOCK IoStatusBlock,
_Out_writes_bytes_(Length) PVOID Buffer,
_In_ ULONG Length,
_In_opt_ PLARGE_INTEGER ByteOffset,
_In_opt_ PULONG Key) {

Unhook2();
FuncPtr2 func = (FuncPtr2)target2;

if (FileHandler && FileHandler == FileHandle) {
kprintf(("call NtReadFile(%p,%p,%p,%p,%p,%p,%p,%p,%p)\n"), FileHandle, Event, ApcRoutine, ApcContext, IoStatusBlock, Buffer, Length, ByteOffset, Key);
DbgBreakPoint();
FileHandler = 0;
}
//DbgBreakPoint();
NTSTATUS s = func(FileHandle,Event,ApcRoutine,ApcContext,IoStatusBlock,Buffer,Length,ByteOffset,Key);

Hook2();

return s;


}

void DriverUnload(PDRIVER_OBJECT pDriver) {
kprintf(("Line %d:xia0ji233: start unload\n"), __LINE__);
Unhook();
Unhook2();
DeleteDevice(pDriver);
}


NTSTATUS DriverEntry(
_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath
) {
DriverObject->DriverUnload = DriverUnload;
kprintf(("Line %d:xia0ji233: RegistryPath = %S\n"), __LINE__, RegistryPath->Buffer);
target = NtCreateFile;
target2 = NtReadFile;
kprintf(("Line %d:xia0ji233: NtCreateFile=%p NtReadFile=%p\n"), __LINE__, target,target2);
g_Object = DriverObject;
if (target&&target2) {
for (int i = 0; i < sizeof(oldcode); i++) {
oldcode[i] = target[i];
oldcode2[i] = target2[i];
}
*(UINT64*)(newcode + 2) = myCreateFile;
*(UINT64*)(newcode2 + 2) = myReadFile;
Hook();
Hook2();
}
else {
kprintf(("xia0ji233:hahaha"));
}
return 0;
}

跟到后面可以找到文件内容(ReadFile第六个参数),在文件内容处下硬件读取断点,可以找到这里文件内容被被写入两个寄存器,随后又写入另外的内存(RCX所指向的内存)。

然后就直接 ret 了,这里将内存窗口转到 RCX 指向的地址,然后程序跳出来。

紧接着给末尾添 0 字节,然后将 r14 与 0x10 比较,小于跳出

这一次输出失败了,于是考虑换长度但是改一个字符,发现在另外的位置写了零字节

在跟的过程中,发现后面的一个内存就是长度

然后接着跟,会跟到一个找 - 的代码

很容易理解,因为 - 就是分隔 user 和 key 的,必然有一个遍历在找 - 的位置,那就直接跳到它找到了 - 的位置,发现有一个大跳转

随后会把 - 所处的地址存入栈中

紧接着跟,发现把User拷贝到下面的内存了

随后将key也写入下方的内存

然后开始循环 key,判断如果 -0x30 是否 >10,应该 key 只能是数字的判断。

于是我在循环这里下了一个软件断点,发现 RDI 会存储当前已遍历的十进制。

例如现在已经遍历到了 405,那么 rdi=0x195=405。

经过数次的循环,

可以发现 RDI=0xF17E203C,就是 4051574844,那么接下来就往下面跟看看跟 User 有什么样的关系。

取出ACE之后算出一个值 0x0000000020450083,最后很 0x1003F 相乘,得到 00000000F17E203D,刚好是题目所给 key 的十六进制表示。

后面通过一定的调试分析,发现一个规律

似乎它会把每一个字符加起来然后 *0x1003F,并且一定是 int

先验证一遍ACE是否正确

发现果然如此,那么照样子算出 key 为 4007951923

编写一个keygen,能生成对于任何用户名的KEY(1分)

根据上面的分析,不难写出 keygen 程序

1
2
3
4
5
6
7
8
9
10
11
#include<stdio.h>
#include<string.h>
int main(){
char user[]="xia0ji233";
int n=strlen(user);
unsigned key=0;
for(int i=0;i<n;i++){
key=(key+user[i])*0x1003F;
}
printf("%u\n",key);
}

运行即可获得 key 的输出。

编写一个exp,在exp程序运行后,对于任意的用户名-key,Loader.sys均能正确启动(1分)

有这么几种方法:监控内核线程,在 shellcode 执行的时候拦截,把比较是否相等的代码patch掉。监控文件读写,在读文件的时候,判断如果是目标文件,让它返回正确的结果。

最后还是选择在文件处拦截,然后趁它读文件的时候遍历驱动模块改它代码,上面分析的 imul 关键指令在 Loader.sys+0xafc1c4 的位置

再调试一遍,决出关键一步,找到了 cmp 指令

如图所示的内存分别为实际输入的数值和通过 user 计算得到的key的数值,随后取出相比较,不相等显然跳转到 Fail 分支,因此这里改成 NOP 让它不跳转任意情况下跳转成功。

此时的 sys 基地址为 0xFFFFF806F82D0000,与该指令相减得到 0xa27e 的偏移,只需把这两个字节改成 0x90 即可达到任意的 user key 可以成功加载驱动。

我先使用了hook的方式去劫持,确保劫持的函数没错,再通过修改劫持时机和方式让方法满足要求

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
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
#include <ntifs.h>
#include <ntdef.h>
#include <ntstatus.h>
#include <ntddk.h>
#define MAX_BACKTRACE_DEPTH 20
#define SYMBOL L"\\??\\xia0ji2333"
#define kprintf(format, ...) DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, format, ##__VA_ARGS__)

UINT64 BaseAddr=NULL, DLLSize=0;

void DeleteDevice(PDRIVER_OBJECT pDriver) {
kprintf(("Line %d:xia0ji233: start delete device\n"), __LINE__);
if (pDriver->DeviceObject) {
UNICODE_STRING Sym;
RtlInitUnicodeString(&Sym, SYMBOL);//CreateFile
kprintf(("Line %d:xia0ji233: Delete Symbol\n"), __LINE__);
IoDeleteSymbolicLink(&Sym);
kprintf(("Line %d:xia0ji233: Delete Device\n"), __LINE__);
IoDeleteDevice(pDriver->DeviceObject);
}
kprintf(("Line %d:xia0ji233: end delete device\n"), __LINE__);
}

HANDLE FileHandler = NULL;

char newcode[] = {
0x48,0xB8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//mov rax,xxx
0xFF,0xE0//jmp rax
};
char oldcode[] = {
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,
};

char newcode2[] = {
0x48,0xB8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//mov rax,xxx
0xFF,0xE0//jmp rax
};
char oldcode2[] = {
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,
};

char* target;
char* target2;
KIRQL WPOFFx64()
{
KIRQL irql = KeRaiseIrqlToDpcLevel();
UINT64 cr0 = __readcr0();
cr0 &= 0xfffffffffffeffff;
__writecr0(cr0);
_disable();
return irql;
}

void WPONx64(KIRQL irql)
{
UINT64 cr0 = __readcr0();
cr0 |= 0x10000;
_enable();
__writecr0(cr0);
KeLowerIrql(irql);
}

NTSTATUS Unhook() {
KIRQL irql = WPOFFx64();
for (int i = 0; i < sizeof(newcode); i++) {
target[i] = oldcode[i];
}
WPONx64(irql);
return STATUS_SUCCESS;
}

NTSTATUS Unhook2() {
KIRQL irql = WPOFFx64();
for (int i = 0; i < sizeof(newcode2); i++) {
target2[i] = oldcode2[i];
}
WPONx64(irql);
return STATUS_SUCCESS;
}

NTSTATUS Hook() {
KIRQL irql = WPOFFx64();
for (int i = 0; i < sizeof(newcode); i++) {
target[i] = newcode[i];
}
WPONx64(irql);
return STATUS_SUCCESS;
}

NTSTATUS Hook2() {
KIRQL irql = WPOFFx64();
for (int i = 0; i < sizeof(newcode2); i++) {
target2[i] = newcode2[i];
}
WPONx64(irql);
return STATUS_SUCCESS;
}

PDRIVER_OBJECT g_Object = NULL;
typedef struct _LDR_DATA_TABLE_ENTRY {
LIST_ENTRY InLoadOrderLinks;
LIST_ENTRY InMemoryOrderLinks;
LIST_ENTRY InInitializationOrderLinks;
PVOID DllBase;
PVOID EntryPoint;//驱动的进入点 DriverEntry
ULONG SizeOfImage;
UNICODE_STRING FullDllName;//驱动的满路径
UNICODE_STRING BaseDllName;//不带路径的驱动名字
ULONG Flags;
USHORT LoadCount;
USHORT TlsIndex;
union {
LIST_ENTRY HashLinks;
struct {
PVOID SectionPointer;
ULONG CheckSum;
};
};
union {
struct {
ULONG TimeDateStamp;
};
struct {
PVOID LoadedImports;
};
};
} LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;



typedef NTSTATUS (* FuncPtr) (
_Out_ PHANDLE FileHandle,
_In_ ACCESS_MASK DesiredAccess,
_In_ POBJECT_ATTRIBUTES ObjectAttributes,
_Out_ PIO_STATUS_BLOCK IoStatusBlock,
_In_opt_ PLARGE_INTEGER AllocationSize,
_In_ ULONG FileAttributes,
_In_ ULONG ShareAccess,
_In_ ULONG CreateDisposition,
_In_ ULONG CreateOptions,
_In_reads_bytes_opt_(EaLength) PVOID EaBuffer,
_In_ ULONG EaLength
);
typedef NTSTATUS (* FuncPtr2 )(
_In_ HANDLE FileHandle,
_In_opt_ HANDLE Event,
_In_opt_ PIO_APC_ROUTINE ApcRoutine,
_In_opt_ PVOID ApcContext,
_Out_ PIO_STATUS_BLOCK IoStatusBlock,
_Out_writes_bytes_(Length) PVOID Buffer,
_In_ ULONG Length,
_In_opt_ PLARGE_INTEGER ByteOffset,
_In_opt_ PULONG Key
);

NTSTATUS EnumerateKernelThreads();

typedef NTSTATUS (*ZWQUERYSYSTEMINFORMATION)(ULONG, PVOID, ULONG, PULONG);
typedef struct _SYSTEM_PROCESS_INFORMATION {
ULONG NextEntryOffset;
ULONG NumberOfThreads;
LARGE_INTEGER Reserved[3];
LARGE_INTEGER CreateTime;
LARGE_INTEGER UserTime;
LARGE_INTEGER KernelTime;
UNICODE_STRING ImageName;
ULONG BasePriority;
HANDLE ProcessId;
HANDLE InheritedFromProcessId;
} SYSTEM_PROCESS_INFORMATION, *PSYSTEM_PROCESS_INFORMATION;
typedef struct _SYSTEM_THREAD_INFORMATION {
LARGE_INTEGER KernelTime;
LARGE_INTEGER UserTime;
LARGE_INTEGER CreateTime;
ULONG WaitTime;
PVOID StartAddress;
CLIENT_ID ClientId;
ULONG Priority;
LONG BasePriority;
ULONG ContextSwitchCount;
LONG State;
LONG WaitReason;
} SYSTEM_THREAD_INFORMATION, *PSYSTEM_THREAD_INFORMATION;
typedef enum _SYSTEM_INFORMATION_CLASS {
SystemProcessInformation = 5
} SYSTEM_INFORMATION_CLASS;
#define SystemModuleInformation 11

ULONG myCreateFile(_Out_ PHANDLE FileHandle,
_In_ ACCESS_MASK DesiredAccess,
_In_ POBJECT_ATTRIBUTES ObjectAttributes,
_Out_ PIO_STATUS_BLOCK IoStatusBlock,
_In_opt_ PLARGE_INTEGER AllocationSize,
_In_ ULONG FileAttributes,
_In_ ULONG ShareAccess,
_In_ ULONG CreateDisposition,
_In_ ULONG CreateOptions,
_In_reads_bytes_opt_(EaLength) PVOID EaBuffer,
_In_ ULONG EaLength) {

Unhook();
FuncPtr func = (FuncPtr)target;

NTSTATUS s = func(FileHandle,DesiredAccess,ObjectAttributes,IoStatusBlock,AllocationSize,FileAttributes,ShareAccess,CreateDisposition,CreateOptions,EaBuffer,EaLength);
if (!wcscmp(ObjectAttributes->ObjectName->Buffer, L"\\??\\C:\\card.txt")) {
kprintf(("call NtCreateFile(%p,%p,%S,%p,%p,%p,%p,%p,%p,%p,%p)\n"), FileHandle,DesiredAccess,ObjectAttributes->ObjectName->Buffer,IoStatusBlock,AllocationSize,FileAttributes,ShareAccess,CreateDisposition,CreateOptions,EaBuffer,EaLength);
//DbgBreakPoint();
FileHandler = *FileHandle;
}

//DbgBreakPoint();


Hook();

return s;
}

MDLWriteMemory(PVOID pBaseAddress, PVOID pWriteData, SIZE_T writeDataSize)
{
PMDL pMdl = NULL;
PVOID pNewAddress = NULL;
pMdl = MmCreateMdl(NULL, pBaseAddress, writeDataSize);
if (NULL == pMdl)
{
return FALSE;
}
MmBuildMdlForNonPagedPool(pMdl);
pNewAddress = MmMapLockedPages(pMdl, KernelMode);
if (NULL == pNewAddress)
{
IoFreeMdl(pMdl);
}
RtlCopyMemory(pNewAddress, pWriteData, writeDataSize);
MmUnmapLockedPages(pNewAddress, pMdl);
IoFreeMdl(pMdl);
return TRUE;
}


VOID PatchInstr()
{
LDR_DATA_TABLE_ENTRY *TE, *Tmp;
TE = (LDR_DATA_TABLE_ENTRY*)g_Object->DriverSection;
PLIST_ENTRY LinkList;
;
int i = 0;
LinkList = TE->InLoadOrderLinks.Flink;
UNICODE_STRING name;
RtlInitUnicodeString(&name,L"Loader.sys");
;
while (LinkList != &TE->InLoadOrderLinks)
{
Tmp = (LDR_DATA_TABLE_ENTRY*)LinkList;

if (RtlEqualUnicodeString(&Tmp->BaseDllName, &name,FALSE)) {
kprintf(("DLLname:%S DLLBase=%p nowcode=%p\n"), Tmp->BaseDllName.Buffer,Tmp->DllBase,(ULONG64)(Tmp->DllBase) + 0xa27e);
char buffer[] = { 0x90,0x90 };
MDLWriteMemory((ULONG64)(Tmp->DllBase) + 0xa27e, buffer, 2);
return;
}
LinkList = LinkList->Flink;
i++;
}


}

ULONG myReadFile(
_In_ HANDLE FileHandle,
_In_opt_ HANDLE Event,
_In_opt_ PIO_APC_ROUTINE ApcRoutine,
_In_opt_ PVOID ApcContext,
_Out_ PIO_STATUS_BLOCK IoStatusBlock,
_Out_writes_bytes_(Length) PVOID Buffer,
_In_ ULONG Length,
_In_opt_ PLARGE_INTEGER ByteOffset,
_In_opt_ PULONG Key) {

Unhook2();
FuncPtr2 func = (FuncPtr2)target2;

if (FileHandler && FileHandler == FileHandle) {
kprintf(("call NtReadFile(%p,%p,%p,%p,%p,%p,%p,%p,%p)\n"), FileHandle, Event, ApcRoutine, ApcContext, IoStatusBlock, Buffer, Length, ByteOffset, Key);
kprintf(("buffer in %p\n"), Buffer);
PatchInstr();
FileHandler = 0;
}
//DbgBreakPoint();
NTSTATUS s = func(FileHandle,Event,ApcRoutine,ApcContext,IoStatusBlock,Buffer,Length,ByteOffset,Key);

Hook2();

return s;


}

void DriverUnload(PDRIVER_OBJECT pDriver) {
kprintf(("Line %d:xia0ji233: start unload\n"), __LINE__);
Unhook();
Unhook2();
DeleteDevice(pDriver);
}


NTSTATUS DriverEntry(
_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath
) {
DriverObject->DriverUnload = DriverUnload;
kprintf(("Line %d:xia0ji233: RegistryPath = %S\n"), __LINE__, RegistryPath->Buffer);
target = NtCreateFile;
target2 = NtReadFile;
kprintf(("Line %d:xia0ji233: NtCreateFile=%p NtReadFile=%p\n"), __LINE__, target,target2);
g_Object = DriverObject;
if (target&&target2) {
for (int i = 0; i < sizeof(oldcode); i++) {
oldcode[i] = target[i];
oldcode2[i] = target2[i];
}
*(UINT64*)(newcode + 2) = myCreateFile;
*(UINT64*)(newcode2 + 2) = myReadFile;
Hook();
Hook2();
}
else {
kprintf(("xia0ji233:hahaha"));
}
return 0;
}

int Filter(ULONG Start)
{
LDR_DATA_TABLE_ENTRY *TE, *Tmp;
TE = (LDR_DATA_TABLE_ENTRY*)g_Object->DriverSection;
PLIST_ENTRY LinkList;
;
int i = 0;
LinkList = TE->InLoadOrderLinks.Flink;
while (LinkList != &TE->InLoadOrderLinks)
{
Tmp = (LDR_DATA_TABLE_ENTRY*)LinkList;
ULONG BASE = Tmp->DllBase;
ULONG Size = Tmp->SizeOfImage;
if (Start >= BASE && Start < BASE + Size) {
return 0;
}

LinkList = LinkList->Flink;
i++;
}

return 1;
}

可以看到,先加载我写的驱动,后加载题目驱动,无论 user-key 正确与否,都加载成功

于是这里把修改的函数套到文件读取里面去拦截,达到读该文件时遍历模块,找到指定模块则写入指令。

下面是真正的代码(编译文件为XSafe2.sys)

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
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
#include <ntifs.h>
#include <ntdef.h>
#include <ntstatus.h>
#include <ntddk.h>
#define kprintf(format, ...) DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, format, ##__VA_ARGS__)

typedef struct _CALLBACK_ENTRY
{
LIST_ENTRY CallbackList;
OB_OPERATION Operations;
ULONG Active;
PVOID Handle;
POBJECT_TYPE ObjectType;
POB_PRE_OPERATION_CALLBACK PreOperation;
POB_POST_OPERATION_CALLBACK PostOperation;
ULONG unknown;
} CALLBACK_ENTRY, *PCALLBACK_ENTRY;

typedef struct _LDR_DATA // 24 elements, 0xE0 bytes (sizeof)
{
/*0x000*/ struct _LIST_ENTRY InLoadOrderLinks; // 2 elements, 0x10 bytes (sizeof)
/*0x010*/ struct _LIST_ENTRY InMemoryOrderLinks; // 2 elements, 0x10 bytes (sizeof)
/*0x020*/ struct _LIST_ENTRY InInitializationOrderLinks; // 2 elements, 0x10 bytes (sizeof)
/*0x030*/ VOID* DllBase;
/*0x038*/ VOID* EntryPoint;
/*0x040*/ ULONG32 SizeOfImage;
/*0x044*/ UINT8 _PADDING0_[0x4];
/*0x048*/ struct _UNICODE_STRING FullDllName; // 3 elements, 0x10 bytes (sizeof)
/*0x058*/ struct _UNICODE_STRING BaseDllName; // 3 elements, 0x10 bytes (sizeof)
/*0x068*/ ULONG32 Flags;
/*0x06C*/ UINT16 LoadCount;
/*0x06E*/ UINT16 TlsIndex;
union // 2 elements, 0x10 bytes (sizeof)
{
/*0x070*/ struct _LIST_ENTRY HashLinks; // 2 elements, 0x10 bytes (sizeof)
struct // 2 elements, 0x10 bytes (sizeof)
{
/*0x070*/ VOID* SectionPointer;
/*0x078*/ ULONG32 CheckSum;
/*0x07C*/ UINT8 _PADDING1_[0x4];
};
};
union // 2 elements, 0x8 bytes (sizeof)
{
/*0x080*/ ULONG32 TimeDateStamp;
/*0x080*/ VOID* LoadedImports;
};
/*0x088*/ struct _ACTIVATION_CONTEXT* EntryPointActivationContext;
/*0x090*/ VOID* PatchInformation;
/*0x098*/ struct _LIST_ENTRY ForwarderLinks; // 2 elements, 0x10 bytes (sizeof)
/*0x0A8*/ struct _LIST_ENTRY ServiceTagLinks; // 2 elements, 0x10 bytes (sizeof)
/*0x0B8*/ struct _LIST_ENTRY StaticLinks; // 2 elements, 0x10 bytes (sizeof)
/*0x0C8*/ VOID* ContextInformation;
/*0x0D0*/ UINT64 OriginalBase;
/*0x0D8*/ union _LARGE_INTEGER LoadTime; // 4 elements, 0x8 bytes (sizeof)
}LDR_DATA, *PLDR_DATA;

typedef struct _OBJECT_TYPE_INITIALIZER // 25 elements, 0x70 bytes (sizeof)
{
/*0x000*/ UINT16 Length;
union // 2 elements, 0x1 bytes (sizeof)
{
/*0x002*/ UINT8 ObjectTypeFlags;
struct // 7 elements, 0x1 bytes (sizeof)
{
/*0x002*/ UINT8 CaseInsensitive : 1; // 0 BitPosition
/*0x002*/ UINT8 UnnamedObjectsOnly : 1; // 1 BitPosition
/*0x002*/ UINT8 UseDefaultObject : 1; // 2 BitPosition
/*0x002*/ UINT8 SecurityRequired : 1; // 3 BitPosition
/*0x002*/ UINT8 MaintainHandleCount : 1; // 4 BitPosition
/*0x002*/ UINT8 MaintainTypeList : 1; // 5 BitPosition
/*0x002*/ UINT8 SupportsObjectCallbacks : 1; // 6 BitPosition
};
};
/*0x004*/ ULONG32 ObjectTypeCode;
/*0x008*/ ULONG32 InvalidAttributes;
/*0x00C*/ struct _GENERIC_MAPPING GenericMapping; // 4 elements, 0x10 bytes (sizeof)
/*0x01C*/ ULONG32 ValidAccessMask;
/*0x020*/ ULONG32 RetainAccess;
/*0x024*/ enum _POOL_TYPE PoolType;
/*0x028*/ ULONG32 DefaultPagedPoolCharge;
/*0x02C*/ ULONG32 DefaultNonPagedPoolCharge;
/*0x030*/ PVOID DumpProcedure;
/*0x038*/ PVOID OpenProcedure;
/*0x040*/ PVOID CloseProcedure;
/*0x048*/ PVOID DeleteProcedure;
/*0x050*/ PVOID ParseProcedure;
/*0x058*/ PVOID SecurityProcedure;
/*0x060*/ PVOID QueryNameProcedure;
/*0x068*/ PVOID OkayToCloseProcedure;
}OBJECT_TYPE_INITIALIZER, *POBJECT_TYPE_INITIALIZER;

typedef struct _EX_PUSH_LOCK // 7 elements, 0x8 bytes (sizeof)
{
union // 3 elements, 0x8 bytes (sizeof)
{
struct // 5 elements, 0x8 bytes (sizeof)
{
/*0x000*/ UINT64 Locked : 1; // 0 BitPosition
/*0x000*/ UINT64 Waiting : 1; // 1 BitPosition
/*0x000*/ UINT64 Waking : 1; // 2 BitPosition
/*0x000*/ UINT64 MultipleShared : 1; // 3 BitPosition
/*0x000*/ UINT64 Shared : 60; // 4 BitPosition
};
/*0x000*/ UINT64 Value;
/*0x000*/ VOID* Ptr;
};
};

typedef struct _MY_OBJECT_TYPE // 12 elements, 0xD0 bytes (sizeof)
{
/*0x000*/ struct _LIST_ENTRY TypeList; // 2 elements, 0x10 bytes (sizeof)
/*0x010*/ struct _UNICODE_STRING Name; // 3 elements, 0x10 bytes (sizeof)
/*0x020*/ VOID* DefaultObject;
/*0x028*/ UINT8 Index;
/*0x029*/ UINT8 _PADDING0_[0x3];
/*0x02C*/ ULONG32 TotalNumberOfObjects;
/*0x030*/ ULONG32 TotalNumberOfHandles;
/*0x034*/ ULONG32 HighWaterNumberOfObjects;
/*0x038*/ ULONG32 HighWaterNumberOfHandles;
/*0x03C*/ UINT8 _PADDING1_[0x4];
/*0x040*/ struct _OBJECT_TYPE_INITIALIZER TypeInfo; // 25 elements, 0x70 bytes (sizeof)
/*0x0B0*/ struct _EX_PUSH_LOCK TypeLock; // 7 elements, 0x8 bytes (sizeof)
/*0x0B8*/ ULONG32 Key;
/*0x0BC*/ UINT8 _PADDING2_[0x4];
/*0x0C0*/ struct _LIST_ENTRY CallbackList; // 2 elements, 0x10 bytes (sizeof)
}MY_OBJECT_TYPE, *PMY_OBJECT_TYPE;


NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath);
VOID UnloadDriver(PDRIVER_OBJECT DriverObject);
NTSTATUS EnumerateKernelThreads();

typedef NTSTATUS (*ZWQUERYSYSTEMINFORMATION)(ULONG, PVOID, ULONG, PULONG);
typedef struct _SYSTEM_PROCESS_INFORMATION {
ULONG NextEntryOffset;
ULONG NumberOfThreads;
LARGE_INTEGER Reserved[3];
LARGE_INTEGER CreateTime;
LARGE_INTEGER UserTime;
LARGE_INTEGER KernelTime;
UNICODE_STRING ImageName;
ULONG BasePriority;
HANDLE ProcessId;
HANDLE InheritedFromProcessId;
} SYSTEM_PROCESS_INFORMATION, *PSYSTEM_PROCESS_INFORMATION;
typedef struct _SYSTEM_THREAD_INFORMATION {
LARGE_INTEGER KernelTime;
LARGE_INTEGER UserTime;
LARGE_INTEGER CreateTime;
ULONG WaitTime;
PVOID StartAddress;
CLIENT_ID ClientId;
ULONG Priority;
LONG BasePriority;
ULONG ContextSwitchCount;
LONG State;
LONG WaitReason;
} SYSTEM_THREAD_INFORMATION, *PSYSTEM_THREAD_INFORMATION;
typedef enum _SYSTEM_INFORMATION_CLASS {
SystemProcessInformation = 5
} SYSTEM_INFORMATION_CLASS;
#define SystemModuleInformation 11



PVOID obHandle;
DRIVER_INITIALIZE DriverEntry;

PDRIVER_OBJECT g_Object = NULL;
typedef struct _LDR_DATA_TABLE_ENTRY {
LIST_ENTRY InLoadOrderLinks;
LIST_ENTRY InMemoryOrderLinks;
LIST_ENTRY InInitializationOrderLinks;
PVOID DllBase;
PVOID EntryPoint;//驱动的进入点 DriverEntry
ULONG SizeOfImage;
UNICODE_STRING FullDllName;//驱动的满路径
UNICODE_STRING BaseDllName;//不带路径的驱动名字
ULONG Flags;
USHORT LoadCount;
USHORT TlsIndex;
union {
LIST_ENTRY HashLinks;
struct {
PVOID SectionPointer;
ULONG CheckSum;
};
};
union {
struct {
ULONG TimeDateStamp;
};
struct {
PVOID LoadedImports;
};
};
} LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;


MDLWriteMemory(PVOID pBaseAddress, PVOID pWriteData, SIZE_T writeDataSize)
{
PMDL pMdl = NULL;
PVOID pNewAddress = NULL;
pMdl = MmCreateMdl(NULL, pBaseAddress, writeDataSize);
if (NULL == pMdl)
{
return FALSE;
}
MmBuildMdlForNonPagedPool(pMdl);
pNewAddress = MmMapLockedPages(pMdl, KernelMode);
if (NULL == pNewAddress)
{
IoFreeMdl(pMdl);
}
RtlCopyMemory(pNewAddress, pWriteData, writeDataSize);
MmUnmapLockedPages(pNewAddress, pMdl);
IoFreeMdl(pMdl);
return TRUE;
}


VOID PatchInstr()
{
LDR_DATA_TABLE_ENTRY *TE, *Tmp;
TE = (LDR_DATA_TABLE_ENTRY*)g_Object->DriverSection;
PLIST_ENTRY LinkList;
;
int i = 0;
LinkList = TE->InLoadOrderLinks.Flink;
UNICODE_STRING name;
RtlInitUnicodeString(&name,L"Loader.sys");
;
while (LinkList != &TE->InLoadOrderLinks)
{
Tmp = (LDR_DATA_TABLE_ENTRY*)LinkList;
if (RtlEqualUnicodeString(&Tmp->BaseDllName, &name,FALSE)) {
kprintf(("DLLname:%S DLLBase=%p nowcode=%p\n"), Tmp->BaseDllName.Buffer,Tmp->DllBase,(ULONG64)(Tmp->DllBase) + 0xa27e);
char buffer[] = { 0x90,0x90 };
MDLWriteMemory((ULONG64)(Tmp->DllBase) + 0xa27e, buffer, 2);
return;
}
LinkList = LinkList->Flink;
i++;
}
}

// 文件回调
OB_PREOP_CALLBACK_STATUS FileObjectpreCall(PVOID RegistrationContext, POB_PRE_OPERATION_INFORMATION OperationInformation)
{
UNICODE_STRING DosName;
PFILE_OBJECT fileo = OperationInformation->Object;
HANDLE CurrentProcessId = PsGetCurrentProcessId();
UNREFERENCED_PARAMETER(RegistrationContext);

if (OperationInformation->ObjectType != *IoFileObjectType)
{
return OB_PREOP_SUCCESS;
}

// 过滤无效指针
if (fileo->FileName.Buffer == NULL ||
!MmIsAddressValid(fileo->FileName.Buffer) ||
fileo->DeviceObject == NULL ||
!MmIsAddressValid(fileo->DeviceObject))
{
return OB_PREOP_SUCCESS;
}

// 过滤无效路径
if (!_wcsicmp(fileo->FileName.Buffer, L"\\Endpoint") ||
!_wcsicmp(fileo->FileName.Buffer, L"?") ||
!_wcsicmp(fileo->FileName.Buffer, L"\\.\\.") ||
!_wcsicmp(fileo->FileName.Buffer, L"\\"))
{
return OB_PREOP_SUCCESS;
}

// 将对象转为DOS路径
RtlVolumeDeviceToDosName(fileo->DeviceObject, &DosName);



if (!wcscmp(fileo->FileName.Buffer, L"\\card.txt")) {
PETHREAD pct=PsGetCurrentThread();
PVOID addr=*(ULONG64*)((char*)pct + 0x450);
PatchInstr();

//EnumerateKernelThreads();
DbgBreakPoint();
}



return OB_PREOP_SUCCESS;
}

VOID EnableObType(POBJECT_TYPE ObjectType)
{
PMY_OBJECT_TYPE myobtype = (PMY_OBJECT_TYPE)ObjectType;
myobtype->TypeInfo.SupportsObjectCallbacks = 1;
}

VOID UnDriver(PDRIVER_OBJECT driver)
{
UNREFERENCED_PARAMETER(driver);
ObUnRegisterCallbacks(obHandle);
}

NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{
NTSTATUS status = STATUS_SUCCESS;
PLDR_DATA ldr;

kprintf(("hello xia0ji233\n"));
g_Object = Driver;
OB_CALLBACK_REGISTRATION obRegFileCallBack;
OB_OPERATION_REGISTRATION opRegFileCallBack;

// enable IoFileObjectType
EnableObType(*IoFileObjectType);

// bypass MmVerifyCallbackFunction
ldr = (PLDR_DATA)Driver->DriverSection;
ldr->Flags |= 0x20;

// 初始化回调
memset(&obRegFileCallBack, 0, sizeof(obRegFileCallBack));
obRegFileCallBack.Version = ObGetFilterVersion();
obRegFileCallBack.OperationRegistrationCount = 1;
obRegFileCallBack.RegistrationContext = NULL;
RtlInitUnicodeString(&obRegFileCallBack.Altitude, L"321000");
obRegFileCallBack.OperationRegistration = &opRegFileCallBack;

memset(&opRegFileCallBack, 0, sizeof(opRegFileCallBack));
opRegFileCallBack.ObjectType = IoFileObjectType;
opRegFileCallBack.Operations = OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE;
opRegFileCallBack.PreOperation = (POB_PRE_OPERATION_CALLBACK)&FileObjectpreCall;

status = ObRegisterCallbacks(&obRegFileCallBack, &obHandle);
if (!NT_SUCCESS(status))
{
kprintf(("注册回调错误 \n"));
status = STATUS_UNSUCCESSFUL;
}

UNREFERENCED_PARAMETER(RegistryPath);
Driver->DriverUnload = &UnDriver;
return status;
}

该程序(附件中的XSafe2.sys)先加载,再加载Loader.sys同样可以任意user key加载成功并且不hook任何系统API和文件。

分析shellcode反复在读取哪个内存地址(2分)

shellcode加载之后,会检测双机调试

但是有一定的延迟,说明是主动检测的不是被动触发的,刚好遇上这个题,猜测是检测了一个调试器标志位。

不过这里感觉是得先确定一下 shellcode 的位置的,因为它带反调,不知道它怎么反调的,突然想到之前一位神仙把蓝屏代码删了导致电脑爆炸,于是我也想效仿一下看看可不可彳亍。

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
#include <ntifs.h>
#include <ntdef.h>
#include <ntstatus.h>
#include <ntddk.h>
#define MAX_BACKTRACE_DEPTH 20
#define SYMBOL L"\\??\\xia0ji2333"
#define kprintf(format, ...) DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, format, ##__VA_ARGS__)

UINT64 BaseAddr=NULL, DLLSize=0;
#define MAX_BACKTRACE_DEPTH 20

void DeleteDevice(PDRIVER_OBJECT pDriver) {
kprintf(("Line %d:xia0ji233: start delete device\n"), __LINE__);
if (pDriver->DeviceObject) {
UNICODE_STRING Sym;
RtlInitUnicodeString(&Sym, SYMBOL);//CreateFile
kprintf(("Line %d:xia0ji233: Delete Symbol\n"), __LINE__);
IoDeleteSymbolicLink(&Sym);
kprintf(("Line %d:xia0ji233: Delete Device\n"), __LINE__);
IoDeleteDevice(pDriver->DeviceObject);
}
kprintf(("Line %d:xia0ji233: end delete device\n"), __LINE__);
}

HANDLE FileHandler = NULL;

char newcode[] = {
0x48,0xB8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//mov rax,xxx
0xFF,0xE0//jmp rax
};
char oldcode[] = {
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,
};


char* target;
KIRQL WPOFFx64()
{
KIRQL irql = KeRaiseIrqlToDpcLevel();
UINT64 cr0 = __readcr0();
cr0 &= 0xfffffffffffeffff;
__writecr0(cr0);
_disable();
return irql;
}

void WPONx64(KIRQL irql)
{
UINT64 cr0 = __readcr0();
cr0 |= 0x10000;
_enable();
__writecr0(cr0);
KeLowerIrql(irql);
}

NTSTATUS Unhook() {
KIRQL irql = WPOFFx64();
for (int i = 0; i < sizeof(newcode); i++) {
target[i] = oldcode[i];
}
WPONx64(irql);
return STATUS_SUCCESS;
}



NTSTATUS Hook() {
KIRQL irql = WPOFFx64();
for (int i = 0; i < sizeof(newcode); i++) {
target[i] = newcode[i];
}
WPONx64(irql);
return STATUS_SUCCESS;
}


PDRIVER_OBJECT g_Object = NULL;
typedef struct _LDR_DATA_TABLE_ENTRY {
LIST_ENTRY InLoadOrderLinks;
LIST_ENTRY InMemoryOrderLinks;
LIST_ENTRY InInitializationOrderLinks;
PVOID DllBase;
PVOID EntryPoint;//驱动的进入点 DriverEntry
ULONG SizeOfImage;
UNICODE_STRING FullDllName;//驱动的满路径
UNICODE_STRING BaseDllName;//不带路径的驱动名字
ULONG Flags;
USHORT LoadCount;
USHORT TlsIndex;
union {
LIST_ENTRY HashLinks;
struct {
PVOID SectionPointer;
ULONG CheckSum;
};
};
union {
struct {
ULONG TimeDateStamp;
};
struct {
PVOID LoadedImports;
};
};
} LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;



typedef NTSTATUS (* FuncPtr) (
_In_ ULONG BugCheckCode,
_In_ ULONG_PTR BugCheckParameter1,
_In_ ULONG_PTR BugCheckParameter2,
_In_ ULONG_PTR BugCheckParameter3,
_In_ ULONG_PTR BugCheckParameter4
);


ULONG myKeBugCheckEx(_In_ ULONG BugCheckCode,
_In_ ULONG_PTR BugCheckParameter1,
_In_ ULONG_PTR BugCheckParameter2,
_In_ ULONG_PTR BugCheckParameter3,
_In_ ULONG_PTR BugCheckParameter4
) {


Unhook();
FuncPtr func = (FuncPtr)target;

PVOID backtrace[MAX_BACKTRACE_DEPTH];
USHORT capturedFrames = RtlCaptureStackBackTrace(0, MAX_BACKTRACE_DEPTH, backtrace, NULL);
for (USHORT i = 0; i < capturedFrames; i++) {
kprintf(("xia0ji233:Backtrace[%u]: %p\n"), i, backtrace[i]);
}

kprintf(("calling KeBugCheckEx(%p,%p,%p,%p,%p)\n"),BugCheckCode,BugCheckParameter1,BugCheckParameter2,BugCheckParameter3,BugCheckParameter4);
DbgBreakPoint();
LARGE_INTEGER inTime;
inTime.QuadPart = (LONGLONG) - 10 * 1000 * 1000 * 3600;
KeDelayExecutionThread(KernelMode, FALSE, &inTime);

ULONG64 s = func(BugCheckCode,BugCheckParameter1,BugCheckParameter2,BugCheckParameter3,BugCheckParameter4);
Hook();

return s;
}

MDLWriteMemory(PVOID pBaseAddress, PVOID pWriteData, SIZE_T writeDataSize)
{
PMDL pMdl = NULL;
PVOID pNewAddress = NULL;
pMdl = MmCreateMdl(NULL, pBaseAddress, writeDataSize);
if (NULL == pMdl)
{
return FALSE;
}
MmBuildMdlForNonPagedPool(pMdl);
pNewAddress = MmMapLockedPages(pMdl, KernelMode);
if (NULL == pNewAddress)
{
IoFreeMdl(pMdl);
}
RtlCopyMemory(pNewAddress, pWriteData, writeDataSize);
MmUnmapLockedPages(pNewAddress, pMdl);
IoFreeMdl(pMdl);
return TRUE;
}
void DriverUnload(PDRIVER_OBJECT pDriver) {
kprintf(("Line %d:xia0ji233: start unload\n"), __LINE__);
Unhook();
DeleteDevice(pDriver);
}


NTSTATUS DriverEntry(
_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath
) {
DriverObject->DriverUnload = DriverUnload;
kprintf(("Line %d:xia0ji233: RegistryPath = %S\n"), __LINE__, RegistryPath->Buffer);
UNICODE_STRING unName = { 0 };
RtlInitUnicodeString(&unName, L"KeBugCheckEx");
target = ((ULONG64)MmGetSystemRoutineAddress(&unName))+5;
kprintf(("Line %d:xia0ji233: KeBugCheckEx=%p\n"), __LINE__, target);
g_Object = DriverObject;
if (target) {
for (int i = 0; i < sizeof(oldcode); i++) {
oldcode[i] = target[i];
}
*(UINT64*)(newcode + 2) = myKeBugCheckEx;
Hook();

}
else {
kprintf(("xia0ji233:hahaha"));
}
return 0;
}

这里去hook KeBugCheckEx,然后直接让它 sleep 一小时,防止它蓝我,我有更多时间可以去分析。

直接拿捏住了蓝屏。

在后面的分析中发现了 GameSec.exe 的内存一直在被读,估计是在搜索进程,然后读取进程的内存,这一部分后面没有分析太出来。

并且在运行的时候发现会读一些 exe 文件的字符串,在 shellcode 开头 + 80 的位置,这里后续没继续分析了。

编写一个search程序,在Load驱动运行后找到内核内存空间中的shellcode,输出shellcode范围内的任意地址

随后想到去dump shellcode,这里注册回调的方式并不能成功拦截住,因此想到直接去 hook,判断线程起始位置是否在模块范围内,或者说在 Loader.sys 范围内,如果有都输出然后调试器看看内存像不像shellcode,无果,于是选择去跟一下,结果跟到一个类似shellcode的地方(很多浮点指令,看起来像垃圾指令的混淆),dump下来用 010 分析。

方法1

通过内存地址的特征可以发现,前八位可以通过 VAD 的方式去获取,后四个位每次加载似乎都是固定的,因此只需要爆破两个字节用一个特征去匹配就行了,这里。

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
#include "vad.h"
#include <ntifs.h>
#define kprintf(format, ...) DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, format, ##__VA_ARGS__)
// 定义VAD相对于EProcess头部偏移值
#define eprocess_offset_VadRoot 0x658
#define eprocess_offset_VadCount 0x668

VOID EnumVad(PMMVAD Root, PALL_VADS pBuffer, ULONG nCnt)
{
if (!Root || !pBuffer || !nCnt)
{
return;
}

__try
{
if (nCnt > pBuffer->nCnt)
{
// 得到起始页与结束页
ULONG64 endptr = (ULONG64)Root->Core.EndingVpnHigh;
endptr = endptr << 32;

ULONG64 startptr = (ULONG64)Root->Core.StartingVpnHigh;
startptr = startptr << 32;

// 得到根节点
pBuffer->VadInfos[pBuffer->nCnt].pVad = (ULONG_PTR)Root;

// 起始页: startingVpn * 0x1000
pBuffer->VadInfos[pBuffer->nCnt].startVpn = (startptr | Root->Core.StartingVpn) << PAGE_SHIFT;

// 结束页: EndVpn * 0x1000 + 0xfff
pBuffer->VadInfos[pBuffer->nCnt].endVpn = ((endptr | Root->Core.EndingVpn) << PAGE_SHIFT) + 0xfff;

// VAD标志 928 = Mapped 1049088 = Private ....
pBuffer->VadInfos[pBuffer->nCnt].flags = Root->Core.u1.Flags.flag;

// 验证节点可读性
if (MmIsAddressValid(Root->Subsection) && MmIsAddressValid(Root->Subsection->ControlArea))
{
if (MmIsAddressValid((PVOID)((Root->Subsection->ControlArea->FilePointer.Value >> 4) << 4)))
{
pBuffer->VadInfos[pBuffer->nCnt].pFileObject = ((Root->Subsection->ControlArea->FilePointer.Value >> 4) << 4);
}
}
pBuffer->nCnt++;
}

if (MmIsAddressValid(Root->Core.VadNode.Left))
{
// 递归枚举左子树
EnumVad((PMMVAD)Root->Core.VadNode.Left, pBuffer, nCnt);
}

if (MmIsAddressValid(Root->Core.VadNode.Right))
{
// 递归枚举右子树
EnumVad((PMMVAD)Root->Core.VadNode.Right, pBuffer, nCnt);
}
}
__except (1)
{
}
}

BOOLEAN EnumProcessVad(ULONG Pid, PALL_VADS pBuffer, ULONG nCnt)
{
PEPROCESS Peprocess = 0;
PRTL_AVL_TREE Table = NULL;
PMMVAD Root = NULL;

// 通过进程PID得到进程EProcess
if (NT_SUCCESS(PsLookupProcessByProcessId((HANDLE)Pid, &Peprocess)))
{
// 与偏移相加得到VAD头节点
Table = (PRTL_AVL_TREE)((UCHAR*)Peprocess + eprocess_offset_VadRoot);
if (!MmIsAddressValid(Table) || !eprocess_offset_VadRoot)
{
return FALSE;
}

__try
{
// 取出头节点
Root = (PMMVAD)Table->Root;

if (nCnt > pBuffer->nCnt)
{
// 得到起始页与结束页
ULONG64 endptr = (ULONG64)Root->Core.EndingVpnHigh;
endptr = endptr << 32;

ULONG64 startptr = (ULONG64)Root->Core.StartingVpnHigh;
startptr = startptr << 32;

pBuffer->VadInfos[pBuffer->nCnt].pVad = (ULONG_PTR)Root;

// 起始页: startingVpn * 0x1000
pBuffer->VadInfos[pBuffer->nCnt].startVpn = (startptr | Root->Core.StartingVpn) << PAGE_SHIFT;

// 结束页: EndVpn * 0x1000 + 0xfff
pBuffer->VadInfos[pBuffer->nCnt].endVpn = (endptr | Root->Core.EndingVpn) << PAGE_SHIFT;
pBuffer->VadInfos[pBuffer->nCnt].flags = Root->Core.u1.Flags.flag;

if (MmIsAddressValid(Root->Subsection) && MmIsAddressValid(Root->Subsection->ControlArea))
{
if (MmIsAddressValid((PVOID)((Root->Subsection->ControlArea->FilePointer.Value >> 4) << 4)))
{
pBuffer->VadInfos[pBuffer->nCnt].pFileObject = ((Root->Subsection->ControlArea->FilePointer.Value >> 4) << 4);
}
}
pBuffer->nCnt++;
}

// 枚举左子树
if (Table->Root->Left)
{
EnumVad((MMVAD*)Table->Root->Left, pBuffer, nCnt);
}

// 枚举右子树
if (Table->Root->Right)
{
EnumVad((MMVAD*)Table->Root->Right, pBuffer, nCnt);
}
}
__finally
{
ObDereferenceObject(Peprocess);
}
}
else
{
return FALSE;
}

return TRUE;
}

VOID UnDriver(PDRIVER_OBJECT driver)
{
kprintf(("unload\n"));
}

NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{
kprintf(("hello xia0ji233\n"));

typedef struct
{
ULONG nPid;
ULONG nSize;
PALL_VADS pBuffer;
}VADProcess;

__try
{
VADProcess vad = { 0 };

vad.nPid = 4;

// 默认有1000个线程
vad.nSize = sizeof(VAD_INFO) * 0x5000 + sizeof(ULONG);

// 分配临时空间
vad.pBuffer = (PALL_VADS)ExAllocatePool(PagedPool, vad.nSize);

// 根据传入长度得到枚举数量
ULONG nCount = (vad.nSize - sizeof(ULONG)) / sizeof(VAD_INFO);

// 枚举VAD
EnumProcessVad(vad.nPid, vad.pBuffer, nCount);

uintptr_t addr;

for (ULONG64 i = 0x0; i <65536; i++)
{
addr = vad.pBuffer->VadInfos[0].pVad & 0xffffffff00000000;
addr = addr + 0x1000;
addr = addr + (i<<16);
if (MmIsAddressValid((PVOID)addr) && *((ULONG64 *)addr) == 0x7C8B483024748B48 )
{
kprintf(("shellcode found in %p\n"), addr);
//DbgBreakPoint();
goto end;
}

}
}
__except (1)

{
kprintf(("Something Error1\n"));
}
end:
Driver->DriverUnload = UnDriver;
return STATUS_SUCCESS;
}

vad.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
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
#pragma once
#include <ntifs.h>

typedef struct _MM_GRAPHICS_VAD_FLAGS // 15 elements, 0x4 bytes (sizeof)
{
/*0x000*/ ULONG32 Lock : 1; // 0 BitPosition
/*0x000*/ ULONG32 LockContended : 1; // 1 BitPosition
/*0x000*/ ULONG32 DeleteInProgress : 1; // 2 BitPosition
/*0x000*/ ULONG32 NoChange : 1; // 3 BitPosition
/*0x000*/ ULONG32 VadType : 3; // 4 BitPosition
/*0x000*/ ULONG32 Protection : 5; // 7 BitPosition
/*0x000*/ ULONG32 PreferredNode : 6; // 12 BitPosition
/*0x000*/ ULONG32 PageSize : 2; // 18 BitPosition
/*0x000*/ ULONG32 PrivateMemoryAlwaysSet : 1; // 20 BitPosition
/*0x000*/ ULONG32 WriteWatch : 1; // 21 BitPosition
/*0x000*/ ULONG32 FixedLargePageSize : 1; // 22 BitPosition
/*0x000*/ ULONG32 ZeroFillPagesOptional : 1; // 23 BitPosition
/*0x000*/ ULONG32 GraphicsAlwaysSet : 1; // 24 BitPosition
/*0x000*/ ULONG32 GraphicsUseCoherentBus : 1; // 25 BitPosition
/*0x000*/ ULONG32 GraphicsPageProtection : 3; // 26 BitPosition
}MM_GRAPHICS_VAD_FLAGS, * PMM_GRAPHICS_VAD_FLAGS;
typedef struct _MM_PRIVATE_VAD_FLAGS // 15 elements, 0x4 bytes (sizeof)
{
/*0x000*/ ULONG32 Lock : 1; // 0 BitPosition
/*0x000*/ ULONG32 LockContended : 1; // 1 BitPosition
/*0x000*/ ULONG32 DeleteInProgress : 1; // 2 BitPosition
/*0x000*/ ULONG32 NoChange : 1; // 3 BitPosition
/*0x000*/ ULONG32 VadType : 3; // 4 BitPosition
/*0x000*/ ULONG32 Protection : 5; // 7 BitPosition
/*0x000*/ ULONG32 PreferredNode : 6; // 12 BitPosition
/*0x000*/ ULONG32 PageSize : 2; // 18 BitPosition
/*0x000*/ ULONG32 PrivateMemoryAlwaysSet : 1; // 20 BitPosition
/*0x000*/ ULONG32 WriteWatch : 1; // 21 BitPosition
/*0x000*/ ULONG32 FixedLargePageSize : 1; // 22 BitPosition
/*0x000*/ ULONG32 ZeroFillPagesOptional : 1; // 23 BitPosition
/*0x000*/ ULONG32 Graphics : 1; // 24 BitPosition
/*0x000*/ ULONG32 Enclave : 1; // 25 BitPosition
/*0x000*/ ULONG32 ShadowStack : 1; // 26 BitPosition
}MM_PRIVATE_VAD_FLAGS, * PMM_PRIVATE_VAD_FLAGS;


typedef struct _MMVAD_FLAGS // 9 elements, 0x4 bytes (sizeof)
{
/*0x000*/ ULONG32 Lock : 1; // 0 BitPosition
/*0x000*/ ULONG32 LockContended : 1; // 1 BitPosition
/*0x000*/ ULONG32 DeleteInProgress : 1; // 2 BitPosition
/*0x000*/ ULONG32 NoChange : 1; // 3 BitPosition
/*0x000*/ ULONG32 VadType : 3; // 4 BitPosition
/*0x000*/ ULONG32 Protection : 5; // 7 BitPosition
/*0x000*/ ULONG32 PreferredNode : 6; // 12 BitPosition
/*0x000*/ ULONG32 PageSize : 2; // 18 BitPosition
/*0x000*/ ULONG32 PrivateMemory : 1; // 20 BitPosition
}MMVAD_FLAGS, * PMMVAD_FLAGS;

typedef struct _MM_SHARED_VAD_FLAGS // 11 elements, 0x4 bytes (sizeof)
{
/*0x000*/ ULONG32 Lock : 1; // 0 BitPosition
/*0x000*/ ULONG32 LockContended : 1; // 1 BitPosition
/*0x000*/ ULONG32 DeleteInProgress : 1; // 2 BitPosition
/*0x000*/ ULONG32 NoChange : 1; // 3 BitPosition
/*0x000*/ ULONG32 VadType : 3; // 4 BitPosition
/*0x000*/ ULONG32 Protection : 5; // 7 BitPosition
/*0x000*/ ULONG32 PreferredNode : 6; // 12 BitPosition
/*0x000*/ ULONG32 PageSize : 2; // 18 BitPosition
/*0x000*/ ULONG32 PrivateMemoryAlwaysClear : 1; // 20 BitPosition
/*0x000*/ ULONG32 PrivateFixup : 1; // 21 BitPosition
/*0x000*/ ULONG32 HotPatchAllowed : 1; // 22 BitPosition
}MM_SHARED_VAD_FLAGS, * PMM_SHARED_VAD_FLAGS;

typedef struct _MMVAD_FLAGS2 // 7 elements, 0x4 bytes (sizeof)
{
/*0x000*/ ULONG32 FileOffset : 24; // 0 BitPosition
/*0x000*/ ULONG32 Large : 1; // 24 BitPosition
/*0x000*/ ULONG32 TrimBehind : 1; // 25 BitPosition
/*0x000*/ ULONG32 Inherit : 1; // 26 BitPosition
/*0x000*/ ULONG32 NoValidationNeeded : 1; // 27 BitPosition
/*0x000*/ ULONG32 PrivateDemandZero : 1; // 28 BitPosition
/*0x000*/ ULONG32 Spare : 3; // 29 BitPosition
}MMVAD_FLAGS2, * PMMVAD_FLAGS2;

typedef struct _MMVAD_SHORT
{
RTL_BALANCED_NODE VadNode;
UINT32 StartingVpn; /*0x18*/
UINT32 EndingVpn; /*0x01C*/
UCHAR StartingVpnHigh;
UCHAR EndingVpnHigh;
UCHAR CommitChargeHigh;
UCHAR SpareNT64VadUChar;
INT32 ReferenceCount;
EX_PUSH_LOCK PushLock; /*0x028*/
struct
{
union
{
ULONG_PTR flag;
MM_PRIVATE_VAD_FLAGS PrivateVadFlags; /*0x030*/
MMVAD_FLAGS VadFlags;
MM_GRAPHICS_VAD_FLAGS GraphicsVadFlags;
MM_SHARED_VAD_FLAGS SharedVadFlags;
}Flags;

}u1;

PVOID EventList; /*0x038*/

}MMVAD_SHORT, * PMMVAD_SHORT;

typedef struct _MMADDRESS_NODE
{
ULONG64 u1;
struct _MMADDRESS_NODE* LeftChild;
struct _MMADDRESS_NODE* RightChild;
ULONG64 StartingVpn;
ULONG64 EndingVpn;
}MMADDRESS_NODE, * PMMADDRESS_NODE;

typedef struct _MMEXTEND_INFO // 2 elements, 0x10 bytes (sizeof)
{
/*0x000*/ UINT64 CommittedSize;
/*0x008*/ ULONG32 ReferenceCount;
/*0x00C*/ UINT8 _PADDING0_[0x4];
}MMEXTEND_INFO, * PMMEXTEND_INFO;
struct _SEGMENT
{
struct _CONTROL_AREA* ControlArea;
ULONG TotalNumberOfPtes;
ULONG SegmentFlags;
ULONG64 NumberOfCommittedPages;
ULONG64 SizeOfSegment;
union
{
struct _MMEXTEND_INFO* ExtendInfo;
void* BasedAddress;
}u;
ULONG64 SegmentLock;
ULONG64 u1;
ULONG64 u2;
PVOID* PrototypePte;
ULONGLONG ThePtes[0x1];
};

typedef struct _EX_FAST_REF
{
union
{
PVOID Object;
ULONG_PTR RefCnt : 3;
ULONG_PTR Value;
};
} EX_FAST_REF, * PEX_FAST_REF;

typedef struct _CONTROL_AREA // 17 elements, 0x80 bytes (sizeof)
{
/*0x000*/ struct _SEGMENT* Segment;
union // 2 elements, 0x10 bytes (sizeof)
{
/*0x008*/ struct _LIST_ENTRY ListHead; // 2 elements, 0x10 bytes (sizeof)
/*0x008*/ VOID* AweContext;
};
/*0x018*/ UINT64 NumberOfSectionReferences;
/*0x020*/ UINT64 NumberOfPfnReferences;
/*0x028*/ UINT64 NumberOfMappedViews;
/*0x030*/ UINT64 NumberOfUserReferences;
/*0x038*/ ULONG32 u; // 2 elements, 0x4 bytes (sizeof)
/*0x03C*/ ULONG32 u1; // 2 elements, 0x4 bytes (sizeof)
/*0x040*/ struct _EX_FAST_REF FilePointer; // 3 elements, 0x8 bytes (sizeof)
// 4 elements, 0x8 bytes (sizeof)
}CONTROL_AREA, * PCONTROL_AREA;

typedef struct _SUBSECTION_
{
struct _CONTROL_AREA* ControlArea;

}SUBSECTION, * PSUBSECTION;

typedef struct _MMVAD
{
MMVAD_SHORT Core;
union /*0x040*/
{
UINT32 LongFlags2;
//现在用不到省略
MMVAD_FLAGS2 VadFlags2;

}u2;
PSUBSECTION Subsection; /*0x048*/
PVOID FirstPrototypePte; /*0x050*/
PVOID LastContiguousPte; /*0x058*/
LIST_ENTRY ViewLinks; /*0x060*/
PEPROCESS VadsProcess; /*0x070*/
PVOID u4; /*0x078*/
PVOID FileObject; /*0x080*/
}MMVAD, * PMMVAD;

typedef struct _RTL_AVL_TREE // 1 elements, 0x8 bytes (sizeof)
{
/*0x000*/ struct _RTL_BALANCED_NODE* Root;
}RTL_AVL_TREE, * PRTL_AVL_TREE;

typedef struct _VAD_INFO_
{
ULONG_PTR pVad;
ULONG_PTR startVpn;
ULONG_PTR endVpn;
ULONG_PTR pFileObject;
ULONG_PTR flags;
}VAD_INFO, * PVAD_INFO;

typedef struct _ALL_VADS_
{
ULONG nCnt;
VAD_INFO VadInfos[1];
}ALL_VADS, * PALL_VADS;

typedef struct _MMSECTION_FLAGS // 27 elements, 0x4 bytes (sizeof)
{
/*0x000*/ UINT32 BeingDeleted : 1; // 0 BitPosition
/*0x000*/ UINT32 BeingCreated : 1; // 1 BitPosition
/*0x000*/ UINT32 BeingPurged : 1; // 2 BitPosition
/*0x000*/ UINT32 NoModifiedWriting : 1; // 3 BitPosition
/*0x000*/ UINT32 FailAllIo : 1; // 4 BitPosition
/*0x000*/ UINT32 Image : 1; // 5 BitPosition
/*0x000*/ UINT32 Based : 1; // 6 BitPosition
/*0x000*/ UINT32 File : 1; // 7 BitPosition
/*0x000*/ UINT32 AttemptingDelete : 1; // 8 BitPosition
/*0x000*/ UINT32 PrefetchCreated : 1; // 9 BitPosition
/*0x000*/ UINT32 PhysicalMemory : 1; // 10 BitPosition
/*0x000*/ UINT32 ImageControlAreaOnRemovableMedia : 1; // 11 BitPosition
/*0x000*/ UINT32 Reserve : 1; // 12 BitPosition
/*0x000*/ UINT32 Commit : 1; // 13 BitPosition
/*0x000*/ UINT32 NoChange : 1; // 14 BitPosition
/*0x000*/ UINT32 WasPurged : 1; // 15 BitPosition
/*0x000*/ UINT32 UserReference : 1; // 16 BitPosition
/*0x000*/ UINT32 GlobalMemory : 1; // 17 BitPosition
/*0x000*/ UINT32 DeleteOnClose : 1; // 18 BitPosition
/*0x000*/ UINT32 FilePointerNull : 1; // 19 BitPosition
/*0x000*/ ULONG32 PreferredNode : 6; // 20 BitPosition
/*0x000*/ UINT32 GlobalOnlyPerSession : 1; // 26 BitPosition
/*0x000*/ UINT32 UserWritable : 1; // 27 BitPosition
/*0x000*/ UINT32 SystemVaAllocated : 1; // 28 BitPosition
/*0x000*/ UINT32 PreferredFsCompressionBoundary : 1; // 29 BitPosition
/*0x000*/ UINT32 UsingFileExtents : 1; // 30 BitPosition
/*0x000*/ UINT32 PageSize64K : 1; // 31 BitPosition
}MMSECTION_FLAGS, * PMMSECTION_FLAGS;

typedef struct _SECTION // 9 elements, 0x40 bytes (sizeof)
{
/*0x000*/ struct _RTL_BALANCED_NODE SectionNode; // 6 elements, 0x18 bytes (sizeof)
/*0x018*/ UINT64 StartingVpn;
/*0x020*/ UINT64 EndingVpn;
/*0x028*/ union {
PCONTROL_AREA ControlArea;
PVOID FileObject;

}u1; // 4 elements, 0x8 bytes (sizeof)
/*0x030*/ UINT64 SizeOfSection;
/*0x038*/ union {
ULONG32 LongFlags;
MMSECTION_FLAGS Flags;
}u; // 2 elements, 0x4 bytes (sizeof)
struct // 3 elements, 0x4 bytes (sizeof)
{
/*0x03C*/ ULONG32 InitialPageProtection : 12; // 0 BitPosition
/*0x03C*/ ULONG32 SessionId : 19; // 12 BitPosition
/*0x03C*/ ULONG32 NoValidationNeeded : 1; // 31 BitPosition
};
}SECTION, * PSECTION;

先加载 loader 再加载 search,成功输出 shellcode 的地址,特征码匹配前八个字节,在自己的环境只输出了一个地址,如果输出多个地址可以考虑加长特征码。

方法2

通过获取到线程结构得到它的线程上下文,输出 RIP 的值应该也行,通过PCHUNTER看到shellcode运行的线程

通过分析可知 shellcode 执行的线程具有如下特点:

与 TID=12 的线程入口相同

保持运行状态

据此可以筛选得到这个线程,通过线程结构体可以找到它的栈

多次运行发现栈中存在 GameSec.exe 这个字符串。并且在它 - 0x28 的位置有一个地址,那个地址前八位和shellcode一致,所以同样可以爆破+特征码匹配。

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
#include<ntifs.h> 
#include <ntddk.h>
#include <ntstrsafe.h>

#define kprintf(format, ...) DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, format, ##__VA_ARGS__)
#define MAX_BACKTRACE_DEPTH 20
ULONG64 num = 0;
NTSTATUS EnumerateKernelThreads();

typedef NTSTATUS (*ZWQUERYSYSTEMINFORMATION)(ULONG, PVOID, ULONG, PULONG);

VOID DRIVERUNLOAD(_In_ struct _DRIVER_OBJECT* DriverObject)
{
kprintf(("unload\n"));

}


NTSTATUS EnumerateKernelThreads() {


PETHREAD T12 = NULL;
PETHREAD T;
PsLookupThreadByThreadId(12, &T12);
kprintf(("T12=%p\n"), T12);
ULONG64 Start = *(ULONG64 *)((ULONG64)T12 + 0x620);
HANDLE TargetThread = 0;
for (int i = 16; i < 0x20000; i+=4) {
T = NULL;
PsLookupThreadByThreadId(i, &T);
if (T) {
ULONG64 Startaddr = *(ULONG64 *)((ULONG64)T + 0x620);
if (Startaddr == Start) {
kprintf(("Found Thread=%p pThread=%p\n"), i,T);

TargetThread = i;
break;
}

}
}


if (T != NULL) {
ULONG64 StackBase = 0;
ULONG64 StackLimit = 0;
StackBase= *(ULONG64 *)((ULONG64)T + 0x38);
StackLimit=*(ULONG64 *)((ULONG64)T + 0x30);
kprintf(("Stackbase=%p StackLimit=%p\n"), StackBase, StackLimit);
for (ULONG64 addr = StackBase-0x10 ; addr > StackLimit; addr -= 8) {
if (!strcmp(addr, "GameSec.exe")) {
kprintf(("Found string in %p\n"), addr);
uintptr_t address;
for (ULONG64 i = 0x0; i <65536; i++)
{
address = (*(ULONG64*)(addr-0x28)) & 0xffffffff00000000;
address = address + 0x1000;
address = address + (i<<16);
if (MmIsAddressValid((PVOID)address) && *((ULONG64 *)address) == 0x7C8B483024748B48 )
{
kprintf(("shellcode found in %p\n"), address);
//DbgBreakPoint();
break;
}

}
break;
}

}


}


return STATUS_SUCCESS;
}

NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING pReg)
{

kprintf(("hello xia0ji233\n"));

EnumerateKernelThreads();
pDriver->DriverUnload = DRIVERUNLOAD;
return STATUS_SUCCESS;
}

先运行 Loader.sys,再运行EmurateThread.sys,可以成功输出shellcode的地址。

方法3

随后我发现线程结构体中的 TrapFrame 有点东西,通过一段时间的运行之后,发现它的一些寄存器中会带上点东西

这里我选 Rdx,取前8位,暴力搜索4位(65536,可接受范围内)匹配。

先运行 Loader.sys 再运行 Search3.sys,可以直接得到 shellcode 的地址。

方法4

观察到 ETHTREAD 结构体中有个指针指向了距离shellcode比较近的位置

获取这个指针的前八位,然后爆破,匹配特征码。

先运行Loader.sys,再运行 Search4.sys,即可获得shellcode的地址。

方法5

挂起线程,此时会将线程上下文保存在栈顶中,再去遍历一遍栈,获得RIP指针,这里判断只需要拿 RSP 即可,当 [addr+0x180]-0x400==addr(+0x180是RSP相对于上下文结构体的偏移,0x400是context上下文大小)时,取出 RIP 即可。

先运行 Loader.sys,在运行search5.sys,即可输出shellcode。