Ikoct的饮冰室

你愿意和我学一辈子二进制吗?

0%

2026腾讯游戏安全竞赛 PC客户端安全 决赛题解

r/funny - a sign warns motorists to beware of the windmills.

我宣布我是2026年最唐的唐吉诃德

我可能是唯一一个有一定分析过程但是完全0分的参赛选手, 简单说一下原因

第一关明明说了:

「影」核心系统「根」需要在一些开启了特殊特性的机器上才能部署成功,逆向找到成功部署条件

而我在调试到phase0的第一个cpuid看到返回了'vmwarevmware'之后偏执地认为这里就是在检测对抗虚拟机环境并在后续始终没有回想起来是这里出了问题, 并在后面分析出 ring 3 通过cpuid和驱动通信后高度怀疑本题需要开启VT-x并且是唯一的条件, 而在检测所有VT特征无果后认为第二问中隐藏的代码就是 host 的逻辑, 导致整体认知出现错位, 白干三天

但是知道过后该做还是得做的(

成功运行shadow_panel.exe,控制台程序成功运行进入至输入终止密码的终端

直接启动程序会发现在phase0就失败了, fail 时 code1-3, 通过字符串可以定位到该错误码输出的位置在sub_144A04160中:

image-20260417134444284

其中调用了某个类的方法来对nopass(通过调试发现唯一一个不等于0的判断值故改名)进行赋值操作, 调试发现进入了sub_144A07540, 关键的检测是cpuid的虚拟机厂商, 因为我使用的是VMware所以检测失败, 可以通过 patch 强制比较通过:

image-20260417140910558

image-20260417141108248

patch个即把茂啊, 直接在Windows特性中开启Hyper-V即可

再运行发现code1变成了-4, 再深入到sub_144A06650, 调试发现动态解析得到NtQuerySystemInformation后检测了DMA:

image-20260417142329140

也是直接 patch 返回 0:

image-20260417142428449

patch个即把茂啊, 在VMware的虚拟机设置中关闭内存重映射即可:

QQ_1776834817681

成功通过phase0:

image-20260417142525805

接下来分析phase1错误码出现原因, 同样是phase0时的调用点, 这次将要调用的函数换成了0000000144A075F0, 在其中解密了一个字符串并创建了一个UUID后构成了一个路径:"C:\\Windows\\Temp\\WdiServiceHost\\{uuid}.vhd", 接下来进入了一个被tvm加壳的函数, 无法静态分析, 但是通过在路径上下硬件断点可以追踪到该函数的底层API调用, 通过这个方法在调用链中途的sub_147F2D619中发现了一个kernel32_GetFileAttributesW的间接调用, 交叉引用可以发现在0000000144A10B30中还通过GetProcAddress获取到了很多其他API的地址, 逐个下断可以找到如下调用过程:

1
2
3
4
5
6
7
8
9
10
11
kernel32_GetFileAttributesW

virtdisk_CreateVirtualDisk

kernel32_GetLastError

virtdisk_AttachVirtualDisk

kernel32_CloseHandle

kernel32_DeleteFileW

其中调用virtdisk_AttachVirtualDisk后的返回值1314就是code2, 查询得知是权限不足, 使用管理员打开程序成功进入phase3:

image-20260417152840358

检测在0000000144A07650中, 简单地cpuid了一下后检测结果是否为0x1919810, 显然不可能, 直接 patch 绕过:

image-20260417153403028

patch个即把茂啊, 实际上如果第一关不用patch的方法而是修改环境的话这里就能正常通过

实际上根据后面的输入处理分析, 这里应该是一个驱动核心功能是否启用的检测, cpuid是用于和驱动进行通信的vm-exit触发器

之后成功进入输入密码界面;

image-20260417153529258

「根」使用特殊方法,对操作系统底层进行了攻击,并借此将关键核心代码隐藏了起来,分析其完整实现流程

通过IDA-MCP找到接收到enter后处理输入数据的函数0000000147F31541, 这些函数大部分被混淆, 可以通过匹配两种固定模式来去壳, 去花脚本:

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
"""
IDA Python 9.1 script: static deobfuscation helper for two shell patterns.

Mode:
- Pure static scan, no debugger stepping required.
- Start from the function containing current cursor EA.
- Linear decode instruction-by-instruction from function start.
- Stop when encountering first byte 0xC3 (retn), or function end.

Patterns patched to NOP:
A) push reg; mov reg, imm; pushfq; <one insn>; popfq; jmp reg; <junk>; pop reg
B) push reg; lea reg, ...; lea reg, ...; jmp reg; <junk>; pop reg

Notes:
- "<junk>" is treated as exactly one byte between jmp and following pop.
- jmp and pop must use the same register.
"""

import ida_bytes
import ida_funcs
import ida_kernwin
import ida_ua
import idc


# ---- Tunables ----
VERBOSE = True
MAX_SCAN_INSNS = 2_000_000


def log(msg):
if VERBOSE:
print(msg)


def mnem(ea):
return ida_ua.print_insn_mnem(ea).lower()


def get_op0_reg(insn):
op0 = insn.ops[0]
if op0.type == ida_ua.o_reg:
return op0.reg
return None


def ensure_code_and_decode(ea):
flags = ida_bytes.get_flags(ea)
if not ida_bytes.is_code(flags):
idc.create_insn(ea)

insn = ida_ua.insn_t()
size = ida_ua.decode_insn(insn, ea)
if size == 0:
idc.create_insn(ea)
size = ida_ua.decode_insn(insn, ea)
if size == 0:
return None
return insn


def patch_nops(start_ea, end_ea_exclusive):
if end_ea_exclusive <= start_ea:
return
for pea in range(start_ea, end_ea_exclusive):
ida_bytes.patch_byte(pea, 0x90)
log("[NOP] 0x%X - 0x%X" % (start_ea, end_ea_exclusive - 1))


def decode_entry(ea):
insn = ensure_code_and_decode(ea)
if insn is None:
return None
return {
"ea": ea,
"insn": insn,
"mnem": mnem(ea),
"size": insn.size,
"reg0": get_op0_reg(insn),
}


def is_mov_reg_imm(entry, reg):
if entry["mnem"] != "mov":
return False
if entry["reg0"] != reg:
return False
return entry["insn"].ops[1].type == ida_ua.o_imm


def is_lea_to_reg(entry, reg):
if entry["mnem"] != "lea":
return False
if entry["reg0"] != reg:
return False
op1 = entry["insn"].ops[1]
return op1.type in (ida_ua.o_mem, ida_ua.o_displ, ida_ua.o_phrase)


def is_pushfq(entry):
return entry["mnem"] in ("pushf", "pushfq")


def is_popfq(entry):
return entry["mnem"] in ("popf", "popfq")


def is_jmp_reg(entry, reg):
return entry["mnem"] == "jmp" and entry["reg0"] == reg


def is_pop_reg(entry, reg):
return entry["mnem"] == "pop" and entry["reg0"] == reg


def is_candidate_push_start(ea, func_end):
# Strict gate:
# current must be push reg,
# and next must be either mov reg,imm or lea reg,... (same reg)
e0 = decode_entry(ea)
if e0 is None or e0["mnem"] != "push" or e0["reg0"] is None:
return False
reg = e0["reg0"]

next_ea = e0["ea"] + e0["size"]
if next_ea >= func_end:
return False

e1 = decode_entry(next_ea)
if e1 is None:
return False

return is_mov_reg_imm(e1, reg) or is_lea_to_reg(e1, reg)


def match_pattern_a_at(ea, func_end):
# A) push reg; mov reg, imm; pushfq; one; popfq; jmp reg; junk; pop reg
e0 = decode_entry(ea)
if e0 is None or e0["mnem"] != "push" or e0["reg0"] is None:
return None
reg = e0["reg0"]

e1_ea = e0["ea"] + e0["size"]
e1 = decode_entry(e1_ea)
if e1 is None or not is_mov_reg_imm(e1, reg):
return None

e2_ea = e1["ea"] + e1["size"]
e2 = decode_entry(e2_ea)
if e2 is None or not is_pushfq(e2):
return None

e3_ea = e2["ea"] + e2["size"]
e3 = decode_entry(e3_ea)
if e3 is None:
return None

e4_ea = e3["ea"] + e3["size"]
e4 = decode_entry(e4_ea)
if e4 is None or not is_popfq(e4):
return None

e5_ea = e4["ea"] + e4["size"]
e5 = decode_entry(e5_ea)
if e5 is None or not is_jmp_reg(e5, reg):
return None

junk_ea = e5["ea"] + e5["size"]
e6_ea = junk_ea + 1
if e6_ea >= func_end:
return None

e6 = decode_entry(e6_ea)
if e6 is None or not is_pop_reg(e6, reg):
return None

end_excl = e6["ea"] + e6["size"]
if end_excl > func_end:
return None

return (ea, end_excl, "A")


def match_pattern_b_at(ea, func_end):
# B) push reg; lea reg,...; lea reg,...; jmp reg; junk; pop reg
e0 = decode_entry(ea)
if e0 is None or e0["mnem"] != "push" or e0["reg0"] is None:
return None
reg = e0["reg0"]

e1_ea = e0["ea"] + e0["size"]
e1 = decode_entry(e1_ea)
if e1 is None or not is_lea_to_reg(e1, reg):
return None

e2_ea = e1["ea"] + e1["size"]
e2 = decode_entry(e2_ea)
if e2 is None or not is_lea_to_reg(e2, reg):
return None

e3_ea = e2["ea"] + e2["size"]
e3 = decode_entry(e3_ea)
if e3 is None or not is_jmp_reg(e3, reg):
return None

junk_ea = e3["ea"] + e3["size"]
e4_ea = junk_ea + 1
if e4_ea >= func_end:
return None

e4 = decode_entry(e4_ea)
if e4 is None or not is_pop_reg(e4, reg):
return None

end_excl = e4["ea"] + e4["size"]
if end_excl > func_end:
return None

return (ea, end_excl, "B")


def run_static_dejunk():
start_ea = ida_kernwin.get_screen_ea()
f = ida_funcs.get_func(start_ea)
if f:
func_start = f.start_ea
func_end = f.end_ea
else:
ida_kernwin.msg("[dejunk] current EA is not in a function, asking manual range...\n")
default_start = start_ea
default_end = start_ea + 0x1000
func_start = ida_kernwin.ask_addr(default_start, "Input deobfuscation range start EA")
if func_start is None:
raise RuntimeError("Canceled: start EA not provided.")
func_end = ida_kernwin.ask_addr(default_end, "Input deobfuscation range end EA (exclusive)")
if func_end is None:
raise RuntimeError("Canceled: end EA not provided.")

if func_end <= func_start:
raise RuntimeError("Invalid range: end EA must be greater than start EA.")

log("[START] function: 0x%X - 0x%X" % (func_start, func_end - 1))
log("[MODE] static linear scan until first C3 or function end")

ea = func_start
scanned = 0
patched = 0

while ea < func_end and scanned < MAX_SCAN_INSNS:
# Stop at first C3 as requested.
if ida_bytes.get_byte(ea) == 0xC3:
log("[STOP] hit C3 at 0x%X" % ea)
break

m = None
if is_candidate_push_start(ea, func_end):
try:
m = match_pattern_a_at(ea, func_end)
except Exception as e:
log("[ERROR] pattern A match failed at 0x%X: %s" % (ea, e))
m = None

if m is None:
try:
m = match_pattern_b_at(ea, func_end)
except Exception as e:
log("[ERROR] pattern B match failed at 0x%X: %s" % (ea, e))
m = None

if m is not None:
start_patch, end_patch, ptype = m
patch_nops(start_patch, end_patch)
patched += 1
log("[MATCH] pattern %s at 0x%X" % (ptype, start_patch))
ea = end_patch
scanned += 1
continue

insn = ensure_code_and_decode(ea)
if insn is None:
ea += 1
else:
ea += insn.size
scanned += 1

if scanned >= MAX_SCAN_INSNS:
log("[STOP] max scan count reached: %d" % MAX_SCAN_INSNS)

log("[DONE] scanned=%d, patched=%d" % (scanned, patched))


if __name__ == "__main__":
try:
run_static_dejunk()
except Exception as e:
ida_kernwin.warning("dejunk failed: %s" % e)
raise

去除后可以看到实际上的处理函数:

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
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
__int64 __fastcall process_input()
{
unsigned __int64 l16hex; // r14
unsigned __int64 f16hex; // rsi
size_t v2; // r8
__int128 n2_2; // kr00_16
__int128 *v4; // r8
__int128 *v5; // rax
__int128 *v6; // rax
__int128 *v7; // rax
size_t Size; // rdi
__int128 *v9; // r12
__int64 n22; // rbx
size_t v11; // rax
void *v12; // rax
void *v13; // r15
void *v14; // rcx
__int64 v15; // r9
__int128 *v16; // rax
char v17; // cl
unsigned __int8 v18; // bl
char *v19; // r9
char *v20; // rax
size_t n2_3; // r9
__int128 *v22; // rdi
_BYTE *v23; // rdi
unsigned __int64 i; // rdx
__int128 *v25; // rax
char v26; // r9
unsigned __int8 v27; // cl
__int128 *v28; // rax
char v29; // r9
unsigned __int8 v30; // cl
__int128 *v31; // rax
char v32; // r9
unsigned __int8 v33; // cl
__int128 *v34; // rax
char v35; // r9
unsigned __int8 v36; // cl
__int128 *v37; // rax
char v38; // r9
unsigned __int8 v39; // cl
__int128 *v40; // rax
char v41; // r9
unsigned __int8 v42; // cl
__int128 *v43; // rax
char v44; // r9
unsigned __int8 v45; // cl
__int128 *v46; // rax
char v47; // r9
unsigned __int8 v48; // cl
char v49; // bl
char *v50; // rax
char *INVALID_HEX_FORMAT; // rax
void **i_1; // r8
unsigned __int64 n4; // rcx
size_t *v54; // rdi
_QWORD *i_3; // rbx
_QWORD *i_2; // rdx
void **result; // rax
_BYTE *v58; // rcx
unsigned __int64 n15_1; // r15
unsigned __int64 v60; // r12
unsigned __int8 v61; // bl
unsigned __int8 v62; // di
__int64 *j_1; // rcx
_QWORD **p_i; // rax
void **v65; // rax
char n32; // al
__int64 *j_2; // rdx
_QWORD **p_i_1; // rcx
_QWORD **p_i_2; // rdx
_BYTE *i_6; // rcx
void **result_1; // rax
__int64 i_7; // rdx
__int64 v74; // [rsp+0h] [rbp-100h] BYREF
__int64 v75; // [rsp+20h] [rbp-E0h]
char n48; // [rsp+28h] [rbp-D8h]
unsigned __int8 v77; // [rsp+30h] [rbp-D0h]
__int64 n1500; // [rsp+38h] [rbp-C8h] BYREF
__int128 v79; // [rsp+40h] [rbp-C0h] BYREF
__int128 n2; // [rsp+50h] [rbp-B0h]
_QWORD *i_4; // [rsp+60h] [rbp-A0h] BYREF
_QWORD *i_5; // [rsp+68h] [rbp-98h]
__int64 *j; // [rsp+70h] [rbp-90h]
unsigned __int64 n15_2; // [rsp+78h] [rbp-88h]
__int128 v85; // [rsp+80h] [rbp-80h] BYREF
__int128 n2_1; // [rsp+90h] [rbp-70h]
void *v87[2]; // [rsp+A0h] [rbp-60h] BYREF
unsigned __int64 v88; // [rsp+B0h] [rbp-50h]
unsigned __int64 n0x10_1; // [rsp+B8h] [rbp-48h]
size_t v90[2]; // [rsp+C0h] [rbp-40h] BYREF
__int64 n18; // [rsp+D0h] [rbp-30h]
__int64 n15; // [rsp+D8h] [rbp-28h]
void *v93; // [rsp+E0h] [rbp-20h] BYREF
__m128i si128; // [rsp+F0h] [rbp-10h]
void *v95; // [rsp+100h] [rbp+0h] BYREF
__m128i v96; // [rsp+110h] [rbp+10h]
void *v97; // [rsp+120h] [rbp+20h] BYREF
__m128i v98; // [rsp+130h] [rbp+30h]
_OWORD v99[2]; // [rsp+140h] [rbp+40h] BYREF
_OWORD v100[2]; // [rsp+160h] [rbp+60h] BYREF
_OWORD v101[2]; // [rsp+180h] [rbp+80h] BYREF
_QWORD *v102; // [rsp+1A0h] [rbp+A0h] BYREF
unsigned __int64 n0x10; // [rsp+1B8h] [rbp+B8h]
void *v104[6]; // [rsp+1C0h] [rbp+C0h] BYREF

n1500 = 1500;
sub_144A00260(&n1500);
l16hex = 0;
f16hex = 0;
*(_QWORD *)&v79 = 0;
*(_QWORD *)&n2 = 0;
*((_QWORD *)&n2 + 1) = 15;
v2 = -1;
do
++v2;
while ( input_passwd[v2] );
log_print_0((void **)&v79, input_passwd, v2);
n2_2 = n2;
v4 = (__int128 *)v79;
if ( (unsigned __int64)n2 < 2 )
goto LABEL_37;
v5 = &v79;
if ( *((_QWORD *)&n2 + 1) >= 0x10u )
v5 = (__int128 *)v79;
if ( *(_BYTE *)v5 != 48 )
goto LABEL_37;
v6 = &v79;
if ( *((_QWORD *)&n2 + 1) >= 0x10u )
v6 = (__int128 *)v79;
if ( *((_BYTE *)v6 + 1) != 120 )
{
v7 = &v79;
if ( *((_QWORD *)&n2 + 1) >= 0x10u )
v7 = (__int128 *)v79;
if ( *((_BYTE *)v7 + 1) != 88 )
goto LABEL_37;
}
*(_QWORD *)&v85 = 0;
*((_QWORD *)&n2_1 + 1) = 15;
Size = n2 - 2;
v9 = &v79;
if ( *((_QWORD *)&n2 + 1) >= 0x10u )
v9 = (__int128 *)v79;
if ( Size > 0xF )
{
n22 = 0x7FFFFFFFFFFFFFFFLL;
if ( Size > 0x7FFFFFFFFFFFFFFFLL )
std::_Xlength_error();
if ( (Size | 0xF) <= 0x7FFFFFFFFFFFFFFFLL )
{
n22 = Size | 0xF;
if ( (Size | 0xF) < 0x16 )
n22 = 22;
if ( (unsigned __int64)(n22 + 1) < 0x1000 )
{
if ( n22 == -1 )
v13 = 0;
else
v13 = sub_144A41460(n22 + 1);
LABEL_30:
*(_QWORD *)&n2_1 = Size;
*((_QWORD *)&n2_1 + 1) = n22;
memcpy(v13, (char *)v9 + 2, Size);
*((_BYTE *)v13 + Size) = 0;
*(_QWORD *)&v85 = v13;
goto LABEL_31;
}
v11 = n22 + 40;
if ( n22 + 40 < (unsigned __int64)(n22 + 1) )
throw_string_error();
}
else
{
v11 = 0x8000000000000027uLL;
}
v12 = sub_144A41460(v11);
if ( !v12 )
goto LABEL_34;
v13 = (void *)(((unsigned __int64)v12 + 39) & 0xFFFFFFFFFFFFFFE0uLL);
*((_QWORD *)v13 - 1) = v12;
goto LABEL_30;
}
*(_QWORD *)&n2_1 = n2 - 2;
memmove(&v85, (char *)v9 + 2, Size);
*((_BYTE *)&v85 + Size) = 0;
LABEL_31:
if ( *((_QWORD *)&n2 + 1) >= 0x10u )
{
v14 = (void *)v79;
if ( (unsigned __int64)(*((_QWORD *)&n2 + 1) + 1LL) >= 0x1000 )
{
v14 = *(void **)(v79 - 8);
if ( (unsigned __int64)(v79 - (_QWORD)v14 - 8) > 0x1F )
LABEL_34:
invalid_parameter_noinfo_noreturn();
}
j_j_free(v14);
}
v79 = v85;
n2 = n2_1;
v4 = (__int128 *)v85;
n2_2 = n2_1;
LABEL_37:
if ( (unsigned __int64)(n2_2 - 1) > 0x1F )
{
LABEL_148:
v49 = 1;
goto LABEL_149;
}
v15 = 0;
if ( (_QWORD)n2_2 )
{
do
{
v16 = &v79;
if ( *((_QWORD *)&n2_2 + 1) >= 0x10u )
v16 = v4;
v17 = *((_BYTE *)v16 + v15);
if ( (unsigned __int8)(v17 - 48) > 9u && (unsigned __int8)(v17 - 65) > 5u && (unsigned __int8)(v17 - 97) > 5u )
goto LABEL_148;
}
while ( ++v15 < (unsigned __int64)n2_2 );
}
if ( (unsigned __int64)n2_2 < 0x20 )
{
v18 = v77;
do
{
v19 = (char *)&v79;
if ( *((_QWORD *)&n2_2 + 1) < 0x10u )
{
v20 = (char *)&v79;
}
else
{
v20 = (char *)v4;
v19 = (char *)v4;
}
n2_3 = v19 - v20;
if ( (unsigned __int64)n2_2 < n2_3 )
call_Xout_of_range();
if ( *((_QWORD *)&n2_2 + 1) == (_QWORD)n2_2 )
{
n48 = 48;
v75 = 1;
sub_1449FBE80((void **)&v79, 1u, v18, n2_3);
}
else
{
*(_QWORD *)&n2 = n2_2 + 1;
v22 = &v79;
if ( *((_QWORD *)&n2_2 + 1) >= 0x10u )
v22 = v4;
v23 = (char *)v22 + n2_3;
memmove(v23 + 1, v23, n2_2 - n2_3 + 1);
*v23 = 48;
}
v4 = (__int128 *)v79;
n2_2 = n2;
}
while ( (unsigned __int64)n2 < 0x20 );
}
for ( i = 0; i < 0x20; i += 8LL )
{
v25 = &v79;
if ( *((_QWORD *)&n2_2 + 1) >= 0x10u )
v25 = v4;
v26 = *((_BYTE *)v25 + i);
v27 = 0;
if ( (unsigned __int8)(v26 - 48) > 9u )
{
if ( (unsigned __int8)(v26 - 65) > 5u )
{
if ( (unsigned __int8)(v26 - 97) <= 5u )
v27 = v26 - 87;
}
else
{
v27 = v26 - 55;
}
}
else
{
v27 = v26 - 48;
}
if ( i >= 0x10 )
f16hex = v27 | v27 ^ (16 * f16hex);
else
l16hex = v27 | ((v27 | (16 * l16hex)) - v27);
v28 = &v79;
if ( *((_QWORD *)&n2_2 + 1) >= 0x10u )
v28 = v4;
v29 = *((_BYTE *)v28 + i + 1);
v30 = 0;
if ( (unsigned __int8)(v29 - 48) > 9u )
{
if ( (unsigned __int8)(v29 - 65) > 5u )
{
if ( (unsigned __int8)(v29 - 97) <= 5u )
v30 = v29 - 87;
}
else
{
v30 = v29 - 55;
}
}
else
{
v30 = v29 - 48;
}
if ( i + 1 >= 0x10 )
f16hex = v30 ^ ((v30 | v30 ^ (16 * f16hex)) - v30);
else
l16hex = v30 | v30 ^ (16 * l16hex);
v31 = &v79;
if ( *((_QWORD *)&n2_2 + 1) >= 0x10u )
v31 = v4;
v32 = *((_BYTE *)v31 + i + 2);
v33 = 0;
if ( (unsigned __int8)(v32 - 48) > 9u )
{
if ( (unsigned __int8)(v32 - 65) > 5u )
{
if ( (unsigned __int8)(v32 - 97) <= 5u )
v33 = v32 - 87;
}
else
{
v33 = v32 - 55;
}
}
else
{
v33 = v32 - 48;
}
if ( i + 2 >= 0x10 )
f16hex = v33 | v33 ^ (v33 | (16 * f16hex));
else
l16hex = v33 | v33 ^ (16 * l16hex);
v34 = &v79;
if ( *((_QWORD *)&n2_2 + 1) >= 0x10u )
v34 = v4;
v35 = *((_BYTE *)v34 + i + 3);
v36 = 0;
if ( (unsigned __int8)(v35 - 48) > 9u )
{
if ( (unsigned __int8)(v35 - 65) > 5u )
{
if ( (unsigned __int8)(v35 - 97) <= 5u )
v36 = v35 - 87;
}
else
{
v36 = v35 - 55;
}
}
else
{
v36 = v35 - 48;
}
if ( i + 3 >= 0x10 )
f16hex = v36 | v36 ^ (16 * f16hex);
else
l16hex = v36 | v36 ^ ((v36 | (16 * l16hex)) - v36);
v37 = &v79;
if ( *((_QWORD *)&n2_2 + 1) >= 0x10u )
v37 = v4;
v38 = *((_BYTE *)v37 + i + 4);
v39 = 0;
if ( (unsigned __int8)(v38 - 48) > 9u )
{
if ( (unsigned __int8)(v38 - 65) > 5u )
{
if ( (unsigned __int8)(v38 - 97) <= 5u )
v39 = v38 - 87;
}
else
{
v39 = v38 - 55;
}
}
else
{
v39 = v38 - 48;
}
if ( i + 4 >= 0x10 )
f16hex = v39 | v39 ^ (v39 | (16 * f16hex));
else
l16hex = v39 | v39 ^ (16 * l16hex);
v40 = &v79;
if ( *((_QWORD *)&n2_2 + 1) >= 0x10u )
v40 = v4;
v41 = *((_BYTE *)v40 + i + 5);
v42 = 0;
if ( (unsigned __int8)(v41 - 48) > 9u )
{
if ( (unsigned __int8)(v41 - 65) > 5u )
{
if ( (unsigned __int8)(v41 - 97) <= 5u )
v42 = v41 - 87;
}
else
{
v42 = v41 - 55;
}
}
else
{
v42 = v41 - 48;
}
if ( i + 5 >= 0x10 )
f16hex = v42 | v42 ^ (v42 | v42 ^ (16 * f16hex));
else
l16hex = v42 | v42 ^ ((v42 | (16 * l16hex)) - v42);
v43 = &v79;
if ( *((_QWORD *)&n2_2 + 1) >= 0x10u )
v43 = v4;
v44 = *((_BYTE *)v43 + i + 6);
v45 = 0;
if ( (unsigned __int8)(v44 - 48) > 9u )
{
if ( (unsigned __int8)(v44 - 65) > 5u )
{
if ( (unsigned __int8)(v44 - 97) <= 5u )
v45 = v44 - 87;
}
else
{
v45 = v44 - 55;
}
}
else
{
v45 = v44 - 48;
}
if ( i + 6 >= 0x10 )
f16hex = v45 ^ ((v45 | v45 ^ (16 * f16hex)) - v45);
else
l16hex = v45 | v45 ^ (v45 | v45 ^ (16 * l16hex));
v46 = &v79;
if ( *((_QWORD *)&n2_2 + 1) >= 0x10u )
v46 = v4;
v47 = *((_BYTE *)v46 + i + 7);
v48 = 0;
if ( (unsigned __int8)(v47 - 48) > 9u )
{
if ( (unsigned __int8)(v47 - 65) > 5u )
{
if ( (unsigned __int8)(v47 - 97) <= 5u )
v48 = v47 - 87;
}
else
{
v48 = v47 - 55;
}
}
else
{
v48 = v47 - 48;
}
if ( i + 7 >= 0x10 )
f16hex = v48 | v48 ^ (16 * f16hex);
else
l16hex = v48 | v48 ^ (v48 | (16 * l16hex));
}
v49 = 0;
LABEL_149:
if ( *((_QWORD *)&n2_2 + 1) >= 0x10u )
{
v50 = (char *)v4;
if ( (unsigned __int64)(*((_QWORD *)&n2_2 + 1) + 1LL) >= 0x1000 )
{
v4 = (__int128 *)*((_QWORD *)v4 - 1);
if ( (unsigned __int64)(v50 - (char *)v4 - 8) > 0x1F )
invalid_parameter_noinfo_noreturn();
}
j_j_free(v4);
}
if ( v49 )
{
n2_0 = 2;
log_print_0((void **)&qword_147CAC868, "I N V A L I D I N P U T", 0x19u);
log_print_0((void **)&qword_147CAC888, "[!!]", 4u);
v90[0] = 0;
n18 = 0;
n15 = 15;
INVALID_HEX_FORMAT = (char *)sub_144A41460(0x20u);
n18 = 18;
n15 = 31;
strcpy(INVALID_HEX_FORMAT, "INVALID HEX FORMAT");
v90[0] = (size_t)INVALID_HEX_FORMAT;
v93 = 0;
si128 = _mm_load_si128((const __m128i *)&xmmword_144A65530);
log_print_0(&v93, "Expected: 1-32 hex chars (0-9, A-F)", 0x23u);
v95 = 0;
v96 = _mm_load_si128((const __m128i *)&xmmword_144A65530);
log_print_0(&v95, "Optional 0x prefix allowed", 0x1Au);
v97 = 0;
v98 = _mm_load_si128((const __m128i *)&xmmword_144A65530);
log_print_0(&v97, "Example: 0x11111111111111112222222222222222", 0x2Bu);
i_1 = (void **)i_1;
n4 = ((__int64)i_2 - i_1) >> 5;
if ( n4 >= 4 )
{
i_3 = (_QWORD *)(i_1 + 128);
sub_1449F5A50(v90, (size_t *)v99, (void **)i_1);
i_2 = (_QWORD *)i_2;
}
else
{
if ( (unsigned __int64)((*((_QWORD *)&i_2 + 1) - i_1) >> 5) < 4 )
{
sub_144A073B0((__int128 *)&i_1, 4u);
n4 = 0;
i_1 = (void **)i_1;
}
v54 = &v90[4 * n4];
sub_1449F5A50(v90, v54, i_1);
i_3 = (_QWORD *)i_2;
i_4 = (_QWORD *)i_2;
i_5 = (_QWORD *)i_2;
for ( j = &i_1; v54 != (size_t *)v99; v54 += 4 )
{
sub_144A00FE0(i_3, (__int64)v54);
i_3 += 4;
i_5 = i_3;
}
i_2 = i_3;
}
sub_1449F5AB0(i_3, i_2);
*(_QWORD *)&i_2 = i_3;
sub_144A41390((__int64)v90, 32, 4, (__int64 (__fastcall *)(_QWORD))sub_144A02150);
}
else
{
memset(v100, 0, sizeof(v100));
v75 = (__int64)v100;
do_cpuid(0xDEADBEEFLL, 0x1919810, l16hex, f16hex);
result = get_result((void **)&v102, v100); // 8BAD 6304 294C D99F BC2D 49
sub_144A02650((__int64)&qword_147CAC888, (__int64)result);
if ( n0x10 >= 0x10 )
{
v58 = v102;
if ( n0x10 + 1 >= 0x1000 )
{
v58 = (_BYTE *)*(v102 - 1);
if ( (unsigned __int64)((char *)v102 - v58 - 8) > 0x1F )
invalid_parameter_noinfo_noreturn();
}
j_j_free(v58);
}
memset(v99, 0, sizeof(v99));
v75 = (__int64)v99;
do_cpuid(0xDEADBEEFLL, 0xB16B00B5, l16hex, f16hex);
n2_0 = v99[0];
get_result(v87, v99);
i_4 = 0;
j = 0;
n15_1 = 15;
n15_2 = 15;
v60 = 0;
if ( v88 )
{
v61 = v77;
v62 = v77;
do
{
if ( v60 )
{
j_1 = j;
if ( (unsigned __int64)j >= n15_1 )
{
sub_1449FC1F0((void **)&i_4, 1u, v61, 32);
}
else
{
j = (__int64 *)((char *)j + 1);
p_i = &i_4;
if ( n15_1 >= 0x10 )
p_i = (_QWORD **)i_4;
*(_WORD *)((char *)j_1 + (_QWORD)p_i) = 32;
}
n15_1 = n15_2;
}
v65 = v87;
if ( n0x10_1 >= 0x10 )
v65 = (void **)v87[0];
n32 = toupper(*((char *)v65 + v60));
j_2 = j;
if ( (unsigned __int64)j >= n15_1 )
{
sub_1449FC1F0((void **)&i_4, 1u, v62, n32);
}
else
{
j = (__int64 *)((char *)j + 1);
p_i_1 = &i_4;
if ( n15_1 >= 0x10 )
p_i_1 = (_QWORD **)i_4;
*((_BYTE *)j_2 + (_QWORD)p_i_1) = n32;
*((_BYTE *)j_2 + (_QWORD)p_i_1 + 1) = 0;
}
++v60;
n15_1 = n15_2;
}
while ( v60 < v88 );
}
p_i_2 = &i_4;
if ( n15_1 >= 0x10 )
p_i_2 = (_QWORD **)i_4;
log_print_0((void **)&qword_147CAC868, p_i_2, (size_t)j);
if ( n15_2 >= 0x10 )
{
i_6 = i_4;
if ( n15_2 + 1 >= 0x1000 )
{
i_6 = (_BYTE *)*(i_4 - 1);
if ( (unsigned __int64)((char *)i_4 - i_6 - 8) > 0x1F )
invalid_parameter_noinfo_noreturn();
}
j_j_free(i_6);
}
if ( n0x10_1 >= 0x10 )
sub_144A09A10((__int64)v87, (_QWORD *)v87[0], n0x10_1 + 1);
memset(v101, 0, sizeof(v101));
v75 = (__int64)v101;
do_cpuid(0xDEADBEEFLL, 0xCAFED00D, l16hex, f16hex);
sub_1449F5AB0((_QWORD *)i_1, (_QWORD *)i_2);
*(_QWORD *)&i_2 = i_1;
result_1 = get_result(v104, v101);
i_7 = i_2;
if ( (_QWORD)i_2 == *((_QWORD *)&i_2 + 1) )
{
sub_1449F5F70((unsigned __int64 *)&i_1, (_QWORD *)i_2, result_1);
}
else
{
*(_QWORD *)i_2 = 0;
*(_QWORD *)(i_7 + 16) = 0;
*(_QWORD *)(i_7 + 24) = 0;
*(_OWORD *)i_7 = *(_OWORD *)result_1;
*(_OWORD *)(i_7 + 16) = *((_OWORD *)result_1 + 1);
result_1[2] = 0;
result_1[3] = (void *)15;
*(_BYTE *)result_1 = 0;
*(_QWORD *)&i_2 = i_2 + 32;
}
sub_144A02150((__int64)v104);
}
n2 = 3;
byte_147CB134E = 0;
return sub_144A41300((unsigned __int64)&v74 ^ (unsigned __int64)v104[4]);
}

其中的关键是三次cpuid指令, 输入的十六进制字符串会和一个固定魔数DEADBEEF和3种可能用于分发的通信代码一同放在RAX/RBX/RCX/RDX中, 返回的结果放回这四个寄存器.

这里其实就能猜到实际上特殊的代码隐藏手段就是VT技术, 它拦截了cpuid的执行代替了普通的驱动-ring 3 通信API.

但是即使我使用了题目文档中推荐的Windows 版本, 开启虚拟化, 关闭Windows Defenser, 关闭VBS都无法成功让驱动成功开启虚拟化环境(当然以上都是猜测, 我无法在驱动中找到VT启用的特征指令字节码, 如VMXON, VMLAUNCH等), 包括下面用于检测VT启动的驱动都能够正常安装的情况下仍然无法观察到三环程序打包的驱动激活了VT并拦截cpuid, 这个检测代码基于hvpp项目:

这里直接放源码太长了, 具体就是实现框架中的vmxonvmexit handler就行了

另外一个可能的对系统底层进行攻击的点位于驱动偏移000000000000BEB0处, 这里间接解析了几个内核API, 通过调试可以还原:

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
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
__int64 __fastcall hidecode(__int64 *a1, _QWORD *a2, _QWORD *a3, _OWORD *a4)
{
_QWORD *v5; // rdi
_QWORD *v6; // rbx
PVOID (__stdcall *MmAllocateContiguousMemory)(SIZE_T, PHYSICAL_ADDRESS); // rax
__int64 v8; // r9
__int64 v9; // rcx
__int64 v10; // rdx
__int64 v11; // r8
__int64 v12; // r9
__int64 v13; // rdi
__int64 v14; // r14
char v15; // bl
char *v16; // r14
char v17; // bp
unsigned __int64 v18; // r15
__int64 v19; // rbx
char v20; // r12
__int64 to_match_page_5; // rax
_BYTE *to_match_page_1; // rdx
PPHYSICAL_MEMORY_RANGE (*MmGetPhysicalMemoryRanges)(void); // rax
__int64 v24; // r9
__int64 v25; // rcx
__int64 v26; // rdx
__int64 v27; // r8
__int64 v28; // r9
__int64 v29; // rdi
__int64 v30; // r14
char v31; // bl
char *v32; // r14
char v33; // bp
unsigned __int64 v34; // r15
__int64 v35; // rbx
char v36; // r12
PPHYSICAL_MEMORY_RANGE v38; // rax
_BYTE *to_match_page_4; // rdi
__int64 n1970169159_1; // rbx
PHYSICAL_ADDRESS *p_BaseAddress; // rsi
PHYSICAL_ADDRESS v42; // r15
void (__stdcall *MmUnmapIoSpace)(PVOID, SIZE_T); // rax
LONGLONG v44; // rbp
int (__fastcall *MmCopyMemory)(_BYTE *, unsigned __int64, __int64, __int64, char *); // rax
__int64 v46; // r9
__int64 v47; // rcx
__int64 v48; // rdx
__int64 v49; // r8
__int64 v50; // r9
__int64 v51; // r10
__int64 v52; // r14
char v53; // di
char *v54; // r14
unsigned __int64 v55; // r13
unsigned __int64 v56; // r11
char v57; // r12
unsigned __int64 page_index; // rbp
unsigned __int64 idx_; // rax
__int64 (__fastcall *MmMaploSpace)(unsigned __int64, __int64, _QWORD); // rax
__int64 v61; // r9
__int64 v62; // rcx
__int64 v63; // rdx
__int64 v64; // r8
__int64 v65; // r9
__int64 v66; // r10
__int64 v67; // rdi
char *v68; // r14
char v69; // di
unsigned __int64 v70; // r13
unsigned __int64 v71; // r11
char v72; // r12
__int64 va_kernel_page_from_physic; // rax
__int64 va_kernel_page_from_physic_; // rbp
__int64 n1970169159; // r8
__int64 n1970169159_2; // rt1
NTSTATUS (__stdcall *RtlGetVersion)(PRTL_OSVERSIONINFOW); // rax
__int64 v83; // r9
__int64 v84; // rcx
__int64 v85; // rdx
__int64 v86; // r8
__int64 v87; // r9
__int64 v88; // r10
__int64 v89; // rdi
char *v90; // r14
char v91; // di
unsigned __int64 v92; // r13
unsigned __int64 v93; // r11
char v94; // r12
__int64 n1752462657; // r8
__int64 n1752462657_1; // rtt
NTSTATUS (__stdcall *RtlGetVersion_1)(PRTL_OSVERSIONINFOW); // rax
__int64 v103; // r9
__int64 v104; // rcx
__int64 v105; // rdx
__int64 v106; // r8
__int64 v107; // r9
__int64 v108; // r10
__int64 v109; // rdi
char *v110; // r14
char v111; // di
unsigned __int64 v112; // r13
unsigned __int64 v113; // r11
char v114; // r12
__int64 ntoskrnl_base_addr; // rax
__int64 v116; // r9
__int64 v117; // rcx
__int64 v118; // rdx
__int64 v119; // r8
__int64 v120; // r9
__int64 v121; // r10
__int64 v122; // rdi
char *v123; // r14
char v124; // di
unsigned __int64 v125; // r13
unsigned __int64 v126; // r11
char v127; // r12
unsigned __int64 _22631; // rdx
_BYTE *_pattern; // rax
unsigned int n10; // ecx
__int64 v131; // r8
__int64 v132; // r9
__int64 idx; // r11
__int64 v134; // r9
__int64 v135; // rcx
__int64 v136; // r8
__int64 v137; // rdi
char *v138; // r14
char v139; // di
unsigned __int64 v140; // r13
unsigned __int64 v141; // r11
char v142; // r12
void (__stdcall *MmUnmapIoSpace_1)(PVOID, SIZE_T); // rax
__int64 v144; // r9
__int64 v145; // rcx
__int64 v146; // rdx
__int64 v147; // r8
__int64 v148; // r9
__int64 v149; // r10
__int64 v150; // rdi
char *v151; // r14
char v152; // di
unsigned __int64 v153; // r15
unsigned __int64 v154; // r11
char v155; // r12
bool v156; // zf
void (__fastcall *v157)(_BYTE *); // rax
__int64 v158; // r9
__int64 v159; // rcx
__int64 v160; // rdx
__int64 v161; // r8
__int64 v162; // r9
__int64 v163; // rdi
__int64 v164; // r14
char v165; // bl
char *v166; // r14
char v167; // bp
unsigned __int64 v168; // r15
__int64 v169; // rbx
char v170; // r12
_BYTE *v171; // r15
void (__stdcall *n1131796)(PVOID, ULONG); // rax
__int64 v173; // rcx
__int64 v174; // rdx
__int64 v175; // r11
__int64 v176; // rdi
char *v177; // r14
char v178; // di
unsigned __int64 v179; // r12
unsigned __int64 v180; // rsi
char v181; // r13
void (__fastcall *v182)(_BYTE *); // rax
_BYTE *to_match_page_3; // rcx
__int64 v184; // r9
__int64 v185; // r12
__int64 v186; // rdx
__int64 v187; // r8
__int64 v188; // r9
__int64 v189; // rdi
__int64 v190; // r14
char v191; // bl
char *v192; // r14
char v193; // bp
unsigned __int64 v194; // r15
__int64 v195; // rbx
char v196; // r13
void (__stdcall *ExFreePoolWithTag)(PVOID, ULONG); // rax
__int64 v198; // r9
__int64 v199; // rcx
__int64 v200; // rdx
__int64 v201; // r8
__int64 v202; // r9
__int64 v203; // rdi
__int64 v204; // r14
char v205; // bl
char *v206; // r14
char v207; // bp
unsigned __int64 v208; // r15
__int64 v209; // rbx
char v210; // r12
__int64 (__fastcall *i)(_QWORD, _QWORD, _QWORD, _QWORD, _QWORD); // rax
__int64 ntoskrnl_base_addr_1; // rax
__int64 v213; // r9
__int64 v214; // rcx
__int64 v215; // rdx
__int64 v216; // r8
__int64 v217; // r9
__int64 v218; // r11
__int64 v219; // rdi
char *v220; // r14
char v221; // di
unsigned __int64 v222; // r15
unsigned __int64 v223; // rsi
char v224; // bp
_BYTE *to_match_page_2; // [rsp+38h] [rbp-350h]
_QWORD *v227; // [rsp+40h] [rbp-348h]
_QWORD *v228; // [rsp+40h] [rbp-348h]
_QWORD *v230; // [rsp+48h] [rbp-340h]
_QWORD *v231; // [rsp+48h] [rbp-340h]
_BYTE *to_match_page; // [rsp+50h] [rbp-338h]
PPHYSICAL_MEMORY_RANGE v233; // [rsp+58h] [rbp-330h]
_OWORD *v234; // [rsp+60h] [rbp-328h]
_BYTE pattern[144]; // [rsp+70h] [rbp-318h] BYREF
char v237[8]; // [rsp+100h] [rbp-288h] BYREF
__m128 v238[17]; // [rsp+108h] [rbp-280h] BYREF
__m128 build_version[17]; // [rsp+21Ch] [rbp-16Ch] BYREF

v5 = a3;
v6 = a2;
MmAllocateContiguousMemory = ::MmAllocateContiguousMemory;
if ( !::MmAllocateContiguousMemory )
{
if ( ::ntoskrnl_base_addr
&& (v8 = *(unsigned int *)(::ntoskrnl_base_addr + *(int *)(::ntoskrnl_base_addr + 60) + 136),
v9 = *(unsigned int *)(::ntoskrnl_base_addr + v8 + 24),
*(_DWORD *)(::ntoskrnl_base_addr + v8 + 24)) )
{
v10 = ::ntoskrnl_base_addr + *(unsigned int *)(::ntoskrnl_base_addr + v8 + 28);
v11 = ::ntoskrnl_base_addr + *(unsigned int *)(::ntoskrnl_base_addr + v8 + 32);
v12 = ::ntoskrnl_base_addr + *(unsigned int *)(::ntoskrnl_base_addr + v8 + 36);
v13 = 0;
do
{
v14 = *(unsigned int *)(v11 + 4 * v13);
v15 = *(_BYTE *)(::ntoskrnl_base_addr + v14);
if ( v15 )
{
v16 = (char *)(::ntoskrnl_base_addr + v14 + 1);
v17 = v15;
v18 = 0xCBF29CE484222325uLL;
do
{
v19 = 0x100000001B3LL * (v18 ^ v17);
v20 = *v16++;
v17 = v20;
v18 = v19;
}
while ( v20 );
if ( v19 == 0x8CD9141D23428B07uLL )
{
MmAllocateContiguousMemory = (PVOID (__stdcall *)(SIZE_T, PHYSICAL_ADDRESS))(*(unsigned int *)(v10 + 4LL * *(unsigned __int16 *)(v12 + 2 * v13))
+ ::ntoskrnl_base_addr);
goto LABEL_13;
}
}
++v13;
}
while ( v13 != v9 );
MmAllocateContiguousMemory = (PVOID (__stdcall *)(SIZE_T, PHYSICAL_ADDRESS))&loc_114514;
LABEL_13:
v5 = a3;
v6 = a2;
}
else
{
MmAllocateContiguousMemory = (PVOID (__stdcall *)(SIZE_T, PHYSICAL_ADDRESS))&loc_114514;
}
::MmAllocateContiguousMemory = MmAllocateContiguousMemory;
}
to_match_page_5 = ((__int64 (__fastcall *)(__int64, __int64))MmAllocateContiguousMemory)(4096, -1);
if ( !to_match_page_5 )
{
sub_19E30((__int64)&qword_1D0FFEC, (__int64)&unk_2135F);
sub_19410(&qword_1D0FF30, &unk_2117C);
sub_1BCE0(&qword_1D102F0, &unk_21A82);
sub_1AFA0(&unk_1D10188, &unk_21706);
error_log((__int64)&qword_1D0FFEC, (__int64)&qword_1D0FF30, (__int64)&qword_1D102F0, 808, (__int64)&unk_1D10188);
return 0xC000009ALL;
}
to_match_page_1 = (_BYTE *)to_match_page_5;
MmGetPhysicalMemoryRanges = ::MmGetPhysicalMemoryRanges;
to_match_page = to_match_page_1;
if ( !::MmGetPhysicalMemoryRanges )
{
if ( ::ntoskrnl_base_addr
&& (v24 = *(unsigned int *)(::ntoskrnl_base_addr + *(int *)(::ntoskrnl_base_addr + 60) + 136),
v25 = *(unsigned int *)(::ntoskrnl_base_addr + v24 + 24),
*(_DWORD *)(::ntoskrnl_base_addr + v24 + 24)) )
{
v227 = v6;
v230 = v5;
v26 = ::ntoskrnl_base_addr + *(unsigned int *)(::ntoskrnl_base_addr + v24 + 28);
v27 = ::ntoskrnl_base_addr + *(unsigned int *)(::ntoskrnl_base_addr + v24 + 32);
v28 = ::ntoskrnl_base_addr + *(unsigned int *)(::ntoskrnl_base_addr + v24 + 36);
v29 = 0;
do
{
v30 = *(unsigned int *)(v27 + 4 * v29);
v31 = *(_BYTE *)(::ntoskrnl_base_addr + v30);
if ( v31 )
{
v32 = (char *)(::ntoskrnl_base_addr + v30 + 1);
v33 = v31;
v34 = 0xCBF29CE484222325uLL;
do
{
v35 = 0x100000001B3LL * (v34 ^ v33);
v36 = *v32++;
v33 = v36;
v34 = v35;
}
while ( v36 );
if ( v35 == 0x8A0AB57E2BF51C65uLL )
{
MmGetPhysicalMemoryRanges = (PPHYSICAL_MEMORY_RANGE (*)(void))(*(unsigned int *)(v26
+ 4LL
* *(unsigned __int16 *)(v28 + 2 * v29))
+ ::ntoskrnl_base_addr);
goto LABEL_29;
}
}
++v29;
}
while ( v29 != v25 );
MmGetPhysicalMemoryRanges = (PPHYSICAL_MEMORY_RANGE (*)(void))&loc_114514;
LABEL_29:
v5 = v230;
v6 = v227;
to_match_page_1 = to_match_page;
}
else
{
MmGetPhysicalMemoryRanges = (PPHYSICAL_MEMORY_RANGE (*)(void))&loc_114514;
}
::MmGetPhysicalMemoryRanges = MmGetPhysicalMemoryRanges;
}
to_match_page_2 = to_match_page_1;
v38 = MmGetPhysicalMemoryRanges();
if ( !v38 )
{
v182 = (void (__fastcall *)(_BYTE *))qword_1D15548;
to_match_page_3 = to_match_page_2;
if ( !qword_1D15548 )
{
if ( ::ntoskrnl_base_addr
&& (v184 = *(unsigned int *)(::ntoskrnl_base_addr + *(int *)(::ntoskrnl_base_addr + 60) + 136),
v185 = *(unsigned int *)(::ntoskrnl_base_addr + v184 + 24),
*(_DWORD *)(::ntoskrnl_base_addr + v184 + 24)) )
{
v186 = ::ntoskrnl_base_addr + *(unsigned int *)(::ntoskrnl_base_addr + v184 + 28);
v187 = ::ntoskrnl_base_addr + *(unsigned int *)(::ntoskrnl_base_addr + v184 + 32);
v188 = ::ntoskrnl_base_addr + *(unsigned int *)(::ntoskrnl_base_addr + v184 + 36);
v189 = 0;
do
{
v190 = *(unsigned int *)(v187 + 4 * v189);
v191 = *(_BYTE *)(::ntoskrnl_base_addr + v190);
if ( v191 )
{
v192 = (char *)(::ntoskrnl_base_addr + v190 + 1);
v193 = v191;
v194 = 0xCBF29CE484222325uLL;
do
{
v195 = 0x100000001B3LL * (v194 ^ v193);
v196 = *v192++;
v193 = v196;
v194 = v195;
}
while ( v196 );
if ( v195 == 0xD59511FF39773CA6uLL )
{
v182 = (void (__fastcall *)(_BYTE *))(*(unsigned int *)(v186 + 4LL
* *(unsigned __int16 *)(v188 + 2 * v189))
+ ::ntoskrnl_base_addr);
goto LABEL_194;
}
}
++v189;
}
while ( v189 != v185 );
v182 = (void (__fastcall *)(_BYTE *))&loc_114514;
LABEL_194:
to_match_page_3 = to_match_page_2;
}
else
{
v182 = (void (__fastcall *)(_BYTE *))&loc_114514;
}
qword_1D15548 = (__int64)v182;
}
v182(to_match_page_3);
sub_19E30((__int64)&qword_1D0FFEC, (__int64)&unk_2135F);
sub_19410(&qword_1D0FF30, &unk_2117C);
sub_1BCE0(&qword_1D102F0, &unk_21A82);
sub_1B110((__int64)&unk_1D101B8, (__int64)&unk_21764);
error_log((__int64)&qword_1D0FFEC, (__int64)&qword_1D0FF30, (__int64)&qword_1D102F0, 817, (__int64)&unk_1D101B8);
return 3221225995LL;
}
v228 = v6;
v231 = v5;
v234 = a4;
v233 = v38;
to_match_page_4 = to_match_page_2;
if ( !v38->BaseAddress.QuadPart )
goto LABEL_158;
n1970169159_1 = 0x100000001B3LL;
p_BaseAddress = &v38->BaseAddress;
do
{
if ( !p_BaseAddress[1].QuadPart )
goto LABEL_157;
v42.QuadPart = 0;
while ( 1 )
{
v44 = v42.QuadPart + p_BaseAddress->QuadPart;
MmCopyMemory = (int (__fastcall *)(_BYTE *, unsigned __int64, __int64, __int64, char *))::MmCopyMemory;
if ( !::MmCopyMemory )
{
if ( ::ntoskrnl_base_addr
&& (v46 = *(unsigned int *)(::ntoskrnl_base_addr + *(int *)(::ntoskrnl_base_addr + 60) + 136),
v47 = *(unsigned int *)(::ntoskrnl_base_addr + v46 + 24),
*(_DWORD *)(::ntoskrnl_base_addr + v46 + 24)) )
{
v48 = ::ntoskrnl_base_addr + *(unsigned int *)(::ntoskrnl_base_addr + v46 + 28);
v49 = ::ntoskrnl_base_addr + *(unsigned int *)(::ntoskrnl_base_addr + v46 + 32);
v50 = ::ntoskrnl_base_addr + *(unsigned int *)(::ntoskrnl_base_addr + v46 + 36);
v51 = 0;
do
{
v52 = *(unsigned int *)(v49 + 4 * v51);
v53 = *(_BYTE *)(::ntoskrnl_base_addr + v52);
if ( v53 )
{
v54 = (char *)(::ntoskrnl_base_addr + v52 + 1);
v55 = 0xCBF29CE484222325uLL;
do
{
v56 = n1970169159_1 * (v55 ^ v53);
v57 = *v54++;
v53 = v57;
v55 = v56;
}
while ( v57 );
if ( v56 == 0x306328EE8E049A39LL )
{
MmCopyMemory = (int (__fastcall *)(_BYTE *, unsigned __int64, __int64, __int64, char *))(*(unsigned int *)(v48 + 4LL * *(unsigned __int16 *)(v50 + 2 * v51)) + ::ntoskrnl_base_addr);
goto LABEL_51;
}
}
++v51;
}
while ( v51 != v47 );
MmCopyMemory = (int (__fastcall *)(_BYTE *, unsigned __int64, __int64, __int64, char *))&loc_114514;
LABEL_51:
to_match_page_4 = to_match_page_2;
}
else
{
MmCopyMemory = (int (__fastcall *)(_BYTE *, unsigned __int64, __int64, __int64, char *))&loc_114514;
}
::MmCopyMemory = (__int64)MmCopyMemory;
}
page_index = v44 & 0xFFFFFFFFFFFFF000uLL;
if ( MmCopyMemory(to_match_page_4, page_index, 4096, 1, v237) < 0 )// MM_COPY_MEMORY_PHYSICAL
goto new_page;
idx_ = -8;
do
{
if ( *(_QWORD *)&to_match_page_4[idx_ + 8] != -1 )
goto new_page;
idx_ += 8LL;
}
while ( idx_ <= 0xFF7 );
MmMaploSpace = (__int64 (__fastcall *)(unsigned __int64, __int64, _QWORD))::MmMaploSpace;
if ( !::MmMaploSpace )
{
if ( ::ntoskrnl_base_addr
&& (v61 = *(unsigned int *)(::ntoskrnl_base_addr + *(int *)(::ntoskrnl_base_addr + 60) + 136),
v62 = *(unsigned int *)(::ntoskrnl_base_addr + v61 + 24),
*(_DWORD *)(::ntoskrnl_base_addr + v61 + 24)) )
{
v63 = ::ntoskrnl_base_addr + *(unsigned int *)(::ntoskrnl_base_addr + v61 + 28);
v64 = ::ntoskrnl_base_addr + *(unsigned int *)(::ntoskrnl_base_addr + v61 + 32);
v65 = ::ntoskrnl_base_addr + *(unsigned int *)(::ntoskrnl_base_addr + v61 + 36);
v66 = 0;
do
{
v67 = *(unsigned int *)(v64 + 4 * v66);
if ( *(_BYTE *)(::ntoskrnl_base_addr + v67) )
{
v68 = (char *)(::ntoskrnl_base_addr + v67 + 1);
v69 = *(_BYTE *)(::ntoskrnl_base_addr + v67);
v70 = 0xCBF29CE484222325uLL;
do
{
v71 = n1970169159_1 * (v70 ^ v69);
v72 = *v68++;
v69 = v72;
v70 = v71;
}
while ( v72 );
if ( v71 == 0x40ED8EA987B20683LL )
{
MmMaploSpace = (__int64 (__fastcall *)(unsigned __int64, __int64, _QWORD))(*(unsigned int *)(v63 + 4LL * *(unsigned __int16 *)(v65 + 2 * v66))
+ ::ntoskrnl_base_addr);
goto LABEL_69;
}
}
++v66;
}
while ( v66 != v62 );
MmMaploSpace = (__int64 (__fastcall *)(unsigned __int64, __int64, _QWORD))&loc_114514;
LABEL_69:
to_match_page_4 = to_match_page_2;
}
else
{
MmMaploSpace = (__int64 (__fastcall *)(unsigned __int64, __int64, _QWORD))&loc_114514;
}
::MmMaploSpace = (__int64)MmMaploSpace;
}
va_kernel_page_from_physic = MmMaploSpace(page_index, 0x1000, 0);
if ( !va_kernel_page_from_physic )
goto new_page;
va_kernel_page_from_physic_ = va_kernel_page_from_physic;
if ( (int)doIOcontrol((__int64)to_match_page_4, va_kernel_page_from_physic) >= 0 )
break;
MmUnmapIoSpace = ::MmUnmapIoSpace;
if ( !::MmUnmapIoSpace )
{
ntoskrnl_base_addr = ::ntoskrnl_base_addr;
if ( !::ntoskrnl_base_addr )
goto LABEL_133;
v116 = *(unsigned int *)(::ntoskrnl_base_addr + *(int *)(::ntoskrnl_base_addr + 60) + 136);
v117 = *(unsigned int *)(::ntoskrnl_base_addr + v116 + 24);
if ( !*(_DWORD *)(::ntoskrnl_base_addr + v116 + 24) )
goto LABEL_133;
v118 = ::ntoskrnl_base_addr + *(unsigned int *)(::ntoskrnl_base_addr + v116 + 28);
v119 = ::ntoskrnl_base_addr + *(unsigned int *)(::ntoskrnl_base_addr + v116 + 32);
v120 = ::ntoskrnl_base_addr + *(unsigned int *)(::ntoskrnl_base_addr + v116 + 36);
v121 = 0;
do
{
v122 = *(unsigned int *)(v119 + 4 * v121);
if ( *(_BYTE *)(::ntoskrnl_base_addr + v122) )
{
v123 = (char *)(::ntoskrnl_base_addr + v122 + 1);
v124 = *(_BYTE *)(::ntoskrnl_base_addr + v122);
v125 = 0xCBF29CE484222325uLL;
do
{
v126 = n1970169159_1 * (v125 ^ v124);
v127 = *v123++;
v124 = v127;
v125 = v126;
}
while ( v127 );
if ( v126 == 0x47E1CA0E288956C0LL )
goto LABEL_107;
}
++v121;
}
while ( v121 != v117 );
LABEL_140:
MmUnmapIoSpace = (void (__stdcall *)(PVOID, SIZE_T))&loc_114514;
to_match_page_4 = to_match_page_2;
LABEL_141:
::MmUnmapIoSpace = MmUnmapIoSpace;
}
LABEL_37:
((void (__fastcall *)(__int64, __int64))MmUnmapIoSpace)(va_kernel_page_from_physic_, 4096);
new_page:
v42.QuadPart += 4096LL;
if ( v42.QuadPart >= (unsigned __int64)p_BaseAddress[1].QuadPart )
goto LABEL_157;
}
memset(pattern, 0, 80);
_RAX = 0;
n1970169159 = n1970169159_1;
__asm { cpuid }
n1970169159_2 = n1970169159;
LODWORD(n1970169159) = _RBX;
n1970169159_1 = n1970169159_2;
if ( (_DWORD)n1970169159 != 'uneG' || (_DWORD)_RDX != 'Ieni' || (_DWORD)_RCX != 'letn' )
{
_RAX = 0;
n1752462657 = n1970169159_1;
__asm { cpuid }
n1752462657_1 = n1752462657;
LODWORD(n1752462657) = _RBX;
n1970169159_1 = n1752462657_1;
if ( (_DWORD)n1752462657 != 'htuA' || (_DWORD)_RDX != 'itne' || (_DWORD)_RCX != 'DMAc' )
{
i = (__int64 (__fastcall *)(_QWORD, _QWORD, _QWORD, _QWORD, _QWORD))::i;
if ( ::i )
goto LABEL_218;
ntoskrnl_base_addr_1 = ::ntoskrnl_base_addr;
if ( ::ntoskrnl_base_addr )
{
v213 = *(unsigned int *)(::ntoskrnl_base_addr + *(int *)(::ntoskrnl_base_addr + 60) + 136);
v214 = *(unsigned int *)(::ntoskrnl_base_addr + v213 + 24);
if ( *(_DWORD *)(::ntoskrnl_base_addr + v213 + 24) )
goto LABEL_219;
}
LABEL_216:
for ( i = (__int64 (__fastcall *)(_QWORD, _QWORD, _QWORD, _QWORD, _QWORD))&loc_114514;
;
i = (__int64 (__fastcall *)(_QWORD, _QWORD, _QWORD, _QWORD, _QWORD))(*(unsigned int *)(v215 + 4LL * *(unsigned __int16 *)(v217 + 2 * v218))
+ ntoskrnl_base_addr_1) )
{
::i = (__int64)i;
LABEL_218:
ntoskrnl_base_addr_1 = i('WHAT', 'THE', 'HELL', 'CPU', 'THIS');// BugCheck
LABEL_219:
v215 = ntoskrnl_base_addr_1 + *(unsigned int *)(ntoskrnl_base_addr_1 + v213 + 28);
v216 = ntoskrnl_base_addr_1 + *(unsigned int *)(ntoskrnl_base_addr_1 + v213 + 32);
v217 = ntoskrnl_base_addr_1 + *(unsigned int *)(ntoskrnl_base_addr_1 + v213 + 36);
v218 = 0;
while ( 1 )
{
v219 = *(unsigned int *)(v216 + 4 * v218);
if ( *(_BYTE *)(ntoskrnl_base_addr_1 + v219) )
{
v220 = (char *)(ntoskrnl_base_addr_1 + v219 + 1);
v221 = *(_BYTE *)(ntoskrnl_base_addr_1 + v219);
v222 = 0xCBF29CE484222325uLL;
do
{
v223 = n1970169159_1 * (v222 ^ v221);
v224 = *v220++;
v221 = v224;
v222 = v223;
}
while ( v224 );
if ( v223 == 0x22E1FD0DBA67A3F2LL )
break;
}
if ( ++v218 == v214 )
goto LABEL_216;
}
}
}
sub_1180(v238, 0, 0x114u);
RtlGetVersion_1 = ::RtlGetVersion;
if ( !::RtlGetVersion )
{
if ( ::ntoskrnl_base_addr
&& (v103 = *(unsigned int *)(::ntoskrnl_base_addr + *(int *)(::ntoskrnl_base_addr + 60) + 136),
v104 = *(unsigned int *)(::ntoskrnl_base_addr + v103 + 24),
*(_DWORD *)(::ntoskrnl_base_addr + v103 + 24)) )
{
v105 = ::ntoskrnl_base_addr + *(unsigned int *)(::ntoskrnl_base_addr + v103 + 28);
v106 = ::ntoskrnl_base_addr + *(unsigned int *)(::ntoskrnl_base_addr + v103 + 32);
v107 = ::ntoskrnl_base_addr + *(unsigned int *)(::ntoskrnl_base_addr + v103 + 36);
v108 = 0;
do
{
v109 = *(unsigned int *)(v106 + 4 * v108);
if ( *(_BYTE *)(::ntoskrnl_base_addr + v109) )
{
v110 = (char *)(::ntoskrnl_base_addr + v109 + 1);
v111 = *(_BYTE *)(::ntoskrnl_base_addr + v109);
v112 = 0xCBF29CE484222325uLL;
do
{
v113 = n1970169159_1 * (v112 ^ v111);
v114 = *v110++;
v111 = v114;
v112 = v113;
}
while ( v114 );
if ( v113 == 0x2F0FCEED6FC55D71LL )
{
RtlGetVersion_1 = (NTSTATUS (__stdcall *)(PRTL_OSVERSIONINFOW))(*(unsigned int *)(v105
+ 4LL
* *(unsigned __int16 *)(v107 + 2 * v108))
+ ::ntoskrnl_base_addr);
goto LABEL_118;
}
}
++v108;
}
while ( v108 != v104 );
RtlGetVersion_1 = (NTSTATUS (__stdcall *)(PRTL_OSVERSIONINFOW))&loc_114514;
}
else
{
RtlGetVersion_1 = (NTSTATUS (__stdcall *)(PRTL_OSVERSIONINFOW))&loc_114514;
}
LABEL_118:
::RtlGetVersion = RtlGetVersion_1;
}
((void (__fastcall *)(__m128 *))RtlGetVersion_1)(v238);
if ( !version )
version = v238[0].m128_u32[3];
memset(&pattern[89], 0, 54);
memset(&pattern[84], 120, 5);
*(_QWORD *)pattern = &unk_21109;
strcpy(&pattern[8], "x????xxxxx");
*(_OWORD *)&pattern[29] = *(_OWORD *)&pattern[100];
*(_OWORD *)&pattern[45] = *(_OWORD *)&pattern[116];
*(_OWORD *)&pattern[56] = 0u;
pattern[19] = 0;
*(_WORD *)&pattern[20] = 0;
*(_DWORD *)&pattern[22] = 0;
*(_WORD *)&pattern[26] = 0;
pattern[28] = 0;
*(_QWORD *)&pattern[72] = 10;
_pattern = &unk_21109;
n10 = 10;
goto LABEL_122;
}
sub_1180(build_version, 0, 0x114u);
RtlGetVersion = ::RtlGetVersion;
if ( !::RtlGetVersion )
{
if ( ::ntoskrnl_base_addr
&& (v83 = *(unsigned int *)(::ntoskrnl_base_addr + *(int *)(::ntoskrnl_base_addr + 60) + 136),
v84 = *(unsigned int *)(::ntoskrnl_base_addr + v83 + 24),
*(_DWORD *)(::ntoskrnl_base_addr + v83 + 24)) )
{
v85 = ::ntoskrnl_base_addr + *(unsigned int *)(::ntoskrnl_base_addr + v83 + 28);
v86 = ::ntoskrnl_base_addr + *(unsigned int *)(::ntoskrnl_base_addr + v83 + 32);
v87 = ::ntoskrnl_base_addr + *(unsigned int *)(::ntoskrnl_base_addr + v83 + 36);
v88 = 0;
do
{
v89 = *(unsigned int *)(v86 + 4 * v88);
if ( *(_BYTE *)(::ntoskrnl_base_addr + v89) )
{
v90 = (char *)(::ntoskrnl_base_addr + v89 + 1);
v91 = *(_BYTE *)(::ntoskrnl_base_addr + v89);
v92 = 0xCBF29CE484222325uLL;
do
{
v93 = n1970169159_1 * (v92 ^ v91);
v94 = *v90++;
v91 = v94;
v92 = v93;
}
while ( v94 );
if ( v93 == 0x2F0FCEED6FC55D71LL )
{
RtlGetVersion = (NTSTATUS (__stdcall *)(PRTL_OSVERSIONINFOW))(*(unsigned int *)(v85
+ 4LL
* *(unsigned __int16 *)(v87 + 2 * v88))
+ ::ntoskrnl_base_addr);
goto LABEL_111;
}
}
++v88;
}
while ( v88 != v84 );
RtlGetVersion = (NTSTATUS (__stdcall *)(PRTL_OSVERSIONINFOW))&loc_114514;
LABEL_111:
to_match_page_4 = to_match_page_2;
}
else
{
RtlGetVersion = (NTSTATUS (__stdcall *)(PRTL_OSVERSIONINFOW))&loc_114514;
}
::RtlGetVersion = RtlGetVersion;
}
((void (__fastcall *)(__m128 *))RtlGetVersion)(build_version);
_22631 = version;
if ( !version )
{
_22631 = build_version[0].m128_u32[3];
version = build_version[0].m128_u32[3];
}
get_pattern(pattern, _22631);
_pattern = *(_BYTE **)pattern;
if ( *(_QWORD *)pattern )
{
n10 = *(_DWORD *)&pattern[72];
LABEL_122:
v131 = 0;
v132 = 0;
while ( n10 )
{
idx = 0;
while ( pattern[idx + 8] != 'x' || to_match_page[(unsigned int)v132 + idx] == _pattern[idx] )
{
if ( n10 == ++idx )
goto LABEL_168;
}
v132 = (unsigned int)(v132 + 1);
v131 = (unsigned int)v132;
if ( 4096 - (unsigned __int64)n10 < (unsigned int)v132 )
{
MmUnmapIoSpace = ::MmUnmapIoSpace;
to_match_page_4 = to_match_page_2;
if ( !::MmUnmapIoSpace )
{
ntoskrnl_base_addr = ::ntoskrnl_base_addr;
if ( ::ntoskrnl_base_addr )
{
v134 = *(unsigned int *)(::ntoskrnl_base_addr + *(int *)(::ntoskrnl_base_addr + 60) + 136);
v135 = *(unsigned int *)(::ntoskrnl_base_addr + v134 + 24);
if ( *(_DWORD *)(::ntoskrnl_base_addr + v134 + 24) )
{
v118 = ::ntoskrnl_base_addr + *(unsigned int *)(::ntoskrnl_base_addr + v134 + 28);
v136 = ::ntoskrnl_base_addr + *(unsigned int *)(::ntoskrnl_base_addr + v134 + 32);
v120 = ::ntoskrnl_base_addr + *(unsigned int *)(::ntoskrnl_base_addr + v134 + 36);
v121 = 0;
while ( 1 )
{
v137 = *(unsigned int *)(v136 + 4 * v121);
if ( *(_BYTE *)(::ntoskrnl_base_addr + v137) )
{
v138 = (char *)(::ntoskrnl_base_addr + v137 + 1);
v139 = *(_BYTE *)(::ntoskrnl_base_addr + v137);
v140 = 0xCBF29CE484222325uLL;
do
{
v141 = n1970169159_1 * (v140 ^ v139);
v142 = *v138++;
v139 = v142;
v140 = v141;
}
while ( v142 );
if ( v141 == 0x47E1CA0E288956C0LL )
break;
}
if ( ++v121 == v135 )
goto LABEL_140;
}
LABEL_107:
to_match_page_4 = to_match_page_2;
MmUnmapIoSpace = (void (__stdcall *)(PVOID, SIZE_T))(ntoskrnl_base_addr
+ *(unsigned int *)(v118
+ 4LL
* *(unsigned __int16 *)(v120 + 2 * v121)));
goto LABEL_141;
}
}
LABEL_133:
MmUnmapIoSpace = (void (__stdcall *)(PVOID, SIZE_T))&loc_114514;
goto LABEL_141;
}
goto LABEL_37;
}
}
LABEL_168:
*a1 = va_kernel_page_from_physic_;
*v228 = to_match_page_2;
v171 = &to_match_page[v131 + *(unsigned int *)&pattern[76]];
*v231 = v171;
*v234 = *(_OWORD *)&p_BaseAddress->LowPart;
n1131796 = ::ExFreePoolWithTag;
if ( !::ExFreePoolWithTag )
{
if ( ::ntoskrnl_base_addr
&& (v132 = *(unsigned int *)(::ntoskrnl_base_addr + *(int *)(::ntoskrnl_base_addr + 60) + 136),
v173 = *(unsigned int *)(::ntoskrnl_base_addr + v132 + 24),
*(_DWORD *)(::ntoskrnl_base_addr + v132 + 24)) )
{
v174 = ::ntoskrnl_base_addr + *(unsigned int *)(::ntoskrnl_base_addr + v132 + 28);
v131 = ::ntoskrnl_base_addr + *(unsigned int *)(::ntoskrnl_base_addr + v132 + 32);
v132 = ::ntoskrnl_base_addr + *(unsigned int *)(::ntoskrnl_base_addr + v132 + 36);
v175 = 0;
while ( 1 )
{
v176 = *(unsigned int *)(v131 + 4 * v175);
if ( *(_BYTE *)(::ntoskrnl_base_addr + v176) )
{
v177 = (char *)(::ntoskrnl_base_addr + v176 + 1);
v178 = *(_BYTE *)(::ntoskrnl_base_addr + v176);
v179 = 0xCBF29CE484222325uLL;
do
{
v180 = n1970169159_1 * (v179 ^ v178);
v181 = *v177++;
v178 = v181;
v179 = v180;
}
while ( v181 );
if ( v180 == 0x7F6272C86A6EEADCLL )
break;
}
if ( ++v175 == v173 )
goto LABEL_188;
}
n1131796 = (void (__stdcall *)(PVOID, ULONG))(*(unsigned int *)(v174
+ 4LL * *(unsigned __int16 *)(v132 + 2 * v175))
+ ::ntoskrnl_base_addr);
}
else
{
LABEL_188:
n1131796 = (void (__stdcall *)(PVOID, ULONG))&loc_114514;
}
::ExFreePoolWithTag = n1131796;
}
((void (__fastcall *)(PPHYSICAL_MEMORY_RANGE, _QWORD, __int64, __int64))n1131796)(v233, 0, v131, v132);
sub_19E30((__int64)&qword_1D0FFEC, (__int64)&unk_2135F);
sub_19410(&qword_1D0FF30, &unk_2117C);
sub_1BCE0(&qword_1D102F0, &unk_21A82);
sub_1B400(&qword_1D101EC, &unk_217FE);
sub_18540(
(__int64)&qword_1D0FFEC,
(__int64)&qword_1D0FF30,
(__int64)&qword_1D102F0,
898,
(__int64)&qword_1D101EC,
va_kernel_page_from_physic_,
(__int64)v171);
return 0;
}
sub_19570(&unk_1D0FF68, &unk_211E9);
sub_19410(&qword_1D0FF30, &unk_2117C);
sub_1BCE0(&qword_1D102F0, &unk_21A82);
sub_1B280(&unk_1D101D8, &unk_217BA);
error_log((__int64)&unk_1D0FF68, (__int64)&qword_1D0FF30, (__int64)&qword_1D102F0, 867, (__int64)&unk_1D101D8);
MmUnmapIoSpace_1 = ::MmUnmapIoSpace;
if ( !::MmUnmapIoSpace )
{
if ( ::ntoskrnl_base_addr
&& (v144 = *(unsigned int *)(::ntoskrnl_base_addr + *(int *)(::ntoskrnl_base_addr + 60) + 136),
v145 = *(unsigned int *)(::ntoskrnl_base_addr + v144 + 24),
*(_DWORD *)(::ntoskrnl_base_addr + v144 + 24)) )
{
v146 = ::ntoskrnl_base_addr + *(unsigned int *)(::ntoskrnl_base_addr + v144 + 28);
v147 = ::ntoskrnl_base_addr + *(unsigned int *)(::ntoskrnl_base_addr + v144 + 32);
v148 = ::ntoskrnl_base_addr + *(unsigned int *)(::ntoskrnl_base_addr + v144 + 36);
v149 = 0;
do
{
v150 = *(unsigned int *)(v147 + 4 * v149);
if ( *(_BYTE *)(::ntoskrnl_base_addr + v150) )
{
v151 = (char *)(::ntoskrnl_base_addr + v150 + 1);
v152 = *(_BYTE *)(::ntoskrnl_base_addr + v150);
v153 = 0xCBF29CE484222325uLL;
do
{
v154 = n1970169159_1 * (v153 ^ v152);
v155 = *v151++;
v152 = v155;
v153 = v154;
}
while ( v155 );
if ( v154 == 0x47E1CA0E288956C0LL )
{
MmUnmapIoSpace_1 = (void (__stdcall *)(PVOID, SIZE_T))(*(unsigned int *)(v146
+ 4LL
* *(unsigned __int16 *)(v148 + 2 * v149))
+ ::ntoskrnl_base_addr);
goto LABEL_154;
}
}
++v149;
}
while ( v149 != v145 );
MmUnmapIoSpace_1 = (void (__stdcall *)(PVOID, SIZE_T))&loc_114514;
LABEL_154:
to_match_page_4 = to_match_page_2;
}
else
{
MmUnmapIoSpace_1 = (void (__stdcall *)(PVOID, SIZE_T))&loc_114514;
}
::MmUnmapIoSpace = MmUnmapIoSpace_1;
}
((void (__fastcall *)(__int64, __int64))MmUnmapIoSpace_1)(va_kernel_page_from_physic_, 4096);
LABEL_157:
v156 = p_BaseAddress[2].QuadPart == 0;
p_BaseAddress += 2;
}
while ( !v156 );
LABEL_158:
v157 = (void (__fastcall *)(_BYTE *))qword_1D15548;
if ( !qword_1D15548 )
{
if ( ::ntoskrnl_base_addr
&& (v158 = *(unsigned int *)(::ntoskrnl_base_addr + *(int *)(::ntoskrnl_base_addr + 60) + 136),
v159 = *(unsigned int *)(::ntoskrnl_base_addr + v158 + 24),
*(_DWORD *)(::ntoskrnl_base_addr + v158 + 24)) )
{
v160 = ::ntoskrnl_base_addr + *(unsigned int *)(::ntoskrnl_base_addr + v158 + 28);
v161 = ::ntoskrnl_base_addr + *(unsigned int *)(::ntoskrnl_base_addr + v158 + 32);
v162 = ::ntoskrnl_base_addr + *(unsigned int *)(::ntoskrnl_base_addr + v158 + 36);
v163 = 0;
do
{
v164 = *(unsigned int *)(v161 + 4 * v163);
v165 = *(_BYTE *)(::ntoskrnl_base_addr + v164);
if ( v165 )
{
v166 = (char *)(::ntoskrnl_base_addr + v164 + 1);
v167 = v165;
v168 = 0xCBF29CE484222325uLL;
do
{
v169 = 0x100000001B3LL * (v168 ^ v167);
v170 = *v166++;
v167 = v170;
v168 = v169;
}
while ( v170 );
if ( v169 == 0xD59511FF39773CA6uLL )
{
v157 = (void (__fastcall *)(_BYTE *))(*(unsigned int *)(v160 + 4LL * *(unsigned __int16 *)(v162 + 2 * v163))
+ ::ntoskrnl_base_addr);
goto LABEL_198;
}
}
++v163;
}
while ( v163 != v159 );
v157 = (void (__fastcall *)(_BYTE *))&loc_114514;
LABEL_198:
to_match_page_4 = to_match_page_2;
}
else
{
v157 = (void (__fastcall *)(_BYTE *))&loc_114514;
}
qword_1D15548 = (__int64)v157;
}
v157(to_match_page_4);
ExFreePoolWithTag = ::ExFreePoolWithTag;
if ( !::ExFreePoolWithTag )
{
if ( ::ntoskrnl_base_addr
&& (v198 = *(unsigned int *)(::ntoskrnl_base_addr + *(int *)(::ntoskrnl_base_addr + 60) + 136),
v199 = *(unsigned int *)(::ntoskrnl_base_addr + v198 + 24),
*(_DWORD *)(::ntoskrnl_base_addr + v198 + 24)) )
{
v200 = ::ntoskrnl_base_addr + *(unsigned int *)(::ntoskrnl_base_addr + v198 + 28);
v201 = ::ntoskrnl_base_addr + *(unsigned int *)(::ntoskrnl_base_addr + v198 + 32);
v202 = ::ntoskrnl_base_addr + *(unsigned int *)(::ntoskrnl_base_addr + v198 + 36);
v203 = 0;
while ( 1 )
{
v204 = *(unsigned int *)(v201 + 4 * v203);
v205 = *(_BYTE *)(::ntoskrnl_base_addr + v204);
if ( v205 )
{
v206 = (char *)(::ntoskrnl_base_addr + v204 + 1);
v207 = v205;
v208 = 0xCBF29CE484222325uLL;
do
{
v209 = 0x100000001B3LL * (v208 ^ v207);
v210 = *v206++;
v207 = v210;
v208 = v209;
}
while ( v210 );
if ( v209 == 0x7F6272C86A6EEADCLL )
break;
}
if ( ++v203 == v199 )
goto LABEL_210;
}
ExFreePoolWithTag = (void (__stdcall *)(PVOID, ULONG))(*(unsigned int *)(v200
+ 4LL
* *(unsigned __int16 *)(v202 + 2 * v203))
+ ::ntoskrnl_base_addr);
}
else
{
LABEL_210:
ExFreePoolWithTag = (void (__stdcall *)(PVOID, ULONG))&loc_114514;
}
::ExFreePoolWithTag = ExFreePoolWithTag;
}
((void (__fastcall *)(PPHYSICAL_MEMORY_RANGE, _QWORD))ExFreePoolWithTag)(v233, 0);
return 0xC0000225LL;
}

总体来说就是遍历物理页寻找某个根据Windows版本生成的模式, 在赛题文档推荐的系统版本下, 该模式为xxxx?xxx????xxxxxx?x????x, 这套掩码作用到21090处的代码上用来进行匹配(48 8B 0C 24 ?? eb 07 e8 ?? ?? ?? ?? eb f2 48 8b 54 24 ?? e8 ?? ?? ?? ?? e9):

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
_OWORD *__fastcall get_pattern(_BYTE *pattern, unsigned __int64 _22631)
{
__int64 n28_1; // rax
__int64 n28; // r15

*((_OWORD *)pattern + 4) = 0;
*((_OWORD *)pattern + 3) = 0;
*((_OWORD *)pattern + 2) = 0;
*((_OWORD *)pattern + 1) = 0;
*(_OWORD *)pattern = 0;
if ( _22631 < 0x585D )
{
if ( _22631 < 0x4A61 )
{
if ( _22631 >= 0x4563 )
{
*(_QWORD *)pattern = sub_21090;
*((_QWORD *)pattern + 9) = 0x1300000019LL;
qmemcpy(pattern + 8, "xxxx?xxx????xxxxxx?x????", 0x18);
goto LABEL_11;
}
if ( _22631 < 0x42EE )
{
if ( _22631 < 0x295A )
{
if ( _22631 < 0x2800 )
return pattern;
*(_QWORD *)pattern = &unk_210F0;
*((_QWORD *)pattern + 9) = 0x1300000019LL;
qmemcpy(pattern + 8, "xxxxxxxxxxxxxxx????x", 20);
goto LABEL_8;
}
*(_QWORD *)pattern = &unk_210D0;
*((_QWORD *)pattern + 9) = 0x1300000019LL;
qmemcpy(pattern + 8, "xx????x?xx????xxxx", 18);
}
else
{
*(_QWORD *)pattern = sub_210B0;
*((_QWORD *)pattern + 9) = 0x1300000019LL;
qmemcpy(pattern + 8, "xxxxxxx?xx????xxxx", 18);
}
}
else
{
*(_QWORD *)pattern = &unk_21070;
*((_QWORD *)pattern + 9) = 0x1300000019LL;
qmemcpy(pattern + 8, "xxxxxxxxxxxxx?xxxx", 18);
}
*((_WORD *)pattern + 13) = 0x783F;
LABEL_8:
*((_DWORD *)pattern + 7) = 0x3F3F3F3F;
LABEL_11:
pattern[0x20] = 'x';
return pattern;
}
*(_QWORD *)pattern = &unk_21050;
*((_QWORD *)pattern + 9) = 0x170000001DLL;
n28_1 = 0;
do
{
n28 = n28_1;
sub_1B580(byte_1D10224, &unk_21869);
pattern[n28 + 8] = byte_1D10224[n28];
n28_1 = n28 + 1;
}
while ( n28 != 28 );
pattern[37] = 0;
return pattern;
}

这里通过MmGetPhysicalMemoryRanges获取到连续的物理内存后检查其是否全为空闲页(全为ff), 如果是的话进入0000000000003E10, 先是在sub_3EB0中进行了一些PTE位操作后通过IOCTL_SCSI_PASS_THROUGH_DIRECT\Driver\disk进行通信:

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
__int64 __fastcall doIOcontrol(__int64 to_match_page, __int64 va_kernel_page_from_physic)
{
__int64 v4; // rdi
__int64 result; // rax
unsigned int v6; // esi
__int64 *v7; // [rsp+28h] [rbp-20h] BYREF

if ( !byte_1D0FD10 )
return 0xC00000A3LL;
v7 = 0;
v4 = sub_3EB0(va_kernel_page_from_physic, &v7);
result = core_logic(*(_QWORD *)disk_device, 0x2A, va_kernel_page_from_physic);
if ( v7 )
*v7 = v4;
if ( (int)result >= 0 )
{
v6 = core_logic(*(_QWORD *)disk_device, 0x28, to_match_page);
core_logic(*(_QWORD *)disk_device, 0x2A, disk_device + 8);
return v6;
}
return result;
}
__int64 __fastcall core_logic(__int64 a1, char n42, __int64 a3)
{
void (__stdcall *KeInitializeEvent)(PRKEVENT, EVENT_TYPE, BOOLEAN); // rax
__int64 v7; // r9
__int64 v8; // rcx
__int64 v9; // r8
__int64 v10; // r9
__int64 v11; // r15
__int64 v12; // r12
char v13; // bp
char *v14; // r13
unsigned __int64 v15; // r10
__int64 v16; // r12
char v17; // si
PIRP (__stdcall *IoBuildDeviceIoControlRequest)(ULONG, PDEVICE_OBJECT, PVOID, ULONG, PVOID, ULONG, BOOLEAN, PKEVENT, PIO_STATUS_BLOCK); // rax
__int64 v19; // r9
__int64 v20; // rcx
__int64 v21; // rdx
__int64 v22; // r8
__int64 v23; // r9
__int64 v24; // r14
__int64 v25; // r15
char v26; // bp
char *v27; // r12
unsigned __int64 v28; // r13
__int64 v29; // r15
char v30; // si
__int64 v31; // rax
__int64 v32; // rdx
NTSTATUS (__stdcall *IofCallDriver)(PDEVICE_OBJECT, PIRP); // rax
__int64 v34; // r10
__int64 v35; // rcx
__int64 v36; // r8
__int64 v37; // r9
__int64 v38; // r10
__int64 v39; // r14
__int64 v40; // r15
char v41; // bp
char *v42; // r12
unsigned __int64 v43; // r13
__int64 v44; // r15
char v45; // si
unsigned int n259; // ecx
NTSTATUS (__stdcall *KeWaitForSingleObject)(PVOID, KWAIT_REASON, KPROCESSOR_MODE, BOOLEAN, PLARGE_INTEGER); // rax
__int64 v48; // r9
__int64 v49; // rcx
__int64 v50; // rdx
__int64 v51; // r8
__int64 v52; // r9
__int64 v53; // rdi
__int64 v54; // r14
char v55; // bl
char *v56; // r14
char v57; // bp
unsigned __int64 v58; // r15
__int64 v59; // rbx
char v60; // r12
__int64 v62; // [rsp+48h] [rbp-B0h]
__int64 v63; // [rsp+48h] [rbp-B0h]
__int64 v64; // [rsp+48h] [rbp-B0h]
__int128 v65; // [rsp+50h] [rbp-A8h] BYREF
__int64 n5; // [rsp+60h] [rbp-98h]
__int64 v67; // [rsp+68h] [rbp-90h]
int n56; // [rsp+70h] [rbp-88h]
char v69; // [rsp+74h] [rbp-84h]
_BYTE v70[7]; // [rsp+75h] [rbp-83h] BYREF
int n8; // [rsp+7Ch] [rbp-7Ch]
__int64 v72; // [rsp+80h] [rbp-78h]
__int64 v73; // [rsp+88h] [rbp-70h]
_DWORD v74[4]; // [rsp+90h] [rbp-68h] BYREF
_BYTE v75[88]; // [rsp+A0h] [rbp-58h] BYREF

KeInitializeEvent = ::KeInitializeEvent;
if ( !::KeInitializeEvent )
{
if ( ntoskrnl_base_addr
&& (v7 = *(unsigned int *)(ntoskrnl_base_addr + *(int *)(ntoskrnl_base_addr + 60) + 136),
v8 = *(unsigned int *)(ntoskrnl_base_addr + v7 + 24),
*(_DWORD *)(ntoskrnl_base_addr + v7 + 24)) )
{
v62 = a1;
v73 = ntoskrnl_base_addr + *(unsigned int *)(ntoskrnl_base_addr + v7 + 28);
v9 = ntoskrnl_base_addr + *(unsigned int *)(ntoskrnl_base_addr + v7 + 32);
v10 = ntoskrnl_base_addr + *(unsigned int *)(ntoskrnl_base_addr + v7 + 36);
v11 = 0;
do
{
v12 = *(unsigned int *)(v9 + 4 * v11);
v13 = *(_BYTE *)(ntoskrnl_base_addr + v12);
if ( v13 )
{
v14 = (char *)(ntoskrnl_base_addr + v12 + 1);
v15 = 0xCBF29CE484222325uLL;
do
{
v16 = 0x100000001B3LL * (v15 ^ v13);
v17 = *v14++;
v13 = v17;
v15 = v16;
}
while ( v17 );
if ( v16 == 0xD9FE78EA5EE16A1LL )
{
KeInitializeEvent = (void (__stdcall *)(PRKEVENT, EVENT_TYPE, BOOLEAN))(*(unsigned int *)(v73 + 4LL * *(unsigned __int16 *)(v10 + 2 * v11))
+ ntoskrnl_base_addr);
goto LABEL_13;
}
}
++v11;
}
while ( v11 != v8 );
KeInitializeEvent = (void (__stdcall *)(PRKEVENT, EVENT_TYPE, BOOLEAN))&loc_114514;
LABEL_13:
a1 = v62;
}
else
{
KeInitializeEvent = (void (__stdcall *)(PRKEVENT, EVENT_TYPE, BOOLEAN))&loc_114514;
}
::KeInitializeEvent = KeInitializeEvent;
}
((void (__fastcall *)(_BYTE *, __int64, _QWORD))KeInitializeEvent)(v75, 1, 0);
v65 = 0;
n8 = 8;
v72 = 0;
LOWORD(v65) = 56;
BYTE6(v65) = 10;
n56 = 56;
HIDWORD(v65) = 4096;
n5 = 5;
v67 = a3;
v69 = (2 * (n42 == 0x2A)) | 0x28;
memset(v70, 0, sizeof(v70));
IoBuildDeviceIoControlRequest = ::IoBuildDeviceIoControlRequest;
if ( !::IoBuildDeviceIoControlRequest )
{
if ( ntoskrnl_base_addr
&& (v19 = *(unsigned int *)(ntoskrnl_base_addr + *(int *)(ntoskrnl_base_addr + 60) + 136),
v20 = *(unsigned int *)(ntoskrnl_base_addr + v19 + 24),
*(_DWORD *)(ntoskrnl_base_addr + v19 + 24)) )
{
v63 = a1;
v21 = ntoskrnl_base_addr + *(unsigned int *)(ntoskrnl_base_addr + v19 + 28);
v22 = ntoskrnl_base_addr + *(unsigned int *)(ntoskrnl_base_addr + v19 + 32);
v23 = ntoskrnl_base_addr + *(unsigned int *)(ntoskrnl_base_addr + v19 + 36);
v24 = 0;
do
{
v25 = *(unsigned int *)(v22 + 4 * v24);
v26 = *(_BYTE *)(ntoskrnl_base_addr + v25);
if ( v26 )
{
v27 = (char *)(ntoskrnl_base_addr + v25 + 1);
v28 = 0xCBF29CE484222325uLL;
do
{
v29 = 0x100000001B3LL * (v28 ^ v26);
v30 = *v27++;
v26 = v30;
v28 = v29;
}
while ( v30 );
if ( v29 == 0x1D9B1572A04955D7LL )
{
IoBuildDeviceIoControlRequest = (PIRP (__stdcall *)(ULONG, PDEVICE_OBJECT, PVOID, ULONG, PVOID, ULONG, BOOLEAN, PKEVENT, PIO_STATUS_BLOCK))(*(unsigned int *)(v21 + 4LL * *(unsigned __int16 *)(v23 + 2 * v24)) + ntoskrnl_base_addr);
goto LABEL_27;
}
}
++v24;
}
while ( v24 != v20 );
IoBuildDeviceIoControlRequest = (PIRP (__stdcall *)(ULONG, PDEVICE_OBJECT, PVOID, ULONG, PVOID, ULONG, BOOLEAN, PKEVENT, PIO_STATUS_BLOCK))&loc_114514;
LABEL_27:
a1 = v63;
}
else
{
IoBuildDeviceIoControlRequest = (PIRP (__stdcall *)(ULONG, PDEVICE_OBJECT, PVOID, ULONG, PVOID, ULONG, BOOLEAN, PKEVENT, PIO_STATUS_BLOCK))&loc_114514;
}
::IoBuildDeviceIoControlRequest = IoBuildDeviceIoControlRequest;
}
v31 = ((__int64 (__fastcall *)(__int64, __int64, __int128 *, __int64, _QWORD, _DWORD, _BYTE, _BYTE *, _DWORD *))IoBuildDeviceIoControlRequest)(
0x4D014,
a1,
&v65,
56,
0,
0,
0,
v75,
v74);
if ( v31 )
{
v32 = v31;
IofCallDriver = ::IofCallDriver;
if ( !::IofCallDriver )
{
if ( ntoskrnl_base_addr
&& (v34 = *(unsigned int *)(ntoskrnl_base_addr + *(int *)(ntoskrnl_base_addr + 60) + 136),
v35 = *(unsigned int *)(ntoskrnl_base_addr + v34 + 24),
*(_DWORD *)(ntoskrnl_base_addr + v34 + 24)) )
{
v64 = a1;
v36 = ntoskrnl_base_addr + *(unsigned int *)(ntoskrnl_base_addr + v34 + 28);
v37 = ntoskrnl_base_addr + *(unsigned int *)(ntoskrnl_base_addr + v34 + 32);
v38 = ntoskrnl_base_addr + *(unsigned int *)(ntoskrnl_base_addr + v34 + 36);
v39 = 0;
do
{
v40 = *(unsigned int *)(v37 + 4 * v39);
v41 = *(_BYTE *)(ntoskrnl_base_addr + v40);
if ( v41 )
{
v42 = (char *)(ntoskrnl_base_addr + v40 + 1);
v43 = 0xCBF29CE484222325uLL;
do
{
v44 = 0x100000001B3LL * (v43 ^ v41);
v45 = *v42++;
v41 = v45;
v43 = v44;
}
while ( v45 );
if ( v44 == 0xC26886D76545A61BuLL )
{
IofCallDriver = (NTSTATUS (__stdcall *)(PDEVICE_OBJECT, PIRP))(*(unsigned int *)(v36
+ 4LL
* *(unsigned __int16 *)(v38 + 2 * v39))
+ ntoskrnl_base_addr);
goto LABEL_43;
}
}
++v39;
}
while ( v39 != v35 );
IofCallDriver = (NTSTATUS (__stdcall *)(PDEVICE_OBJECT, PIRP))&loc_114514;
LABEL_43:
a1 = v64;
}
else
{
IofCallDriver = (NTSTATUS (__stdcall *)(PDEVICE_OBJECT, PIRP))&loc_114514;
}
::IofCallDriver = IofCallDriver;
}
n259 = ((__int64 (__fastcall *)(__int64, __int64))IofCallDriver)(a1, v32);
if ( n259 == 0x103 )
{
KeWaitForSingleObject = ::KeWaitForSingleObject;
if ( !::KeWaitForSingleObject )
{
if ( ntoskrnl_base_addr
&& (v48 = *(unsigned int *)(ntoskrnl_base_addr + *(int *)(ntoskrnl_base_addr + 60) + 136),
v49 = *(unsigned int *)(ntoskrnl_base_addr + v48 + 24),
*(_DWORD *)(ntoskrnl_base_addr + v48 + 24)) )
{
v50 = ntoskrnl_base_addr + *(unsigned int *)(ntoskrnl_base_addr + v48 + 28);
v51 = ntoskrnl_base_addr + *(unsigned int *)(ntoskrnl_base_addr + v48 + 32);
v52 = ntoskrnl_base_addr + *(unsigned int *)(ntoskrnl_base_addr + v48 + 36);
v53 = 0;
while ( 1 )
{
v54 = *(unsigned int *)(v51 + 4 * v53);
v55 = *(_BYTE *)(ntoskrnl_base_addr + v54);
if ( v55 )
{
v56 = (char *)(ntoskrnl_base_addr + v54 + 1);
v57 = v55;
v58 = 0xCBF29CE484222325uLL;
do
{
v59 = 0x100000001B3LL * (v58 ^ v57);
v60 = *v56++;
v57 = v60;
v58 = v59;
}
while ( v60 );
if ( v59 == 0x11BDFAD31435CB3CLL )
break;
}
if ( ++v53 == v49 )
goto LABEL_56;
}
KeWaitForSingleObject = (NTSTATUS (__stdcall *)(PVOID, KWAIT_REASON, KPROCESSOR_MODE, BOOLEAN, PLARGE_INTEGER))(*(unsigned int *)(v50 + 4LL * *(unsigned __int16 *)(v52 + 2 * v53)) + ntoskrnl_base_addr);
}
else
{
LABEL_56:
KeWaitForSingleObject = (NTSTATUS (__stdcall *)(PVOID, KWAIT_REASON, KPROCESSOR_MODE, BOOLEAN, PLARGE_INTEGER))&loc_114514;
}
::KeWaitForSingleObject = KeWaitForSingleObject;
}
((void (__fastcall *)(_BYTE *, _QWORD, _QWORD, _QWORD, _QWORD))KeWaitForSingleObject)(v75, 0, 0, 0, 0);
return v74[0];
}
}
else
{
return (unsigned int)-1073741670;
}
return n259;
}

有可能就是在这里通过物理地址转虚拟地址间接写入关键逻辑, 但是调试发现用于匹配的页永远都是全ff的空闲页, 页内无任何数据写入导致该函数永远匹配不到目标模式, 返回0xC0000225, 偶尔也能在内核调试器的输出中看到该驱动(hypercharge)进行日志输出该错误码, 也可能就是因为这里无法匹配到目标模式导致驱动没有成功运行关键逻辑(VT启动等), 但是也未发生蓝屏等现象.

上面就是决赛提交的wp, 下面就是后面断断续续做完了写的wp

补充一个调试驱动的方法, 从三环应用中分离出来的驱动在DriverEntry中第一个进入的函数本身是个安全检查函数, 可以改成一个int3然后直接返回:

image-20260422211601717

在该断点断下后用以下Windbg指令获取模块基址, 在IDA中将驱动 rebase 成 0, 很方便能下断点:

1
2
3
r @$t0=@rip-0x1D34000
bp @$t0+CD09
g

唯一的问题就是每次环境只能断下一次, 因为三环应用的逻辑是安装驱动前会先检查cpuid的行为是否是已经安装驱动后的, 如果是的话跳过安装驱动, 所以记得拍好快照

下面基于已经分析了的内容在开启Hyper-V后继续解题

开启Hyper-V后成功断在匹配模式成功点, 说明开启Hyper-V后才能成功匹配到模式:

image-20260422212043136

继续大调查这个匹配成功得到的地址, 发现只有题目驱动处理过的这个页是可以读取的, 而且它自己还输出了日志, 表明这里是在根据系统版本匹配VMExitHandler:

image-20260422212709207

查询资料可以知道, 原来Hyper-V自己有一套完整的VT-x框架, 包括VMExit之后的分发逻辑, 那么这里大概率就是在寻找这个分发器并 hook cpuid对应的VMExitHandler, 在调试机上把hvix64.exe拉下来之后找到这个模式, 发现它的目标是这个模式 +13h偏移处的一条call:

QQ_1776927614628

让AI分析, 在FC40找到了高可疑的inline hook + trampoline跳回标志代码:

QQ_1776948019521

那么基本可以确定是hook了hvix64.execpuid VMExitHandler, 另外还得知该攻击手法为Diskjacker

接下来让AI继续寻找驱动自己的handler, 因为直接寻找几个cpuid通信的控制码无果, 大概率不是直接对比来分发, 或者是隐藏了代码需要解密, AI分析得出的结果是驱动还在E630手动映射了一个隐藏驱动:

QQ_1776949120747

Windbg在关键函数下断点dump出这个映像IDA就能分析了, 成功在里面找到了上面分析出来的几个导出对象中包含flag验证的部分:

QQ_1776950933407

至此可以得出第二问的回答如下:

  1. 三环应用创建了磁盘设备栈
  2. 驱动层遍历物理内存范围筛选全为ff的空闲页, 因为Hyper-V隐藏自身代码页后其代码页读的结果就是全ff的空闲页
  3. 驱动层通过IOCTL_SCSI_PASS_THROUGH_DIRECT(0x4d014)控制码与磁盘设备栈通信对筛选出的空闲页进行DDMA, 绕过CPU读写内存会被EPT拦截的限制(3E10)
  4. 驱动层将DDMA读出的真正内存拿去匹配一个根据系统版本生成的模式, 匹配的目标是找到hvix64.exe/hvax64.exe(根据CPU厂商决定)中对cpuidVMExitHandler
  5. 驱动层释放带hook的恶意驱动并再次通过DDMA将hook写入原 handler 的跳转目标, 实现对Hyper-Vcpuid操作的处理的劫持

计算出正确的终止密码,输入到shadow_panel.exe中,使得其返回成功

前面AI分析得出了trampoline所需的跳回地址就是隐藏驱动中的导出符号payload_1该槽位储存的, 而隐藏驱动中的校验函数如下:

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
bool __fastcall check(__int64 f16, __int64 l16)
{
unsigned __int64 seed1; // r8
__int64 seed2; // rax
unsigned __int64 seed3; // r8
__int64 seed4; // r9
unsigned __int64 v6; // r8
unsigned __int64 v7; // r9
unsigned __int64 v8; // r8
unsigned __int64 v9; // r9
unsigned __int64 v10; // r8
unsigned __int64 v11; // r9
unsigned __int64 v12; // r8
unsigned __int64 v13; // r9
unsigned __int64 v14; // r8
unsigned __int64 v15; // r9
unsigned __int64 v16; // r8
unsigned __int64 v17; // r9
unsigned __int64 v18; // r8
unsigned __int64 v19; // r9
unsigned __int64 v20; // r8
unsigned __int64 v21; // r9
unsigned __int64 v22; // r8
unsigned __int64 v23; // r9
unsigned __int64 v24; // r8
unsigned __int64 v25; // r9
unsigned __int64 v26; // r8
unsigned __int64 v27; // r9
unsigned __int64 v28; // r8
unsigned __int64 v29; // r9
unsigned __int64 v30; // r8
unsigned __int64 v31; // r9
unsigned __int64 f16_1; // r8
unsigned __int64 l16_1; // r9

seed1 = 0x9E3779B97F4A7C15uLL
* __ROL8__(
*(_QWORD *)(((unsigned __int64)payload_1 & 0xFFFFFFFFFFFFF000uLL) + 0x508) ^ 0x4859504552564D58LL,
13)
+ (*(_QWORD *)(((unsigned __int64)payload_1 & 0xFFFFFFFFFFFFF000uLL) + 0x500) ^ 0x5348414430574E54LL);
seed2 = __ROL8__(seed1, 29);
seed3 = (((seed2 - 0x40A7B892E31B1A47LL)
^ *(_QWORD *)(((unsigned __int64)payload_1 & 0xFFFFFFFFFFFFF000uLL) + 0x508)
^ 0x4859504552564D58uLL) >> 17)
^ seed1;
seed4 = (seed3 << 7)
+ ((seed2 - 0x40A7B892E31B1A47LL)
^ *(_QWORD *)(((unsigned __int64)payload_1 & 0xFFFFFFFFFFFFF000uLL) + 0x508)
^ 0x4859504552564D58LL);
v6 = 0x9E3779B97F4A7C15uLL * __ROL8__(seed4, 13) + seed3;
v7 = (__ROL8__(v6, 29) - 0x40A7B892E31B1A47LL) ^ seed4;
v8 = (v7 >> 17) ^ v6;
v9 = (v8 << 7) + v7;
v10 = 0x9E3779B97F4A7C15uLL * __ROL8__(v9, 13) + v8;
v11 = (__ROL8__(v10, 29) - 0x40A7B892E31B1A47LL) ^ v9;
v12 = (v11 >> 17) ^ v10;
v13 = (v12 << 7) + v11;
v14 = 0x9E3779B97F4A7C15uLL * __ROL8__(v13, 13) + v12;
v15 = (__ROL8__(v14, 29) - 0x40A7B892E31B1A47LL) ^ v13;
v16 = (v15 >> 17) ^ v14;
v17 = (v16 << 7) + v15;
v18 = 0x9E3779B97F4A7C15uLL * __ROL8__(v17, 13) + v16;
v19 = (__ROL8__(v18, 29) - 0x40A7B892E31B1A47LL) ^ v17;
v20 = (v19 >> 17) ^ v18;
v21 = (v20 << 7) + v19;
v22 = 0x9E3779B97F4A7C15uLL * __ROL8__(v21, 13) + v20;
v23 = (__ROL8__(v22, 29) - 0x40A7B892E31B1A47LL) ^ v21;
v24 = (v23 >> 17) ^ v22;
v25 = (v24 << 7) + v23;
v26 = 0x9E3779B97F4A7C15uLL * __ROL8__(v25, 13) + v24;
v27 = (__ROL8__(v26, 29) - 0x40A7B892E31B1A47LL) ^ v25;
v28 = (v27 >> 17) ^ v26;
v29 = (v28 << 7) + v27;
v30 = 0x9E3779B97F4A7C15uLL * __ROL8__(v29, 13) + v28;
v31 = (__ROL8__(v30, 29) - 0x40A7B892E31B1A47LL) ^ v29;
f16_1 = (v31 >> 17) ^ v30;
l16_1 = (f16_1 << 7) + v31;
return f16 == f16_1 && l16 == l16_1;
}

实际上是正向计算出结果后和输入的两个qword对比来确定是否正确的, 直接模拟它的算法即可, 校验算法中唯一的变量就是trampoline跳转目标地址所在页的0x500/0x508偏移的两个qword数据, 用官方推荐的Windows版本拉出的hvix64.exe直接可以找到:

image-20260427201513783

现在只需要分析以下参数传入的顺序就可以计算出正确输入了, 以输入1234567812345678abcdefacdefabefa为例, 在执行cpuid的前一刻前 4 个寄存器分别存放魔数, 前16个hex, 控制码, 后16个hex:

image-20260427202206579

Intel 平台下的 hook 传入的寄存器顺序分别是:

image-20260427202329693

最终进入check的输入数据顺序就是前16个hex, 后16个hex:

image-20260427202427326

至此可以写出本机的注册机:

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
MASK64 = 0xFFFFFFFFFFFFFFFF

def rol64(value: int, bits: int) -> int:
value &= MASK64
return ((value << bits) | (value >> (64 - bits))) & MASK64

def compute_pair(q500: int, q508: int) -> tuple[int, int]:
# Mirrors hidden.sys!sub_1000 exactly:
# first compare arg -> expected v32
# second compare arg -> expected v33
N1 = 0x9E3779B97F4A7C15
N2 = 0x40A7B892E31B1A47

seed1 = (N1 * rol64(q508 ^ 0x4859504552564D58, 13) + (q500 ^ 0x5348414430574E54)) & MASK64
seed2 = (rol64(seed1, 29)) & MASK64

p1 = ((((seed2 - N2) ^ q508 ^ 0x4859504552564D58) >> 17) ^ seed1) & MASK64
p2 = ((p1 << 7) + ((seed2 - N2) ^ q508 ^ 0x4859504552564D58)) & MASK64

for _ in range(7):
t1 = (N1 * rol64(p2, 13) + p1) & MASK64
t2 = ((rol64(t1, 29) - N2) ^ p2) & MASK64
p1 = ((t2 >> 17) ^ t1) & MASK64
p2 = ((p1 << 7) + t2) & MASK64

return p1, p2


def main() -> None:
q500 = 0x482FF8C148C68B48
q508 = 0x870F01F88348C0FF

f16, l16 = compute_pair(q500, q508)
password = f"{f16:016X}{l16:016X}"

print(f"q500 = 0x{q500:016X}")
print(f"q508 = 0x{q508:016X}")
print(f"expected f16hex / RDX = 0x{f16:016X}")
print(f"expected l16hex / RBX = 0x{l16:016X}")
print(password)


if __name__ == "__main__":
main()

# q500 = 0x482FF8C148C68B48
# q508 = 0x870F01F88348C0FF
# expected f16hex / RDX = 0x1CA65AF90319BC1A
# expected l16hex / RBX = 0x58F39760301CAA81
# 1CA65AF90319BC1A58F39760301CAA81

顺便提一嘴, 用AI要保持怀疑态度, 这里AI看校验函数认为那两个qword是释放出来的payload.syspayload_1所在页的 0x500/0x508 的两个qword(*(u64 *)((&payload_1 & 0xFFFFFFFFFFFFF000uLL) + 0x500)), 然后追了半天这两个qword是在哪里填入的, 然后我自己一看, 实际上要用到的是payload_1这个槽位存放的地址, 也就是trampoline的跳回地址所在页的 0x500/0x508 的两个qword(*(u64 *)((payload_1 & 0xFFFFFFFFFFFFF000uLL) + 0x500))

编写keygen,使得在任意机器,任何一次运行shadow_panel.exe,都可以正确计算出终止密码

思路如下:

  1. 静态解析驱动层所有模式
  2. 根据当前 OS build 通过对应的模式去System32下的hvix64.exe/hvax64.exe文件中进行匹配
  3. 静态解析trampoline槽位应该填入的地址
  4. 通过这个地址得到目标两个qword

这个脚本可以验证我手上有的两个不同 OS build 的虚拟机, 更多的就要下载其他虚拟机来测试了, AMD更是一点招没有:

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
from __future__ import annotations

import argparse
import os
import subprocess
import sys
from dataclasses import dataclass
from pathlib import Path
from typing import Iterable

import pefile

MASK64 = 0xFFFFFFFFFFFFFFFF


@dataclass(frozen=True)
class Pattern:
vendor: str
min_build: int
max_build: int
to_match: bytes
mask: str
trampoline_bias: int
name: str


PATTERNS: tuple[Pattern, ...] = (
Pattern(
vendor="intel",
min_build=0x585D,
max_build=0xFFFFFFFF,
to_match=bytes.fromhex(
"66 83 FE 01 75 0A E8 00 00 00 00 48 8B 4C 24 00 FB 8B D6 0B 54 24 00 E8 00 00 00 00 E9"
),
mask="xxxxxxx????xxxx?xxxxxx?x????x",
trampoline_bias=0x17,
name="22621+",
),
Pattern(
vendor="intel",
min_build=0x4A61,
max_build=0x585C,
to_match=bytes.fromhex(
"65 C6 04 25 6D 00 00 00 00 48 8B 4C 24 00 48 8B 54 24 00 E8 00 00 00 00 E9"
),
mask="xxxxxxxxxxxxx?xxxx?x????x",
trampoline_bias=0x13,
name="19041-22620",
),
Pattern(
vendor="intel",
min_build=0x4563,
max_build=0x4A60,
to_match=bytes.fromhex(
"48 8B 4C 24 00 EB 07 E8 00 00 00 00 EB F2 48 8B 54 24 00 E8 00 00 00 00 E9"
),
mask="xxxx?xxx????xxxxxx?x????x",
trampoline_bias=0x13,
name="17763-19040",
),
Pattern(
vendor="intel",
min_build=0x42EE,
max_build=0x4562,
to_match=bytes.fromhex(
"F2 80 3D FC 12 46 00 00 0F 84 00 00 00 00 48 8B 54 24 00 E8 00 00 00 00 E9"
),
mask="xxxxxxx?xx????xxxx?x????x",
trampoline_bias=0x13,
name="17134-17762",
),
Pattern(
vendor="intel",
min_build=0x295A,
max_build=0x42ED,
to_match=bytes.fromhex(
"D0 80 00 00 00 00 00 00 0F 84 00 00 00 00 48 8B 54 24 00 E8 00 00 00 00 E9"
),
mask="xx????x?xx????xxxx?x????x",
trampoline_bias=0x13,
name="10586-17133",
),
Pattern(
vendor="intel",
min_build=0x2800,
max_build=0x2959,
to_match=bytes.fromhex(
"60 C0 0F 29 68 D0 80 3D 7E AF 49 00 01 0F 84 00 00 00 00 E8 00 00 00 00 E9"
),
mask="xxxxxxxxxxxxxxx????x????x",
trampoline_bias=0x13,
name="10240-10585",
),
Pattern(
vendor="amd",
min_build=0x2800,
max_build=0x4A61,
to_match=bytes.fromhex("E8 00 00 00 00 48 89 04 24 E9"),
mask="x????xxxxx",
trampoline_bias=0x0,
name="AMD-Generic",
),
)


def rol64(value: int, bits: int) -> int:
value &= MASK64
return ((value << bits) | (value >> (64 - bits))) & MASK64


def compute_pair(q500: int, q508: int) -> tuple[int, int]:
# Mirrors hidden.sys!sub_1000 exactly.
n1 = 0x9E3779B97F4A7C15
n2 = 0x40A7B892E31B1A47

v8 = (n1 * rol64(q508 ^ 0x4859504552564D58, 13) + (q500 ^ 0x5348414430574E54)) & MASK64
v9 = ((((rol64(v8, 29) - n2) & MASK64) ^ q508 ^ 0x4859504552564D58) >> 17) ^ v8
v9 &= MASK64
v10 = (((v9 << 7) & MASK64) + (((rol64(v8, 29) - n2) & MASK64) ^ q508 ^ 0x4859504552564D58)) & MASK64

cur_a = v9
cur_b = v10
for _ in range(6):
nxt_a = (n1 * rol64(cur_b, 13) + cur_a) & MASK64
nxt_b = (((rol64(nxt_a, 29) - n2) & MASK64) ^ cur_b) & MASK64
cur_a = ((nxt_b >> 17) ^ nxt_a) & MASK64
cur_b = (((cur_a << 7) & MASK64) + nxt_b) & MASK64

v30 = (n1 * rol64(cur_b, 13) + cur_a) & MASK64
v31 = (((rol64(v30, 29) - n2) & MASK64) ^ cur_b) & MASK64
v32 = ((v31 >> 17) ^ v30) & MASK64
v33 = (((v32 << 7) & MASK64) + v31) & MASK64
return v32, v33


def get_build(default: int | None) -> int:
if default is not None:
return default
if not hasattr(sys, "getwindowsversion"):
raise RuntimeError("current Python runtime is not on Windows; pass --build explicitly")
return sys.getwindowsversion().build


def detect_cpu_vendor(explicit: str | None = None) -> str:
if explicit is not None:
vendor = explicit.strip().lower()
if vendor not in {"intel", "amd"}:
raise RuntimeError(f"unsupported --cpu value: {explicit}")
return vendor

try:
out = subprocess.check_output(
[
"powershell",
"-NoProfile",
"-Command",
"(Get-CimInstance Win32_Processor | Select-Object -First 1 -ExpandProperty Manufacturer)",
],
text=True,
stderr=subprocess.DEVNULL,
).strip()
lower = out.lower()
if "intel" in lower:
return "intel"
if "amd" in lower:
return "amd"
except Exception:
pass

proc_ident = os.environ.get("PROCESSOR_IDENTIFIER", "").lower()
if "intel" in proc_ident:
return "intel"
if "amd" in proc_ident:
return "amd"

raise RuntimeError("failed to detect current CPU vendor; pass --cpu intel|amd explicitly")


def pick_pattern(vendor: str, build: int) -> Pattern:
for pattern in PATTERNS:
if pattern.vendor == vendor and pattern.min_build <= build <= pattern.max_build:
return pattern
raise RuntimeError(f"unsupported combination: vendor={vendor}, build={build}")


def match_mask(data: bytes, offset: int, pattern: Pattern) -> bool:
for idx, mask_ch in enumerate(pattern.mask):
if mask_ch == "x" and data[offset + idx] != pattern.to_match[idx]:
return False
return True


def find_pattern_offsets(data: bytes, pattern: Pattern) -> list[int]:
out: list[int] = []
plen = len(pattern.to_match)
for off in range(0, len(data) - plen + 1):
if match_mask(data, off, pattern):
out.append(off)
return out


def module_candidates(explicit: Path | None, vendor: str) -> Iterable[Path]:
if explicit is not None:
yield explicit
return

system_root = Path(os.environ.get("SystemRoot", r"C:\Windows"))
system32 = system_root / "System32"
module_name = "hvix64.exe" if vendor == "intel" else "hvax64.exe"
system_candidate = system32 / module_name
if system_candidate.exists():
yield system_candidate

local_candidate = Path(r".\analyse") / module_name
if local_candidate.exists():
yield local_candidate


def locate_handler_page(module_path: Path, pattern: Pattern) -> tuple[int, int, int, int, int]:
pe = pefile.PE(str(module_path), fast_load=False)
data = module_path.read_bytes()
matches = find_pattern_offsets(data, pattern)
if not matches:
raise RuntimeError(f"no matches for pattern {pattern.name} in {module_path}")
if len(matches) != 1:
raise RuntimeError(f"expected 1 match for pattern {pattern.name} in {module_path}, got {len(matches)}")

match_off = matches[0]
match_rva = pe.get_rva_from_offset(match_off)
insn_rva = match_rva + pattern.trampoline_bias
insn_off = pe.get_offset_from_rva(insn_rva)

if data[insn_off] != 0xE8:
raise RuntimeError(f"expected CALL rel32 at RVA 0x{insn_rva:X}, got 0x{data[insn_off]:02X}")

rel = int.from_bytes(data[insn_off + 1 : insn_off + 5], "little", signed=True)
target_rva = (insn_rva + 5 + rel) & MASK64
page_rva = target_rva & ~0xFFF

q500_off = pe.get_offset_from_rva(page_rva + 0x500)
q508_off = pe.get_offset_from_rva(page_rva + 0x508)
q500 = int.from_bytes(data[q500_off : q500_off + 8], "little")
q508 = int.from_bytes(data[q508_off : q508_off + 8], "little")
return match_rva, insn_rva, target_rva, q500, q508


def generate_password(q500: int, q508: int) -> tuple[int, int, str]:
# hidden.sys!hook -> hidden.sys!check passes:
# first compare <- RDX / f16hex = v32
# second compare <- RBX / l16hex = v33
# user input string is therefore l16hex || f16hex = v33 || v32
v32, v33 = compute_pair(q500, q508)
password = f"{v32:016X}{v33:016X}"
return v32, v33, password


def main() -> None:
parser = argparse.ArgumentParser(
description="Static keygen for shadow_panel.exe using hvix64/hvax64 on disk."
)
parser.add_argument("--build", type=lambda x: int(x, 0), help="Windows build number (default: current OS build)")
parser.add_argument("--cpu", help="Force CPU vendor: intel or amd")
parser.add_argument("--module", type=Path, help="Explicit path to hvix64.exe / hvax64.exe")
parser.add_argument("--q500", type=lambda x: int(x, 0), help="Override qword at handler page +0x500")
parser.add_argument("--q508", type=lambda x: int(x, 0), help="Override qword at handler page +0x508")
args = parser.parse_args()

if args.q500 is not None and args.q508 is not None:
q500, q508 = args.q500, args.q508
module_path = None
pattern = None
match_rva = insn_rva = target_rva = None
vendor = None
else:
build = get_build(args.build)
vendor = detect_cpu_vendor(args.cpu)
pattern = pick_pattern(vendor, build)

last_error: Exception | None = None
module_path = None
match_rva = insn_rva = target_rva = None
q500 = q508 = 0
for candidate in module_candidates(args.module, vendor):
try:
match_rva, insn_rva, target_rva, q500, q508 = locate_handler_page(candidate, pattern)
module_path = candidate
break
except Exception as exc: # noqa: BLE001
last_error = exc

if module_path is None:
raise SystemExit(f"failed to locate handler page: {last_error}")

v32, v33, password = generate_password(q500, q508)

if module_path is not None and pattern is not None:
print(f"cpu_vendor = {vendor}")
print(f"module = {module_path}")
print(f"pattern = {pattern.name}")
print(f"match_rva = 0x{match_rva:X}")
print(f"call_rva = 0x{insn_rva:X}")
print(f"target_rva = 0x{target_rva:X}")
print(f"target_page = 0x{target_rva & ~0xFFF:X}")
print(f"q500 = 0x{q500:016X}")
print(f"q508 = 0x{q508:016X}")
print(f"expected RDX = 0x{v32:016X}")
print(f"expected RBX = 0x{v33:016X}")
print(password)


if __name__ == "__main__":
main()

编写检测代码,检测「影」核心系统攻击操作系统底层的特殊方法

依旧检测最后做, 整体是蜜罐的思路, 具体如下:

  1. 关闭Hyper-V
  2. 安装自己的VT驱动
  3. 在自己的驱动中构造会被题目的驱动扫描到的陷阱页
  4. 将陷阱页映射到全ff的保护页, 确保过题目驱动的第一关检测
  5. 监测这块内存

源码见附件, 主要是在vmexit_custom.cpp中, 这里只说一下为什么要分配12页的陷阱, 一开始的时候我甚至只分配了1页, 只存放关键的模式让题目的驱动进行扫描, 后面发现虽然能够成功在题目驱动中扫描到目标模式的关键点断下, 但是我们的陷阱页没被篡改.

于是我以为是题目还检查了handler是否有效, 毕竟后面自己的payload.sys在 fallback 的时候还要用(也就是存在payload_1槽位里的那个地址), 然后就分配了两页一页装hvix64.exehandler的调用点所在页, 一页装handler所在页, 然后修一下handler的目标地址确保它在下一页, 因为原本调用点和handler就不是相邻的两页, 我只是用了这两个页的数据拼在一起.

但是还是没有监测到页被修改, 想看看题目匹配到模式之后拿着这个页干什么去了, 但是DDMA扫描的函数调用点被厚v, 根本没法静态分析, 而动态分析在扫描函数得到的页上下硬件断点后续MmMapIoSpace时几乎一定触发MEMORY MANAGEMENT蓝屏, 于是只能在几个关键流程下断点看看走到了哪一步, 最后是追到find_cave(000000000000DF10):

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
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
__int64 __fastcall find_cave(__int64 *a1, __int64 a2, __int64 *a3, __int64 *a4, unsigned __int64 *a5)
{
__int64 *v6; // rdi
__int64 v7; // r14
PVOID (__stdcall *MmAllocateContiguousMemory)(SIZE_T, PHYSICAL_ADDRESS); // rax
__int64 v10; // r9
__int64 v11; // rcx
__int64 v12; // rdx
__int64 v13; // r8
__int64 v14; // r9
__int64 v15; // rdi
__int64 v16; // r14
char v17; // bl
char *v18; // r14
char v19; // bp
unsigned __int64 v20; // r15
__int64 v21; // rbx
char v22; // r12
unsigned __int64 v23; // r14
__int64 v24; // r13
void (__stdcall *MmUnmapIoSpace)(PVOID, SIZE_T); // rax
int (__fastcall *MmCopyMemory)(__int64, unsigned __int64, unsigned __int64, __int64, char *); // rax
__int64 v28; // r9
__int64 v29; // rcx
__int64 v30; // rdx
__int64 v31; // r8
__int64 v32; // r9
__int64 v33; // r10
__int64 v34; // rsi
char *v35; // rbp
char v36; // si
unsigned __int64 v37; // rbx
__int64 v38; // r11
char v39; // r15
unsigned __int64 v40; // rbp
unsigned __int64 n0xFF7; // rax
__int64 (__fastcall *MmMaploSpace)(unsigned __int64, unsigned __int64, _QWORD); // rax
__int64 v43; // r9
__int64 v44; // rcx
__int64 v45; // r8
__int64 v46; // r9
__int64 v47; // r10
__int64 v48; // rdx
char v49; // r11
char *v50; // rdx
char v51; // si
unsigned __int64 v52; // rbx
__int64 v53; // r11
char v54; // r15
__int64 v55; // rax
__int64 v56; // rsi
unsigned int v57; // eax
__int64 v58; // rdx
unsigned __int64 v59; // rcx
unsigned __int64 v60; // r8
int n204; // r9d
__int64 ntoskrnl_base_addr; // rax
__int64 v63; // r9
__int64 v64; // rcx
__int64 v65; // rdx
__int64 v66; // r8
__int64 v67; // r9
__int64 v68; // r10
__int64 v69; // rsi
char *v70; // rbp
char v71; // si
unsigned __int64 v72; // rbx
__int64 v73; // r11
char v74; // r15
__int64 v75; // r9
__int64 v76; // rcx
__int64 v77; // r8
__int64 v78; // rsi
char *v79; // rbp
char v80; // si
unsigned __int64 v81; // rbx
__int64 v82; // r11
char v83; // r15
__int64 v84; // [rsp+28h] [rbp-80h]
__int64 v85; // [rsp+28h] [rbp-80h]
__int64 *v87; // [rsp+38h] [rbp-70h]
__int64 v89; // [rsp+48h] [rbp-60h]
__int64 v90; // [rsp+50h] [rbp-58h]
__int64 v91; // [rsp+58h] [rbp-50h]
char v92[72]; // [rsp+60h] [rbp-48h] BYREF

v6 = a3;
v7 = a2;
MmAllocateContiguousMemory = ::MmAllocateContiguousMemory;
if ( !::MmAllocateContiguousMemory )
{
if ( ::ntoskrnl_base_addr
&& (v10 = *(unsigned int *)(::ntoskrnl_base_addr + *(int *)(::ntoskrnl_base_addr + 60) + 136),
v11 = *(unsigned int *)(::ntoskrnl_base_addr + v10 + 24),
*(_DWORD *)(::ntoskrnl_base_addr + v10 + 24)) )
{
v12 = ::ntoskrnl_base_addr + *(unsigned int *)(::ntoskrnl_base_addr + v10 + 28);
v13 = ::ntoskrnl_base_addr + *(unsigned int *)(::ntoskrnl_base_addr + v10 + 32);
v14 = ::ntoskrnl_base_addr + *(unsigned int *)(::ntoskrnl_base_addr + v10 + 36);
v15 = 0;
do
{
v16 = *(unsigned int *)(v13 + 4 * v15);
v17 = *(_BYTE *)(::ntoskrnl_base_addr + v16);
if ( v17 )
{
v18 = (char *)(::ntoskrnl_base_addr + v16 + 1);
v19 = v17;
v20 = 0xCBF29CE484222325uLL;
do
{
v21 = 0x100000001B3LL * (v20 ^ v19);
v22 = *v18++;
v19 = v22;
v20 = v21;
}
while ( v22 );
if ( v21 == 0x8CD9141D23428B07uLL )
{
MmAllocateContiguousMemory = (PVOID (__stdcall *)(SIZE_T, PHYSICAL_ADDRESS))(*(unsigned int *)(v12 + 4LL * *(unsigned __int16 *)(v14 + 2 * v15))
+ ::ntoskrnl_base_addr);
goto LABEL_13;
}
}
++v15;
}
while ( v15 != v11 );
MmAllocateContiguousMemory = (PVOID (__stdcall *)(SIZE_T, PHYSICAL_ADDRESS))&loc_114514;
LABEL_13:
v6 = a3;
v7 = a2;
}
else
{
MmAllocateContiguousMemory = (PVOID (__stdcall *)(SIZE_T, PHYSICAL_ADDRESS))&loc_114514;
}
::MmAllocateContiguousMemory = MmAllocateContiguousMemory;
}
v23 = v7 << 12;
v89 = ((__int64 (__fastcall *)(unsigned __int64, __int64))MmAllocateContiguousMemory)(v23, -1);
if ( !v89 )
{
sub_19E30((__int64)&qword_1D0FFEC, (__int64)&unk_2135F);
sub_19410(&qword_1D0FF30, &unk_2117C);
sub_1B890(&unk_1D10270, &unk_21993);
sub_19CB0(&unk_1D0FFBC, &unk_21303);
error_log((__int64)&qword_1D0FFEC, (__int64)&qword_1D0FF30, (__int64)&unk_1D10270, 385, (__int64)&unk_1D0FFBC);
return 0xC000009ALL;
}
v91 = a1[1];
if ( v91 <= 0 )
return 0xC0000001LL;
v87 = a4;
v90 = *a1;
v24 = 0;
while ( 1 )
{
MmCopyMemory = (int (__fastcall *)(__int64, unsigned __int64, unsigned __int64, __int64, char *))::MmCopyMemory;
if ( !::MmCopyMemory )
{
if ( ::ntoskrnl_base_addr
&& (v28 = *(unsigned int *)(::ntoskrnl_base_addr + *(int *)(::ntoskrnl_base_addr + 60) + 136),
v29 = *(unsigned int *)(::ntoskrnl_base_addr + v28 + 24),
*(_DWORD *)(::ntoskrnl_base_addr + v28 + 24)) )
{
v30 = ::ntoskrnl_base_addr + *(unsigned int *)(::ntoskrnl_base_addr + v28 + 28);
v31 = ::ntoskrnl_base_addr + *(unsigned int *)(::ntoskrnl_base_addr + v28 + 32);
v32 = ::ntoskrnl_base_addr + *(unsigned int *)(::ntoskrnl_base_addr + v28 + 36);
v33 = 0;
while ( 1 )
{
v34 = *(unsigned int *)(v31 + 4 * v33);
if ( *(_BYTE *)(::ntoskrnl_base_addr + v34) )
{
v35 = (char *)(::ntoskrnl_base_addr + v34 + 1);
v36 = *(_BYTE *)(::ntoskrnl_base_addr + v34);
v37 = 0xCBF29CE484222325uLL;
do
{
v38 = 0x100000001B3LL * (v37 ^ v36);
v39 = *v35++;
v36 = v39;
v37 = v38;
}
while ( v39 );
if ( v38 == 0x306328EE8E049A39LL )
break;
}
if ( ++v33 == v29 )
goto LABEL_33;
}
MmCopyMemory = (int (__fastcall *)(__int64, unsigned __int64, unsigned __int64, __int64, char *))(*(unsigned int *)(v30 + 4LL * *(unsigned __int16 *)(v32 + 2 * v33)) + ::ntoskrnl_base_addr);
}
else
{
LABEL_33:
MmCopyMemory = (int (__fastcall *)(__int64, unsigned __int64, unsigned __int64, __int64, char *))&loc_114514;
}
::MmCopyMemory = (__int64)MmCopyMemory;
}
v40 = (v90 + v24) & 0xFFFFFFFFFFFFF000uLL;
if ( MmCopyMemory(v89, v40, v23, 1, v92) >= 0 )
{
n0xFF7 = -8;
do
{
if ( *(_QWORD *)(v89 + n0xFF7 + 8) != -1 )
goto LABEL_22;
n0xFF7 += 8LL;
}
while ( n0xFF7 <= 0xFF7 );
MmMaploSpace = (__int64 (__fastcall *)(unsigned __int64, unsigned __int64, _QWORD))::MmMaploSpace;
if ( !::MmMaploSpace )
{
if ( ::ntoskrnl_base_addr
&& (v43 = *(unsigned int *)(::ntoskrnl_base_addr + *(int *)(::ntoskrnl_base_addr + 60) + 136),
v44 = *(unsigned int *)(::ntoskrnl_base_addr + v43 + 24),
*(_DWORD *)(::ntoskrnl_base_addr + v43 + 24)) )
{
v84 = ::ntoskrnl_base_addr + *(unsigned int *)(::ntoskrnl_base_addr + v43 + 28);
v45 = ::ntoskrnl_base_addr + *(unsigned int *)(::ntoskrnl_base_addr + v43 + 32);
v46 = ::ntoskrnl_base_addr + *(unsigned int *)(::ntoskrnl_base_addr + v43 + 36);
v47 = 0;
while ( 1 )
{
v48 = *(unsigned int *)(v45 + 4 * v47);
v49 = *(_BYTE *)(::ntoskrnl_base_addr + v48);
if ( v49 )
{
v50 = (char *)(::ntoskrnl_base_addr + v48 + 1);
v51 = v49;
v52 = 0xCBF29CE484222325uLL;
do
{
v53 = 0x100000001B3LL * (v52 ^ v51);
v54 = *v50++;
v51 = v54;
v52 = v53;
}
while ( v54 );
if ( v53 == 0x40ED8EA987B20683LL )
break;
}
if ( ++v47 == v44 )
goto LABEL_49;
}
MmMaploSpace = (__int64 (__fastcall *)(unsigned __int64, unsigned __int64, _QWORD))(*(unsigned int *)(v84 + 4LL * *(unsigned __int16 *)(v46 + 2 * v47))
+ ::ntoskrnl_base_addr);
}
else
{
LABEL_49:
MmMaploSpace = (__int64 (__fastcall *)(unsigned __int64, unsigned __int64, _QWORD))&loc_114514;
}
::MmMaploSpace = (__int64)MmMaploSpace;
}
v55 = MmMaploSpace(v40, v23, 0);
if ( v55 )
break;
}
LABEL_22:
v24 += 4096;
if ( v24 >= v91 )
return 0xC0000001LL;
}
v56 = v55;
if ( (int)hide_hook(v89, v55, a2) < 0 )
{
MmUnmapIoSpace = ::MmUnmapIoSpace;
if ( ::MmUnmapIoSpace )
goto LABEL_21;
ntoskrnl_base_addr = ::ntoskrnl_base_addr;
if ( ::ntoskrnl_base_addr )
{
v75 = *(unsigned int *)(::ntoskrnl_base_addr + *(int *)(::ntoskrnl_base_addr + 60) + 136);
v76 = *(unsigned int *)(::ntoskrnl_base_addr + v75 + 24);
if ( *(_DWORD *)(::ntoskrnl_base_addr + v75 + 24) )
{
v85 = v56;
v65 = ::ntoskrnl_base_addr + *(unsigned int *)(::ntoskrnl_base_addr + v75 + 28);
v77 = ::ntoskrnl_base_addr + *(unsigned int *)(::ntoskrnl_base_addr + v75 + 32);
v67 = ::ntoskrnl_base_addr + *(unsigned int *)(::ntoskrnl_base_addr + v75 + 36);
v68 = 0;
while ( 1 )
{
v78 = *(unsigned int *)(v77 + 4 * v68);
if ( *(_BYTE *)(::ntoskrnl_base_addr + v78) )
{
v79 = (char *)(::ntoskrnl_base_addr + v78 + 1);
v80 = *(_BYTE *)(::ntoskrnl_base_addr + v78);
v81 = 0xCBF29CE484222325uLL;
do
{
v82 = 0x100000001B3LL * (v81 ^ v80);
v83 = *v79++;
v80 = v83;
v81 = v82;
}
while ( v83 );
if ( v82 == 0x47E1CA0E288956C0LL )
goto LABEL_82;
}
if ( ++v68 == v76 )
{
LABEL_83:
MmUnmapIoSpace = (void (__stdcall *)(PVOID, SIZE_T))&loc_114514;
v56 = v85;
goto LABEL_20;
}
}
}
}
LABEL_19:
MmUnmapIoSpace = (void (__stdcall *)(PVOID, SIZE_T))&loc_114514;
LABEL_20:
::MmUnmapIoSpace = MmUnmapIoSpace;
LABEL_21:
((void (__fastcall *)(__int64, unsigned __int64))MmUnmapIoSpace)(v56, v23);
goto LABEL_22;
}
if ( !v23 )
{
LABEL_63:
MmUnmapIoSpace = ::MmUnmapIoSpace;
if ( ::MmUnmapIoSpace )
goto LABEL_21;
ntoskrnl_base_addr = ::ntoskrnl_base_addr;
if ( ::ntoskrnl_base_addr )
{
v63 = *(unsigned int *)(::ntoskrnl_base_addr + *(int *)(::ntoskrnl_base_addr + 60) + 136);
v64 = *(unsigned int *)(::ntoskrnl_base_addr + v63 + 24);
if ( *(_DWORD *)(::ntoskrnl_base_addr + v63 + 24) )
{
v85 = v56;
v65 = ::ntoskrnl_base_addr + *(unsigned int *)(::ntoskrnl_base_addr + v63 + 28);
v66 = ::ntoskrnl_base_addr + *(unsigned int *)(::ntoskrnl_base_addr + v63 + 32);
v67 = ::ntoskrnl_base_addr + *(unsigned int *)(::ntoskrnl_base_addr + v63 + 36);
v68 = 0;
while ( 1 )
{
v69 = *(unsigned int *)(v66 + 4 * v68);
if ( *(_BYTE *)(::ntoskrnl_base_addr + v69) )
{
v70 = (char *)(::ntoskrnl_base_addr + v69 + 1);
v71 = *(_BYTE *)(::ntoskrnl_base_addr + v69);
v72 = 0xCBF29CE484222325uLL;
do
{
v73 = 0x100000001B3LL * (v72 ^ v71);
v74 = *v70++;
v71 = v74;
v72 = v73;
}
while ( v74 );
if ( v73 == 0x47E1CA0E288956C0LL )
break;
}
if ( ++v68 == v64 )
goto LABEL_83;
}
LABEL_82:
v56 = v85;
MmUnmapIoSpace = (void (__stdcall *)(PVOID, SIZE_T))(ntoskrnl_base_addr
+ *(unsigned int *)(v65
+ 4LL
* *(unsigned __int16 *)(v67 + 2 * v68)));
goto LABEL_20;
}
}
goto LABEL_19;
}
v57 = 0;
while ( 1 )
{
v58 = v89 + v57;
v59 = v23 - v57;
v60 = 0;
while ( 1 )
{
n204 = *(unsigned __int8 *)(v58 + v60);
if ( *(_BYTE *)(v58 + v60) )
{
if ( n204 != 0xCC && n204 != 0x90 )
break;
}
if ( v59 == ++v60 )
goto LABEL_61;
}
v59 = v60;
LABEL_61:
if ( v59 >= v23 )
break;
if ( v23 <= ++v57 )
goto LABEL_63;
}
*a5 = v40;
*v6 = v89;
*v87 = v56;
return 0;
}

调试发现就是if ( v24 >= v91 )成立导致这个函数返回0xC0000001导致没有后续动作, 而在正常开启Hyper-V时这个函数走到最后返回 0, 进一步调试发现这个函数的第二个参数, 也就是所需的页数刚好等于payload.sys的页数, 这个函数大概率就是找一块 guest 视角全ff的页, 实际内容为int 3(cc)nop(90)的空洞来写入payload.sys

而上面提到的那个条件成立意味着函数遍历完了一个连续物理内存范围也没有找到这样的页, 这就是为什么我要分配10页的全cc页并映射到保护页

另外需要注意一点的是, hvppallocator底层使用ExAllocatePoolWithTag来分配内存, 这样得到的内存只能保证虚拟上连续, 物理上几乎不可能连续, 需要自己改用MmAllocateContiguousMemory分配物理连续内存

先运行自己的VT驱动, 启用控制程序发送detc指令初始化陷阱页环境, 最后启动题目程序, 成功监测到陷阱页被修改:

QQ_1777867614654

使用这种方法甚至可以依赖于我们自己就能操纵 host 的行为来实现调试payload.sys的功能

附件