本文会介绍一种无需在DWM中挂钩也可以实现DWM桌面绘制的方式 经过测试和验证 该方案可行
这个东西其实弄出来有一段时间了 最近很忙也一直没啥时间
之前问了下神话 大概了解了一下DWM绘制以及原理 顺便抄了一波代码实际上目前大部分DWM绘制基本都依赖于寻找SwapChain并且HOOK某函数进行绘制
在一次偶然的调试中我发现 即便是在原绘制函数执行完毕之后再调用绘制也依然可以进行输出
于是就有了这份思路不废话直接进入主题
DWM绘制路径如下 再往下的就没必要继续看了其中VM3DUMP64为VMWARE的虚拟显卡3环驱动在往上就是SSSDT函数了 NTGDIxxx
我觉得我说到这里已经有人明白要干什么了首先直接讲DLL注入到DWM进程中 获取SwapChain并进行一些初始化操作
初始化完成之后可以释放钩子 对于是否可以不挂钩完成初始化我不太了解 不太懂3环的绘制原理只要拿到了SwapChain
接下来问题就好说了众所周知SSSDT并不受PG保护(实际上是里面的动态函数指针可以随意替换) 这也就给了一些可乘之机
只需要替换里面的动态指针即可完成函数HOOK(提示1:下面一层是dxgkrnl 这一层有相当多东西可以深挖)
(提示2:指针替换这种HOOK方式相比起一般HOOK来说难以发现许多 甚至可以用多层跳转来尽可能的伪装)
OK 在成功拦截来自DWM的绘制请求以后 就可以开始正式的绘制了其实思路很简单栈回潮 然后修改函数返回地址即可也就是stack hook
[C++] 纯文本查看 复制代码
FunctionEntry = RtlLookupFunctionEntry(ContextRecord.Rip,
&ImageBase,
NULL);
if ((FunctionEntry != NULL))
{
RtlVirtualUnwind(0,
(ULONG64)ImageBase2.ModuleBase,
ContextRecord.Rip,
FunctionEntry,
&ContextRecord,
&HandlerData,
&EstablisherFrame,
NULL);
ULONG64 *p = (ULONG64*)((ULONG64)ContextRecord.Rsp - 8);
ULONG64 test12345 = *p;
if (test12345 == 0x00000)
{
*p = 0x123456789;
break;
}
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "%llx\n", test12345);
//std::cout << std::hex<< test12345 << std::endl;
}
先前已经成功将DLL注入进程中并且完成了初始化 那么现在要做的就是回潮 修改地址 然后放过3环请求绘制正常进行
当运行到3环目标函数返回时 这个时候函数被截获 DLL的绘制函数也就拿到了执行权正常绘制之后 循环再次运行
重新前往内核 这一层在提交的dma中 就已经带上了先前DLL的绘制内容至此 整个绘制已经成功
由于stack hook的特性 在DWM中无法扫到任何HOOK 即便是文件内存对比也是无效的至于DLL本身
隐藏内存简直不要太简单
虽然DWM进程中没有了HOOK 但R0依然有一个动态指针替换 不过既然主战场已经移到了内核 某种意义上来说就轻松太多了 至少对我来说 我宁愿把大家都拉倒内核去互掐 也不愿意在R3大乱斗
OK 最后的最后 放上几张图
我就愿意读栈回潮
|