首页
社区
课程
招聘
[原创]SetWindowDisplayAffinity:原理与检测(DWM篇)
发表于: 1小时前 42

[原创]SetWindowDisplayAffinity:原理与检测(DWM篇)

1小时前
42

窗口隐藏与反截屏系列 · 第 1 期

工具:IDA · CE · Hawkeye Community · Cursor MCP


目录

  1. 背景与系列规划
  2. win32k 内核链
  3. DWM 侧线索
  4. HasProtectedContent 在做什么
  5. 内存验证
  6. 检测思路(有法有解)
  7. 开源实现

1. 背景与系列规划

SetWindowDisplayAffinity(常见用法:WDA_EXCLUDEFROMCAPTURE)是一种广为人知的反截屏隐私手段。基于此我们打算使用三期来围绕这个话题展开探索。

本系列共三篇,本篇为第一期:

  • 第 1 期(本文)SetWindowDisplayAffinity 原理与检测
  • 第 2 期:Visual 层隐藏原理与检测
  • 第 3 期:基于 BitBlt 的「超级截屏」方案

2. win32k 内核链

用户态调用进入内核后,落脚在 win32kfull!NtUserSetWindowDisplayAffinity,核心逻辑在 SetDisplayAffinity。简化调用链如下:

NtUserSetWindowDisplayAffinity
  └─ SetDisplayAffinity
       ├─ ComposeWindowIfNeeded
       ├─ InternalSetProp / InternalRemoveProp("SysDispAffinity")
       └─ ChangeWindowTreeProtection
            └─ ProtectWindowBitmap
                 ├─ ChangeWindowBitmapOwner
                 └─ GreProtectSpriteContent
                      └─ DwmAsyncUpdateSprite → dwm.exe

DwmAsyncUpdateSprite 最终发送了一个 LPC 消息到 dwm.exe 进程。在整个过程中,除了对 tagWND 中 SysDispAffinity 属性有所涉及,其他相关改动较少。另外,不同 Windows 版本中属性编号时常变动,因此,基于内核去检测窗口的隐藏,在稳定性和兼容性上会差一些。

经过对 dwmcore.dll 的研究,发现截屏路径与直接显示路径是不同的,分别对应 CCaptureRenderTargetCDDisplayRenderTarget。结合更多观察与分析,可以给出判定:在反截屏方面,DWM 进程负责完整逻辑,内核方面作用有限。


3. DWM 侧线索

窗口是否「截屏隐藏」,从机制上应体现在 DWM CCaptureRenderTarget 的合成输出上。dwm.exe 加载多个模块;但嫌疑最大的应该是 dwm.exedwmcore.dlldwmredir.dlluDWM.dll(下文先在这几个模块里搜线索)——毕竟名字里都带 dwm

在 Hawkeye Community 中先用 !probe -pid:<dwm_pid> attach dwm.exe,再对下列四个模块联合搜索 protect 关键字:

!probe -find:protect -mod:dwmcore,dwmredir,udwm,dwm

pic1

图 1. !probe -find:protect 命中大量保护相关符号;下文聚焦 CWindowContext

其中嫌疑最大的是 dwmredir 中与窗口内容相关的两个函数:

  • CWindowContext::HasProtectedContent
  • CWindowContext::NotifyProtectionChange

命名已经说明用途:判断窗口内容是否处于保护状态,以及在保护状态变化时通知合成管线。DWM 内还有大量 IsProtected / SetHardwareProtection 等符号,值得继续挖掘。


4. HasProtectedContent 在做什么

反汇编 dwmredir!CWindowContext::HasProtectedContent 非常直接:
pic2
*图 2. 读取 [rcx+0x114]SHR 6AND 1 — 即检测该 DWORD 的 bit 6(0x40)。*

我们可以大胆的猜测:CWindowContext 对象在偏移 +0x114 处有一个标志字段,bit 6 表示内容是否受保护。
另外我们还可以猜测,每个窗口应该都会对应一个CWindowContext对象。且此对象中应该存在CWindowContext虚表指针。基于此猜测,我们就有了搜索目标。即,基于虚表指针来反推CWindowContext对象的结构。

