首页
社区
课程
招聘
腾讯游戏安全大赛2024决赛题解
2024-4-22 00:57 2764

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

2024-4-22 00:57
2764

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

本题解题附件自取

<!--more-->

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。


[培训]二进制漏洞攻防(第3期);满10人开班;模糊测试与工具使用二次开发;网络协议漏洞挖掘;Linux内核漏洞挖掘与利用;AOSP漏洞挖掘与利用;代码审计。

收藏
点赞3
打赏
分享
最新回复 (4)
雪    币: 540
活跃值: (4325)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
bwner 1 2024-4-22 08:34
2
0
太强了
雪    币: 19461
活跃值: (29125)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
秋狝 2024-4-24 09:24
3
1
tql
雪    币: 32
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
cccwwdd 3天前
4
0
关写保护那有些不严谨,没有考虑到可能会出现CR4.CET开启的情况是不能直接把CR0.WP清除的
具体可以看intel的System Programming Guide的第二章的2.5节Control Registers
雪    币: 10430
活跃值: (5223)
能力值: ( LV13,RANK:491 )
在线值:
发帖
回帖
粉丝
xi@0ji233 9 3天前
5
0
cccwwdd 关写保护那有些不严谨,没有考虑到可能会出现CR4.CET开启的情况是不能直接把CR0.WP清除的 具体可以看intel的System Programming Guide的第二章的2.5节Contro ...
是的,一般虚拟机是没有这个,真机测试的时候是不能这么操作的,所以得用MDL,但是因为之前用的很多的hook都这么写的,虚拟机也没啥问题就一直懒得改了
游客
登录 | 注册 方可回帖
返回