关于一次Windows 注册表回调保护的研究
系统版本
可以看到当应用程序尝试更改Windows Defender注册表项被拦截了。
经过调试发现具体注册表如下, 对这个注册表项的修改遭到了拒绝,怀疑可能有注册表回调。
使用WinArk工具,查看系统内核通知。可以看到微软注册了一个注册表回调。
尝试移除回调,然后失败了,返回值是参数无效STATUS_INVALID_PARAMETER
。
想着IDA简单静态分析这个回调函数里干了些什么,结果转到这个地址,啥也不是啊。
1: kd> u FFFFF80512E652F0
nt!CmpPreloadedHivesList:
fffff805`12e652f0 f052 lock push rdx
fffff805`12e652f2 e612 out 12h,al
fffff805`12e652f4 05f8fffff0 add eax,0F0FFFFF8h
fffff805`12e652f9 52 push rdx
fffff805`12e652fa e612 out 12h,al
fffff805`12e652fc 05f8ffff62 add eax,62FFFFF8h
fffff805`12e65301 4a0000 add byte ptr [rax],al
fffff805`12e65304 6d ins dword ptr [rdi],dx
1: kd> dps FFFFF80512E652F0
fffff80512e652f0 fffff80512e652f0 nt!CmpPreloadedHivesList
fffff80512e652f8 fffff80512e652f0 nt!CmpPreloadedHivesList
接下来搜索字符串吧,啥也没有。?????????
还是Windbg动态调试吧!可以看到当前回调个数为1。
0: kd> dd nt!CmpCallbackCount
fffff805`12e6d8b4 00000001 00000100 00000000 12abc460
fffff805`12e6d8c4 fffff805 12e6dac0 fffff805 0000005a
fffff805`12e6d8d4 00000050 3ff7e000 00000000 dec48d80
fffff805`12e6d8e4 ffff8d0f 00000001 00000001 e47efa60
fffff805`12e6d8f4 ffffe586 00000001 0000004c 000000e0
fffff805`12e6d904 00000044 00000005 0000001a decf5310
fffff805`12e6d914 ffff8d0f 00000004 00000001 12e1ff20
fffff805`12e6d924 fffff805 126ce580 fffff805 00000000
接下来看看CallbackListHead
链表,第一个值是fffff805`12e652f0。非空
0: kd> dq nt!CallbackListHead
fffff805`12e652d0 ffff8d0f`e014cec0 ffff8d0f`e014cec0
fffff805`12e652e0 00000000`00000000 01d87756`d4646f4a
fffff805`12e652f0 fffff805`12e652f0 fffff805`12e652f0
fffff805`12e65300 0000066d`00004a62 00000000`00160014
fffff805`12e65310 fffff805`12e65338 00000000`003a0038
fffff805`12e65320 fffff805`12e653b8 00000000`0050004e
fffff805`12e65330 fffff805`12e65438 0072005f`00620076
fffff805`12e65340 00610065`006c0065 00000000`00650073
再看看下一个呢?第二个值是fffff805`14138ec0。
0: kd> dq ffff8d0f`e014cec0
ffff8d0f`e014cec0 fffff805`12e652d0 fffff805`12e652d0
ffff8d0f`e014ced0 00000000`00000000 01d87756`d4646f49
ffff8d0f`e014cee0 00000000`00000000 fffff805`14138ec0
ffff8d0f`e014cef0 00000000`000c000c ffff8d0f`e020d210
ffff8d0f`e014cf00 ffff8d0f`e014cf00 ffff8d0f`e014cf00
ffff8d0f`e014cf10 6d4e624f`03060000 00000000`00000000
ffff8d0f`e014cf20 00720063`0069004d 0066006f`0073006f
ffff8d0f`e014cf30 006c0061`004d0074 00650072`00610077
下一个的地址是fffff80512e652d0,也就是回到了
CallbackListHead`。因此不用在看了。
对两个地址的反汇编结果表明fffff805`14138ec0才是真正的回调地址,所在模块是WdFilter.sys。
0: kd> u fffff805`14138ec0
*** ERROR: Module load completed but symbols could not be loaded for WdFilter.sys
WdFilter+0x38ec0:
fffff805`14138ec0 48895c2408 mov qword ptr [rsp+8],rbx
fffff805`14138ec5 55 push rbp
fffff805`14138ec6 56 push rsi
fffff805`14138ec7 57 push rdi
fffff805`14138ec8 4154 push r12
fffff805`14138eca 4155 push r13
fffff805`14138ecc 4156 push r14
fffff805`14138ece 4157 push r15
0: kd> u fffff805`12e652f0
nt!CmpPreloadedHivesList:
fffff805`12e652f0 f052 lock push rdx
fffff805`12e652f2 e612 out 12h,al
fffff805`12e652f4 05f8fffff0 add eax,0F0FFFFF8h
fffff805`12e652f9 52 push rdx
fffff805`12e652fa e612 out 12h,al
fffff805`12e652fc 05f8ffff62 add eax,62FFFFF8h
fffff805`12e65301 4a0000 add byte ptr [rax],al
fffff805`12e65304 6d ins dword ptr [rdi],dx
由此可见,我们的WinArk遍历存在问题。试了一下PyArk.exe,也存在同样的问题,但是比我强的是他把WdFilter.sys的驱动的注册表回调遍历出来了,此时的注册表回调函数应该只有一个才对,他错误地显示了两个。
查看WdFilter模块信息
0: kd> lmDvmWdFilter
Browse full module list
start end module name
fffff805`14100000 fffff805`1416f000 WdFilter (no symbols)
Loaded symbol image file: WdFilter.sys
Image path: \SystemRoot\system32\drivers\wd\WdFilter.sys
Image name: WdFilter.sys
Browse all global symbols functions data
Image was built with /Brepro flag.
Timestamp: 75C63DA1 (This is a reproducible build file hash, not a timestamp)
CheckSum: 0007B0E9
ImageSize: 0006F000
Translations: 0000.04b0 0000.04e4 0409.04b0 0409.04e4
Information from resource tables:
提取出来转到函数进行IDA静态分析。拖到函数尾部,可以看到返回值是要么是0,要么是0xC0000022,即STATUS_ACCESS_DENIED
和STATUS_SUCCESS
。
由此对于这个变量的交叉引用变得尤为重要。
可以看到微软写了9个判定函数。
经过简单分析,应该就是他了。
细节不进行逆向了,主要是目的修复WinArk.exe的bug。以下是修复后的结果。
移除后可以成功修改Defender注册表。
手动重启后,可以发现WinDefend服务没有自启动,处于Stop状态且实时保护等也被关闭了。
经过测试PyArk对于错误回调信息的移除成功与否可能没做判断,看着界面没了,但是刷新后又回来了。