我宣布我是2026年最唐的唐吉诃德 我可能是唯一一个有一定分析过程但是完全0分的参赛选手, 简单说一下原因
第一关明明说了:
「影」核心系统「根」需要在一些开启了特殊特性 的机器上才能部署成功,逆向找到成功部署条件
而我在调试到phase0的第一个cpuid看到返回了'vmwarevmware'之后偏执地认为这里就是在检测对抗虚拟机环境并在后续始终 没有回想起来是这里出了问题, 并在后面分析出 ring 3 通过cpuid和驱动通信后高度怀疑本题需要开启VT-x并且是唯一 的条件, 而在检测所有VT特征无果后认为第二问中隐藏的代码就是 host 的逻辑, 导致整体认知出现错位, 白干三天
但是知道过后该做还是得做的(
成功运行shadow_panel.exe,控制台程序成功运行进入至输入终止密码的终端 直接启动程序会发现在phase0就失败了, fail 时 code1 为 -3, 通过字符串可以定位到该错误码输出的位置在sub_144A04160中:
其中调用了某个类的方法来对nopass(通过调试发现唯一一个不等于0的判断值故改名)进行赋值操作, 调试发现进入了sub_144A07540, 关键的检测是cpuid的虚拟机厂商, 因为我使用的是VMware所以检测失败, 可以通过 patch 强制比较通过:
patch个即把茂啊, 直接在Windows特性中开启Hyper-V即可
再运行发现code1变成了-4, 再深入到sub_144A06650, 调试发现动态解析得到NtQuerySystemInformation后检测了DMA:
也是直接 patch 返回 0:
patch个即把茂啊, 在VMware的虚拟机设置中关闭内存重映射即可:
成功通过phase0:
“
接下来分析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:
检测在0000000144A07650中, 简单地cpuid了一下后检测结果是否为0x1919810, 显然不可能, 直接 patch 绕过:
patch个即把茂啊, 实际上如果第一关不用patch的方法而是修改环境的话这里就能正常通过
实际上根据后面的输入处理分析, 这里应该是一个驱动核心功能是否启用的检测, cpuid是用于和驱动进行通信的vm-exit触发器
之后成功进入输入密码界面;
「根」使用特殊方法,对操作系统底层进行了攻击,并借此将关键核心代码隐藏了起来,分析其完整实现流程 通过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_bytesimport ida_funcsimport ida_kernwinimport ida_uaimport idcVERBOSE = 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 ): 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 ): 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 ): 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: 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; unsigned __int64 f16hex; size_t v2; __int128 n2_2; __int128 *v4; __int128 *v5; __int128 *v6; __int128 *v7; size_t Size; __int128 *v9; __int64 n22; size_t v11; void *v12; void *v13; void *v14; __int64 v15; __int128 *v16; char v17; unsigned __int8 v18; char *v19; char *v20; size_t n2_3; __int128 *v22; _BYTE *v23; unsigned __int64 i; __int128 *v25; char v26; unsigned __int8 v27; __int128 *v28; char v29; unsigned __int8 v30; __int128 *v31; char v32; unsigned __int8 v33; __int128 *v34; char v35; unsigned __int8 v36; __int128 *v37; char v38; unsigned __int8 v39; __int128 *v40; char v41; unsigned __int8 v42; __int128 *v43; char v44; unsigned __int8 v45; __int128 *v46; char v47; unsigned __int8 v48; char v49; char *v50; char *INVALID_HEX_FORMAT; void **i_1; unsigned __int64 n4; size_t *v54; _QWORD *i_3; _QWORD *i_2; void **result; _BYTE *v58; unsigned __int64 n15_1; unsigned __int64 v60; unsigned __int8 v61; unsigned __int8 v62; __int64 *j_1; _QWORD **p_i; void **v65; char n32; __int64 *j_2; _QWORD **p_i_1; _QWORD **p_i_2; _BYTE *i_6; void **result_1; __int64 i_7; __int64 v74; __int64 v75; char n48; unsigned __int8 v77; __int64 n1500; __int128 v79; __int128 n2; _QWORD *i_4; _QWORD *i_5; __int64 *j; unsigned __int64 n15_2; __int128 v85; __int128 n2_1; void *v87[2 ]; unsigned __int64 v88; unsigned __int64 n0x10_1; size_t v90[2 ]; __int64 n18; __int64 n15; void *v93; __m128i si128; void *v95; __m128i v96; void *v97; __m128i v98; _OWORD v99[2 ]; _OWORD v100[2 ]; _OWORD v101[2 ]; _QWORD *v102; unsigned __int64 n0x10; void *v104[6 ]; 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 ) >= 0x10 u ) v5 = (__int128 *)v79; if ( *(_BYTE *)v5 != 48 ) goto LABEL_37; v6 = &v79; if ( *((_QWORD *)&n2 + 1 ) >= 0x10 u ) v6 = (__int128 *)v79; if ( *((_BYTE *)v6 + 1 ) != 120 ) { v7 = &v79; if ( *((_QWORD *)&n2 + 1 ) >= 0x10 u ) 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 ) >= 0x10 u ) v9 = (__int128 *)v79; if ( Size > 0xF ) { n22 = 0x7FFFFFFFFFFFFFFF LL; if ( Size > 0x7FFFFFFFFFFFFFFF LL ) std ::_Xlength_error(); if ( (Size | 0xF ) <= 0x7FFFFFFFFFFFFFFF LL ) { 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 = 0x8000000000000027 uLL; } v12 = sub_144A41460(v11); if ( !v12 ) goto LABEL_34; v13 = (void *)(((unsigned __int64)v12 + 39 ) & 0xFFFFFFFFFFFFFFE0 uLL); *((_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 ) >= 0x10 u ) { 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 ) >= 0x10 u ) 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 ) < 0x10 u ) { 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 ) >= 0x10 u ) 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 ) >= 0x10 u ) 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 ) >= 0x10 u ) 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 ) >= 0x10 u ) 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 ) >= 0x10 u ) 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 ) >= 0x10 u ) 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 ) >= 0x10 u ) 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 ) >= 0x10 u ) 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 ) >= 0x10 u ) 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 ) >= 0x10 u ) { 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" , 0x19 u); log_print_0((void **)&qword_147CAC888, "[!!]" , 4u ); v90[0 ] = 0 ; n18 = 0 ; n15 = 15 ; INVALID_HEX_FORMAT = (char *)sub_144A41460(0x20 u); 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)" , 0x23 u); v95 = 0 ; v96 = _mm_load_si128((const __m128i *)&xmmword_144A65530); log_print_0(&v95, "Optional 0x prefix allowed" , 0x1A u); v97 = 0 ; v98 = _mm_load_si128((const __m128i *)&xmmword_144A65530); log_print_0(&v97, "Example: 0x11111111111111112222222222222222" , 0x2B u); 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(0xDEADBEEF LL, 0x1919810 , l16hex, f16hex); result = get_result((void **)&v102, v100); 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(0xDEADBEEF LL, 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(0xDEADBEEF LL, 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项目:
这里直接放源码太长了, 具体就是实现框架中的vmxon的vmexit 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; _QWORD *v6; PVOID (__stdcall *MmAllocateContiguousMemory)(SIZE_T, PHYSICAL_ADDRESS); __int64 v8; __int64 v9; __int64 v10; __int64 v11; __int64 v12; __int64 v13; __int64 v14; char v15; char *v16; char v17; unsigned __int64 v18; __int64 v19; char v20; __int64 to_match_page_5; _BYTE *to_match_page_1; PPHYSICAL_MEMORY_RANGE (*MmGetPhysicalMemoryRanges)(void ); __int64 v24; __int64 v25; __int64 v26; __int64 v27; __int64 v28; __int64 v29; __int64 v30; char v31; char *v32; char v33; unsigned __int64 v34; __int64 v35; char v36; PPHYSICAL_MEMORY_RANGE v38; _BYTE *to_match_page_4; __int64 n1970169159_1; PHYSICAL_ADDRESS *p_BaseAddress; PHYSICAL_ADDRESS v42; void (__stdcall *MmUnmapIoSpace)(PVOID, SIZE_T); LONGLONG v44; int (__fastcall *MmCopyMemory)(_BYTE *, unsigned __int64, __int64, __int64, char *); __int64 v46; __int64 v47; __int64 v48; __int64 v49; __int64 v50; __int64 v51; __int64 v52; char v53; char *v54; unsigned __int64 v55; unsigned __int64 v56; char v57; unsigned __int64 page_index; unsigned __int64 idx_; __int64 (__fastcall *MmMaploSpace)(unsigned __int64, __int64, _QWORD); __int64 v61; __int64 v62; __int64 v63; __int64 v64; __int64 v65; __int64 v66; __int64 v67; char *v68; char v69; unsigned __int64 v70; unsigned __int64 v71; char v72; __int64 va_kernel_page_from_physic; __int64 va_kernel_page_from_physic_; __int64 n1970169159; __int64 n1970169159_2; NTSTATUS (__stdcall *RtlGetVersion)(PRTL_OSVERSIONINFOW); __int64 v83; __int64 v84; __int64 v85; __int64 v86; __int64 v87; __int64 v88; __int64 v89; char *v90; char v91; unsigned __int64 v92; unsigned __int64 v93; char v94; __int64 n1752462657; __int64 n1752462657_1; NTSTATUS (__stdcall *RtlGetVersion_1)(PRTL_OSVERSIONINFOW); __int64 v103; __int64 v104; __int64 v105; __int64 v106; __int64 v107; __int64 v108; __int64 v109; char *v110; char v111; unsigned __int64 v112; unsigned __int64 v113; char v114; __int64 ntoskrnl_base_addr; __int64 v116; __int64 v117; __int64 v118; __int64 v119; __int64 v120; __int64 v121; __int64 v122; char *v123; char v124; unsigned __int64 v125; unsigned __int64 v126; char v127; unsigned __int64 _22631; _BYTE *_pattern; unsigned int n10; __int64 v131; __int64 v132; __int64 idx; __int64 v134; __int64 v135; __int64 v136; __int64 v137; char *v138; char v139; unsigned __int64 v140; unsigned __int64 v141; char v142; void (__stdcall *MmUnmapIoSpace_1)(PVOID, SIZE_T); __int64 v144; __int64 v145; __int64 v146; __int64 v147; __int64 v148; __int64 v149; __int64 v150; char *v151; char v152; unsigned __int64 v153; unsigned __int64 v154; char v155; bool v156; void (__fastcall *v157)(_BYTE *); __int64 v158; __int64 v159; __int64 v160; __int64 v161; __int64 v162; __int64 v163; __int64 v164; char v165; char *v166; char v167; unsigned __int64 v168; __int64 v169; char v170; _BYTE *v171; void (__stdcall *n1131796)(PVOID, ULONG); __int64 v173; __int64 v174; __int64 v175; __int64 v176; char *v177; char v178; unsigned __int64 v179; unsigned __int64 v180; char v181; void (__fastcall *v182)(_BYTE *); _BYTE *to_match_page_3; __int64 v184; __int64 v185; __int64 v186; __int64 v187; __int64 v188; __int64 v189; __int64 v190; char v191; char *v192; char v193; unsigned __int64 v194; __int64 v195; char v196; void (__stdcall *ExFreePoolWithTag)(PVOID, ULONG); __int64 v198; __int64 v199; __int64 v200; __int64 v201; __int64 v202; __int64 v203; __int64 v204; char v205; char *v206; char v207; unsigned __int64 v208; __int64 v209; char v210; __int64 (__fastcall *i)(_QWORD, _QWORD, _QWORD, _QWORD, _QWORD); __int64 ntoskrnl_base_addr_1; __int64 v213; __int64 v214; __int64 v215; __int64 v216; __int64 v217; __int64 v218; __int64 v219; char *v220; char v221; unsigned __int64 v222; unsigned __int64 v223; char v224; _BYTE *to_match_page_2; _QWORD *v227; _QWORD *v228; _QWORD *v230; _QWORD *v231; _BYTE *to_match_page; PPHYSICAL_MEMORY_RANGE v233; _OWORD *v234; _BYTE pattern[144 ]; char v237[8 ]; __m128 v238[17 ]; __m128 build_version[17 ]; 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 = 0xCBF29CE484222325 uLL; do { v19 = 0x100000001B3 LL * (v18 ^ v17); v20 = *v16++; v17 = v20; v18 = v19; } while ( v20 ); if ( v19 == 0x8CD9141D23428B07 uLL ) { 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 0xC000009A LL; } 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 = 0xCBF29CE484222325 uLL; do { v35 = 0x100000001B3 LL * (v34 ^ v33); v36 = *v32++; v33 = v36; v34 = v35; } while ( v36 ); if ( v35 == 0x8A0AB57E2BF51C65 uLL ) { 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 = 0xCBF29CE484222325 uLL; do { v195 = 0x100000001B3 LL * (v194 ^ v193); v196 = *v192++; v193 = v196; v194 = v195; } while ( v196 ); if ( v195 == 0xD59511FF39773CA6 uLL ) { 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 = 0x100000001B3 LL; 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 = 0xCBF29CE484222325 uLL; do { v56 = n1970169159_1 * (v55 ^ v53); v57 = *v54++; v53 = v57; v55 = v56; } while ( v57 ); if ( v56 == 0x306328EE8E049A39 LL ) { 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 & 0xFFFFFFFFFFFFF000 uLL; if ( MmCopyMemory(to_match_page_4, page_index, 4096 , 1 , v237) < 0 ) 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 = 0xCBF29CE484222325 uLL; do { v71 = n1970169159_1 * (v70 ^ v69); v72 = *v68++; v69 = v72; v70 = v71; } while ( v72 ); if ( v71 == 0x40ED8EA987B20683 LL ) { 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 = 0xCBF29CE484222325 uLL; do { v126 = n1970169159_1 * (v125 ^ v124); v127 = *v123++; v124 = v127; v125 = v126; } while ( v127 ); if ( v126 == 0x47E1CA0E288956C0 LL ) 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' ); 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 = 0xCBF29CE484222325 uLL; do { v223 = n1970169159_1 * (v222 ^ v221); v224 = *v220++; v221 = v224; v222 = v223; } while ( v224 ); if ( v223 == 0x22E1FD0DBA67A3F2 LL ) break ; } if ( ++v218 == v214 ) goto LABEL_216; } } } sub_1180(v238, 0 , 0x114 u); 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 = 0xCBF29CE484222325 uLL; do { v113 = n1970169159_1 * (v112 ^ v111); v114 = *v110++; v111 = v114; v112 = v113; } while ( v114 ); if ( v113 == 0x2F0FCEED6FC55D71 LL ) { 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 , 0x114 u); 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 = 0xCBF29CE484222325 uLL; do { v93 = n1970169159_1 * (v92 ^ v91); v94 = *v90++; v91 = v94; v92 = v93; } while ( v94 ); if ( v93 == 0x2F0FCEED6FC55D71 LL ) { 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 = 0xCBF29CE484222325 uLL; do { v141 = n1970169159_1 * (v140 ^ v139); v142 = *v138++; v139 = v142; v140 = v141; } while ( v142 ); if ( v141 == 0x47E1CA0E288956C0 LL ) 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 = 0xCBF29CE484222325 uLL; do { v180 = n1970169159_1 * (v179 ^ v178); v181 = *v177++; v178 = v181; v179 = v180; } while ( v181 ); if ( v180 == 0x7F6272C86A6EEADC LL ) 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 = 0xCBF29CE484222325 uLL; do { v154 = n1970169159_1 * (v153 ^ v152); v155 = *v151++; v152 = v155; v153 = v154; } while ( v155 ); if ( v154 == 0x47E1CA0E288956C0 LL ) { 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 = 0xCBF29CE484222325 uLL; do { v169 = 0x100000001B3 LL * (v168 ^ v167); v170 = *v166++; v167 = v170; v168 = v169; } while ( v170 ); if ( v169 == 0xD59511FF39773CA6 uLL ) { 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 = 0xCBF29CE484222325 uLL; do { v209 = 0x100000001B3 LL * (v208 ^ v207); v210 = *v206++; v207 = v210; v208 = v209; } while ( v210 ); if ( v209 == 0x7F6272C86A6EEADC LL ) 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 0xC0000225 LL; }
总体来说就是遍历物理页寻找某个根据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; __int64 n28; *((_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 ) = 0x1300000019 LL; 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 ) = 0x1300000019 LL; qmemcpy(pattern + 8 , "xxxxxxxxxxxxxxx????x" , 20 ); goto LABEL_8; } *(_QWORD *)pattern = &unk_210D0; *((_QWORD *)pattern + 9 ) = 0x1300000019 LL; qmemcpy(pattern + 8 , "xx????x?xx????xxxx" , 18 ); } else { *(_QWORD *)pattern = sub_210B0; *((_QWORD *)pattern + 9 ) = 0x1300000019 LL; qmemcpy(pattern + 8 , "xxxxxxx?xx????xxxx" , 18 ); } } else { *(_QWORD *)pattern = &unk_21070; *((_QWORD *)pattern + 9 ) = 0x1300000019 LL; 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 ) = 0x170000001D LL; 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; __int64 result; unsigned int v6; __int64 *v7; if ( !byte_1D0FD10 ) return 0xC00000A3 LL; 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); __int64 v7; __int64 v8; __int64 v9; __int64 v10; __int64 v11; __int64 v12; char v13; char *v14; unsigned __int64 v15; __int64 v16; char v17; PIRP (__stdcall *IoBuildDeviceIoControlRequest)(ULONG, PDEVICE_OBJECT, PVOID, ULONG, PVOID, ULONG, BOOLEAN, PKEVENT, PIO_STATUS_BLOCK); __int64 v19; __int64 v20; __int64 v21; __int64 v22; __int64 v23; __int64 v24; __int64 v25; char v26; char *v27; unsigned __int64 v28; __int64 v29; char v30; __int64 v31; __int64 v32; NTSTATUS (__stdcall *IofCallDriver)(PDEVICE_OBJECT, PIRP); __int64 v34; __int64 v35; __int64 v36; __int64 v37; __int64 v38; __int64 v39; __int64 v40; char v41; char *v42; unsigned __int64 v43; __int64 v44; char v45; unsigned int n259; NTSTATUS (__stdcall *KeWaitForSingleObject)(PVOID, KWAIT_REASON, KPROCESSOR_MODE, BOOLEAN, PLARGE_INTEGER); __int64 v48; __int64 v49; __int64 v50; __int64 v51; __int64 v52; __int64 v53; __int64 v54; char v55; char *v56; char v57; unsigned __int64 v58; __int64 v59; char v60; __int64 v62; __int64 v63; __int64 v64; __int128 v65; __int64 n5; __int64 v67; int n56; char v69; _BYTE v70[7 ]; int n8; __int64 v72; __int64 v73; _DWORD v74[4 ]; _BYTE v75[88 ]; 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 = 0xCBF29CE484222325 uLL; do { v16 = 0x100000001B3 LL * (v15 ^ v13); v17 = *v14++; v13 = v17; v15 = v16; } while ( v17 ); if ( v16 == 0xD9FE78EA5EE16A1 LL ) { 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 = 0xCBF29CE484222325 uLL; do { v29 = 0x100000001B3 LL * (v28 ^ v26); v30 = *v27++; v26 = v30; v28 = v29; } while ( v30 ); if ( v29 == 0x1D9B1572A04955D7 LL ) { 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 = 0xCBF29CE484222325 uLL; do { v44 = 0x100000001B3 LL * (v43 ^ v41); v45 = *v42++; v41 = v45; v43 = v44; } while ( v45 ); if ( v44 == 0xC26886D76545A61B uLL ) { 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 = 0xCBF29CE484222325 uLL; do { v59 = 0x100000001B3 LL * (v58 ^ v57); v60 = *v56++; v57 = v60; v58 = v59; } while ( v60 ); if ( v59 == 0x11BDFAD31435CB3C LL ) 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然后直接返回:
在该断点断下后用以下Windbg指令获取模块基址, 在IDA中将驱动 rebase 成 0, 很方便能下断点:
1 2 3 r @$t0=@rip-0x1D34000 bp @$t0+CD09 g
唯一的问题就是每次环境只能断下一次, 因为三环应用的逻辑是安装驱动前会先检查cpuid的行为是否是已经安装驱动后的, 如果是的话跳过安装驱动, 所以记得拍好快照
下面基于已经分析了的内容在开启Hyper-V后继续解题
开启Hyper-V后成功断在匹配模式成功点, 说明开启Hyper-V后才能成功匹配到模式:
继续大调查这个匹配成功得到的地址, 发现只有题目驱动处理过的这个页是可以读取的, 而且它自己还输出了日志, 表明这里是在根据系统版本匹配VMExitHandler:
查询资料可以知道, 原来Hyper-V自己有一套完整的VT-x框架, 包括VMExit之后的分发逻辑, 那么这里大概率就是在寻找这个分发器并 hook cpuid对应的VMExitHandler, 在调试机上把hvix64.exe拉下来之后找到这个模式, 发现它的目标是这个模式 +13h偏移处的一条call:
让AI分析, 在FC40找到了高可疑的inline hook + trampoline跳回标志代码:
那么基本可以确定是hook了hvix64.exe的cpuid VMExitHandler, 另外还得知该攻击手法为Diskjacker
接下来让AI继续寻找驱动自己的handler, 因为直接寻找几个cpuid通信的控制码无果, 大概率不是直接对比来分发, 或者是隐藏了代码需要解密, AI分析得出的结果是驱动还在E630手动映射了一个隐藏驱动:
Windbg在关键函数下断点dump出这个映像IDA就能分析了, 成功在里面找到了上面分析出来的几个导出对象中包含flag验证的部分:
至此可以得出第二问的回答如下:
三环应用创建了磁盘设备栈
驱动层遍历物理内存范围筛选全为ff的空闲页, 因为Hyper-V隐藏自身代码页后其代码页读的结果就是全ff的空闲页
驱动层通过IOCTL_SCSI_PASS_THROUGH_DIRECT(0x4d014)控制码与磁盘设备栈通信对筛选出的空闲页进行DDMA, 绕过CPU读写内存会被EPT拦截的限制(3E10)
驱动层将DDMA读出的真正内存拿去匹配一个根据系统版本生成的模式, 匹配的目标是找到hvix64.exe/hvax64.exe(根据CPU厂商决定)中对cpuid的VMExitHandler
驱动层释放带hook的恶意驱动并再次通过DDMA将hook写入原 handler 的跳转目标, 实现对Hyper-V对cpuid操作的处理的劫持
计算出正确的终止密码,输入到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; __int64 seed2; unsigned __int64 seed3; __int64 seed4; unsigned __int64 v6; unsigned __int64 v7; unsigned __int64 v8; unsigned __int64 v9; unsigned __int64 v10; unsigned __int64 v11; unsigned __int64 v12; unsigned __int64 v13; unsigned __int64 v14; unsigned __int64 v15; unsigned __int64 v16; unsigned __int64 v17; unsigned __int64 v18; unsigned __int64 v19; unsigned __int64 v20; unsigned __int64 v21; unsigned __int64 v22; unsigned __int64 v23; unsigned __int64 v24; unsigned __int64 v25; unsigned __int64 v26; unsigned __int64 v27; unsigned __int64 v28; unsigned __int64 v29; unsigned __int64 v30; unsigned __int64 v31; unsigned __int64 f16_1; unsigned __int64 l16_1; seed1 = 0x9E3779B97F4A7C15 uLL * __ROL8__( *(_QWORD *)(((unsigned __int64)payload_1 & 0xFFFFFFFFFFFFF000 uLL) + 0x508 ) ^ 0x4859504552564D58 LL, 13 ) + (*(_QWORD *)(((unsigned __int64)payload_1 & 0xFFFFFFFFFFFFF000 uLL) + 0x500 ) ^ 0x5348414430574E54 LL); seed2 = __ROL8__(seed1, 29 ); seed3 = (((seed2 - 0x40A7B892E31B1A47 LL) ^ *(_QWORD *)(((unsigned __int64)payload_1 & 0xFFFFFFFFFFFFF000 uLL) + 0x508 ) ^ 0x4859504552564D58 uLL) >> 17 ) ^ seed1; seed4 = (seed3 << 7 ) + ((seed2 - 0x40A7B892E31B1A47 LL) ^ *(_QWORD *)(((unsigned __int64)payload_1 & 0xFFFFFFFFFFFFF000 uLL) + 0x508 ) ^ 0x4859504552564D58 LL); v6 = 0x9E3779B97F4A7C15 uLL * __ROL8__(seed4, 13 ) + seed3; v7 = (__ROL8__(v6, 29 ) - 0x40A7B892E31B1A47 LL) ^ seed4; v8 = (v7 >> 17 ) ^ v6; v9 = (v8 << 7 ) + v7; v10 = 0x9E3779B97F4A7C15 uLL * __ROL8__(v9, 13 ) + v8; v11 = (__ROL8__(v10, 29 ) - 0x40A7B892E31B1A47 LL) ^ v9; v12 = (v11 >> 17 ) ^ v10; v13 = (v12 << 7 ) + v11; v14 = 0x9E3779B97F4A7C15 uLL * __ROL8__(v13, 13 ) + v12; v15 = (__ROL8__(v14, 29 ) - 0x40A7B892E31B1A47 LL) ^ v13; v16 = (v15 >> 17 ) ^ v14; v17 = (v16 << 7 ) + v15; v18 = 0x9E3779B97F4A7C15 uLL * __ROL8__(v17, 13 ) + v16; v19 = (__ROL8__(v18, 29 ) - 0x40A7B892E31B1A47 LL) ^ v17; v20 = (v19 >> 17 ) ^ v18; v21 = (v20 << 7 ) + v19; v22 = 0x9E3779B97F4A7C15 uLL * __ROL8__(v21, 13 ) + v20; v23 = (__ROL8__(v22, 29 ) - 0x40A7B892E31B1A47 LL) ^ v21; v24 = (v23 >> 17 ) ^ v22; v25 = (v24 << 7 ) + v23; v26 = 0x9E3779B97F4A7C15 uLL * __ROL8__(v25, 13 ) + v24; v27 = (__ROL8__(v26, 29 ) - 0x40A7B892E31B1A47 LL) ^ v25; v28 = (v27 >> 17 ) ^ v26; v29 = (v28 << 7 ) + v27; v30 = 0x9E3779B97F4A7C15 uLL * __ROL8__(v29, 13 ) + v28; v31 = (__ROL8__(v30, 29 ) - 0x40A7B892E31B1A47 LL) ^ 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直接可以找到:
现在只需要分析以下参数传入的顺序就可以计算出正确输入了, 以输入1234567812345678abcdefacdefabefa为例, 在执行cpuid的前一刻前 4 个寄存器分别存放魔数, 前16个hex, 控制码, 后16个hex:
Intel 平台下的 hook 传入的寄存器顺序分别是:
最终进入check的输入数据顺序就是前16个hex, 后16个hex:
至此可以写出本机的注册机:
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 ]: 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()
顺便提一嘴, 用AI要保持怀疑态度, 这里AI看校验函数认为那两个qword是释放出来的payload.sys的payload_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,都可以正确计算出终止密码 思路如下:
静态解析驱动层所有模式
根据当前 OS build 通过对应的模式去System32下的hvix64.exe/hvax64.exe文件中进行匹配
静态解析trampoline槽位应该填入的地址
通过这个地址得到目标两个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 annotationsimport argparseimport osimport subprocessimport sysfrom dataclasses import dataclassfrom pathlib import Pathfrom typing import Iterableimport pefileMASK64 = 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 ]: 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 ]: 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: 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()
编写检测代码,检测「影」核心系统攻击操作系统底层的特殊方法 依旧检测最后做, 整体是蜜罐的思路, 具体如下:
关闭Hyper-V
安装自己的VT驱动
在自己的驱动中构造会被题目的驱动扫描到的陷阱页
将陷阱页映射到全ff的保护页, 确保过题目驱动的第一关检测
监测这块内存
源码见附件, 主要是在vmexit_custom.cpp中, 这里只说一下为什么要分配12页的陷阱, 一开始的时候我甚至只分配了1页, 只存放关键的模式让题目的驱动进行扫描, 后面发现虽然能够成功在题目驱动中扫描到目标模式的关键点断下, 但是我们的陷阱页没被篡改.
于是我以为是题目还检查了handler是否有效, 毕竟后面自己的payload.sys在 fallback 的时候还要用(也就是存在payload_1槽位里的那个地址), 然后就分配了两页一页装hvix64.exe中handler的调用点所在页, 一页装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; __int64 v7; PVOID (__stdcall *MmAllocateContiguousMemory)(SIZE_T, PHYSICAL_ADDRESS); __int64 v10; __int64 v11; __int64 v12; __int64 v13; __int64 v14; __int64 v15; __int64 v16; char v17; char *v18; char v19; unsigned __int64 v20; __int64 v21; char v22; unsigned __int64 v23; __int64 v24; void (__stdcall *MmUnmapIoSpace)(PVOID, SIZE_T); int (__fastcall *MmCopyMemory)(__int64, unsigned __int64, unsigned __int64, __int64, char *); __int64 v28; __int64 v29; __int64 v30; __int64 v31; __int64 v32; __int64 v33; __int64 v34; char *v35; char v36; unsigned __int64 v37; __int64 v38; char v39; unsigned __int64 v40; unsigned __int64 n0xFF7; __int64 (__fastcall *MmMaploSpace)(unsigned __int64, unsigned __int64, _QWORD); __int64 v43; __int64 v44; __int64 v45; __int64 v46; __int64 v47; __int64 v48; char v49; char *v50; char v51; unsigned __int64 v52; __int64 v53; char v54; __int64 v55; __int64 v56; unsigned int v57; __int64 v58; unsigned __int64 v59; unsigned __int64 v60; int n204; __int64 ntoskrnl_base_addr; __int64 v63; __int64 v64; __int64 v65; __int64 v66; __int64 v67; __int64 v68; __int64 v69; char *v70; char v71; unsigned __int64 v72; __int64 v73; char v74; __int64 v75; __int64 v76; __int64 v77; __int64 v78; char *v79; char v80; unsigned __int64 v81; __int64 v82; char v83; __int64 v84; __int64 v85; __int64 *v87; __int64 v89; __int64 v90; __int64 v91; char v92[72 ]; 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 = 0xCBF29CE484222325 uLL; do { v21 = 0x100000001B3 LL * (v20 ^ v19); v22 = *v18++; v19 = v22; v20 = v21; } while ( v22 ); if ( v21 == 0x8CD9141D23428B07 uLL ) { 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 0xC000009A LL; } v91 = a1[1 ]; if ( v91 <= 0 ) return 0xC0000001 LL; 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 = 0xCBF29CE484222325 uLL; do { v38 = 0x100000001B3 LL * (v37 ^ v36); v39 = *v35++; v36 = v39; v37 = v38; } while ( v39 ); if ( v38 == 0x306328EE8E049A39 LL ) 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) & 0xFFFFFFFFFFFFF000 uLL; 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 = 0xCBF29CE484222325 uLL; do { v53 = 0x100000001B3 LL * (v52 ^ v51); v54 = *v50++; v51 = v54; v52 = v53; } while ( v54 ); if ( v53 == 0x40ED8EA987B20683 LL ) 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 0xC0000001 LL; } 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 = 0xCBF29CE484222325 uLL; do { v82 = 0x100000001B3 LL * (v81 ^ v80); v83 = *v79++; v80 = v83; v81 = v82; } while ( v83 ); if ( v82 == 0x47E1CA0E288956C0 LL ) 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 = 0xCBF29CE484222325 uLL; do { v73 = 0x100000001B3 LL * (v72 ^ v71); v74 = *v70++; v71 = v74; v72 = v73; } while ( v74 ); if ( v73 == 0x47E1CA0E288956C0 LL ) 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页并映射到保护页
另外需要注意一点的是, hvpp的allocator底层使用ExAllocatePoolWithTag来分配内存, 这样得到的内存只能保证虚拟上连续, 物理上几乎不可能连续, 需要自己改用MmAllocateContiguousMemory分配物理连续内存
先运行自己的VT驱动, 启用控制程序发送detc指令初始化陷阱页环境, 最后启动题目程序, 成功监测到陷阱页被修改:
使用这种方法甚至可以依赖于我们自己就能操纵 host 的行为来实现调试payload.sys的功能
附件