跟着Windbg看DWM

1.什么是DWM

DWM全称桌面窗口管理程序,是Windows Vista之后一个全新的窗口管理系统,他决定windows应用程序的呈现方式,用过XP的同学肯定遇到过窗口拖影的情况。

在XP时代,窗口绘制都是直接提交到显卡的显存中显示的,简单来说就是Windows桌面只有一个对应的图像缓存,所有程序都直接在这个缓存下进行渲染。这样就知道了只有应用程序知道应该怎么绘图,而XP下的Windows桌面系统完全不知道怎么绘制,因此当窗口出现未响应的窗口被遮挡时,Windows就会产生拖影的现象。

Windows Vista后彻底对窗口系统做了重构,引入了DWM,Windows应用程序的窗口绘制的图形就不会再和XP一样绘制到如上所说的桌面缓存里面去了,而是将绘制操作重定向到DWM的对应的off-screen surface上,然后再通过DWM合成输出到显示器上。

2.DWM对截屏的影响

先看一张图再开启DWM和关闭DWM截取窗口的效果

从图中可以看出启了DWM的则直接截取指定窗口及其子窗口的图像;而没有开启DWM则截取到目标窗口所在区域的所有图形;

其本质原因是如上文所说是

    每个进程中都有各自的Surface,DWM中会为单个进程的所有窗口维护一份合成之后的Surface;
    注意,每个进程在DWM中有且仅有一份Surface,且这个Surface是合成之后的;而一个进程内可以有多份Surface,他们可以是相互独立的;比如DX和GDI的Surface就相互独立
    进程绘制时都是往各自绘图接口所对应的Surface中绘制,然后通知DWM,DWM进行合成最终刷新到显卡的显存中并显示到显示器;
    截图时,BitBlt会根据源hDc向DWM索取指定窗口指定位置合成后的图像;
    而没有开启DWM的情况下,每个进程绘制时都是往各自绘图接口所对应的Surface中绘制,绘制完毕后直接提交到显卡的显存中并显示到显示器;
    截图时,BitBlt会根据源hDc到显卡的指定位置处复制像素数据;

2.1跟着windbg看没有开启DWM情况下图形绘制流程

1、虚拟机中Win7的分辨率设置如下:
2、断点设置如下:
kd> !process 0 0 test_wnd_capture.exe
PROCESS a4ebf348  SessionId: 1  Cid: 0d04    Peb: 7ffd5000  ParentCid: 0764
    DirBase: be63ba60  ObjectTable: b4686c38  HandleCount:  43.
    Image: test_wnd_capture.exe
kd> ba e1 win32k!EngLineTo ".if(@$tpid==0d04){dt _eprocess @$proc -yn ImageF;kb}.else{gc;}"
3.运行windbg调试器, 断点命中,栈回溯如下
再上面的windbg截图中, 我们可以发现2个进程中的pso(pso是surfaceobj稍后会介绍到)不一样,pso.pvBits也不一样,这就说明了,再没有开启DWM情况下,每个进程的Surface是不一样,并且开启了DWM的进程的surface是放在各自进程用户态空间的,没有开启DWM的进程的surface则放到内核空间。

直接手动修改Surface的像素数据也是OK的,看下图:

4、那么谁会将这些Surface的像素数据刷新到显存呢?
4.1 在surface中下物理断点:
4.2 断点命中时, 堆栈如下:
我们发现时CSRSS.EXE调用cdd.dll来刷新像素数据到对应, cdd.dll:Canonical Display Driver, 是桌面架构用来混合Windows图形用户界面(GUI)和DirectX绘图的。
意思就是说在没有开启DWM情况最终对调用的 cdd.dll:DrvLineTo调用 CDD显卡驱动进行绘制。

2.2 跟着windbg看开启DWM情况下图形绘制流程

还是以画线函数为例看DWM情况下图形绘制流程,简单做个逆向分析便知道该API的调用链如下:

     Gdi32!LineTo---->GDI32!NtGdiLineTo---->win32k!NtGdiLineTo---->win32k!GreLineTo---->win32k!EngLineTo;
EngLineTo()是OS导出的接口,原型如下: EngLineTo 函数 (winddi.h) - Win32 apps | Microsoft Learn
ENGAPI BOOL EngLineTo(SURFOBJ *pso, CLIPOBJ *pco, BRUSHOBJ *pbo, LONG x1, LONG y1, LONG x2, LONG y2, RECTL *prclBounds, MIX mix);
重点关注第一个参数,如下:
1.
编写程序test_wnd_capture.exe:主窗口,其宽高分别为:800,600;其内部绘制一条曲线和一个红色填充的矩形;   
编写程序 CaptureWnd.exe,由其在test_wnd_capture.exe创建子窗口,子窗口的宽高分别为300,600;;其内部绘制一条曲线和一个绿色填充的矩形;
2.双击调试
3.windbg输入如下命令
由下图知,数据都是正确的;
我们再来看下具体的像素数据:
【像素数据保存在下边这个文件中】
发现了一个问题,居然test_wnd_capture.exe进程的窗口的surface中含有子窗口的像素数据,难不成子窗口共用父窗口的surface吗?只是使用了该surface相对于该子窗口相应的位置及大小?
答案也是这样的,下边我们看下子窗口绘制线条时,其pso参数,若与父窗口的一样,则证实了该结论;
由下图可知,父子窗口的pso确实用的同一个,那也证实了上边的结论,我们在看下子窗口当前所绘制的 pso ;即看
当窗口大小变化时, _SURFOBJ . pvBits 也会改变,即OS会重新分配一块内存用以作为Surface;

ba &_SURFOBJ .pvBits r4;

然后手动改变窗口大小;栈回溯如下:

利用调试器手动的修改这块内存的像素数据,也是会生效的;但当WM_PAINT消息产生时,如果程序没有拦截该消息,OS默认的窗口过程会用背景画刷重绘该区域;

通过上述动手做实验发现了DWM开启时候,操作系统会为应用程序维护一个所有窗口共享的surface, 每个进程的窗口对应一个DC,DC相关接口如BitBlt, DX的想更换接口如ColorFill都只是在对应的DC或Surface上进行操作,最后会合成到进程共享的Surface上去,上述例子也证明了截图父窗口DC为啥可以既然看到DX绘制的红色,也能看到GDI绘制的斜线。

本质上DWM最后会维护所有进程的窗口共享surface, 然后在DWMCore中完全合成最后送显,在显示器中显示

  • 14
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值