定位 CWindowContext 实例时,注意该类有两张 vftable。应使用 IDwmWindow 接口对应的那张(本机示例如下):
pic3
图 3. !probe -find:CWindowContext,vftable -mod:dwmredir — 定位 IDwmWindow vftable。
pic4
图 4. vftable 地址在 dwmredir.dll 内,可用于在 DWM 堆上扫描对象。


5. 内存验证

实验:对某窗口调用 SetWindowDisplayAffinity(WDA_EXCLUDEFROMCAPTURE),在 CE 中对 dwm.exe 进程搜索该窗口 HWND 的数值,即可找到对应的 CWindowContext 对象。(搜索过程和验证过程省略)
pic5
图 5. 对象布局验证:前 8 字节为 vftable;+0x1140xC7 的 bit6(0x40)为保护位;可交叉验证 HWND 与 owning PID。

观察项 示例 说明
vftable 0x00007FFAF582A000 CWindowContextIDwmWindow)虚表指针
保护标志 +0x114,bit 6 = 1 HasProtectedContent 汇编一致
窗口 kind 0x1 / 0x2 / 0x4 DWM 内部类型枚举(大体猜测):0x1 控制台类、0x2 GUI 窗口(无边框 / 自定义标题栏)、0x4 GUI 窗口
HWND / PID 窗口的句柄和窗口所属进程 PID

再次确认:CWindowContext 对象前 8 字节即为 vftable。不同 Windows 版本中具体偏移会有变动,但 vftable + 保护位 + HWND/PID 这一组特征在多版本上相对稳定,可据此设计检测方案。


6. 检测思路(有法有解)

基于以上分析,窗口截屏排除相关的合成逻辑主要在 DWM 进程内完成,与内核路径关系不大,因此扫描 dwm.exe 是较可行的检测面。

可操作的方案与上文 CE 手工验证类似,但把布局发现自动化:

  1. dwmredir.dll 符号(PDB)解析 IDwmWindow vtable 地址。
  2. 扫描 dwm.exe 可读写的内存区域,查找等于该 vtable 的指针。
  3. 校准阶段:对已知窗口开启反截屏 — 鹰眼在初始化时对自身主窗口调用 SetWindowDisplayAffinity — 再按 vtable、保护位 bit 6、窗口 kind、HWND、所属 PID 锁定匹配对象。
  4. 记录 flags / kind / HWND / PID 相对对象起始的字节偏移,供后续扫描复用。

绝对偏移(例如本机样例中标志 DWORD 在 +0x114)会随 Windows 版本变化;以 vtable 为锚点、校准一次即可保持工具可移植。Community 实现中,扫描时 window kind 仅匹配 0x20x4,尽管内存 dump 里也可能出现 0x1


7. 开源实现

本文所述检测思路已在 Hawkeye Community 落地并开源,对应命令 !hidden_windows(需先 -init)与测试命令 !hidden_windows_sim。Community 版以 dwmredir.dllCWindowContext / IDwmWindow 的 vtable 为锚点,经一次校准得到 flags / kind / HWND / PID 的相对偏移后扫描 dwm.exe 内存。

  • 源码仓库:3a9K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6Z5j5i4N6C8k6i4W2W2i4K6u0V1e0r3g2G2i4K6u0r3K9r3q4%4K9$3g2&6k6g2)9J5k6r3y4G2L8h3#2#2L8X3W2@1P5b7`.`.
  • 预编译包:d57K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6Z5j5i4N6C8k6i4W2W2i4K6u0V1e0r3g2G2i4K6u0r3K9r3q4%4K9$3g2&6k6g2)9J5k6r3y4G2L8h3#2#2L8X3W2@1P5g2)9J5c8Y4u0W2L8r3g2S2M7$3g2K6i4K6u0r3L8r3q4@1k6i4y4@1

系列下一篇:隐藏Visual — 更加自由和隐蔽的反截屏方案。



冰与火的战歌:Windows内核攻防实战高级班!从零到实战,融合AI与Windows内核攻防全技术栈,打造具备自动化能力的内核开发高手。

收藏
免费 0
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回