首页
社区
课程
招聘
[原创]DWM渲染劫持注入ImGui
发表于: 1天前 394

[原创]DWM渲染劫持注入ImGui

1天前
394

一、前言

在 Direct3D 11 渲染劫持的常见方案中,核心实现方式是 Hook CDXGISwapChain::Present方法。CDXGISwapChain 是 DXGI 交换链的内部 C++ 实现类,其中的成员函数遵循 thiscall 调用约定,首参数隐式传递指向类实例的 this 指针。成功劫持该函数后,就可以获取到实例指针完成 ImGui 渲染上下文初始化,注入自定义绘制逻辑。

但是,DWM进程采用独立的桌面合成渲染管线,其帧提交与合成逻辑并不经过 CDXGISwapChain::Present 这一公开调用路径,常规的 Present 劫持手段对 DWM 进程不生效。

二、IDA分析dxgi.dll

将dxgi.dll拖入IDA,函数列表中搜索CDXGISwapChain::Present

其中CDXGISwapChain::PresentImplCoreCDXGISwapChain::PresentImpl调用

CDXGISwapChain::PresentMultiplaneOverlayInternalCDXGISwapChain::PresentMultiplaneOverlay调用

想要找到DWM调用了哪些函数,我的方法是给这些函数都下断点,但是DWM进程是桌面窗口管理器,DWM被暂停后整个桌面画面也会暂停

三、双机调试

1. WinDbg附加到虚拟机后需要Break后才能输入指令

!process 0 0 dwm.exe


2. 我们将进程上下文切换到dwm.exe,使用.process /i <PROCESS>

.process /i ffffe10bbdfa4080


3. 这里提示我们需要继续执行以切换上下文。使用 g 继续执行,上下文就来到了dwm进程空间

然后我们需要使用 .reload /f dxgi.dll 加载符号 可以使用 lm m dxgi 查看符号是否加载成功



4.现在可以直接给函数下断点了

bp dxgi!CDXGISwapChain::PresentBuffer

bp dxgi!CDXGISwapChain::PresentDWM

bp dxgi!CDXGISwapChain::PresentImpl

bp dxgi!CDXGISwapChain::PresentMultiplaneOverlay

bp dxgi!CDXGISwapChain::PresentFullscreenFlip

之后一直使用 g 继续执行,看哪些函数被断下来了

最终dwm只执行了 CDXGISwapChain::PresentDWM  CDXGISwapChain::PresentImpl 这两个函数

四、挂钩函数

我们选择对 CDXGISwapChain::PresentDWM 进行Hook,函数原型为

_int64 __fastcall CDXGISwapChain::PresentDWM(

        CDXGISwapChain *this,

        int a2,

        unsigned int a3,

        int a4,

        const struct tagRECT *a5,

        unsigned int a6,

        const struct DXGI_SCROLL_RECT *a7,

        struct IDXGIResource *a8,

        unsigned int a9);


1. 寻找函数位置直接用最简单的方法:搜函数特征码

		// CDXGISwapChain::PresentDWM 函数特征码
		const unsigned char PresentDWM_Bytes[68] = {
			0x48, 0x89, 0x5C, 0x24, 0x10, 0x55, 0x56, 0x57,
			0x41, 0x54, 0x41, 0x55, 0x41, 0x56, 0x41, 0x57,
			0x48,			'?', '?', '?', '?', '?', '?', '?', '?',			'?', '?', '?', '?', '?', '?', '?', '?',			'?', '?', '?', '?', '?', '?', '?', '?',			'?', '?', '?', '?', '?', '?', '?', '?',			'?', '?', '?', '?', '?', '?', '?', '?',			'?', '?', '?', '?',
			0x8B,			'?', '?', '?', '?', '?',
			0x00
		};

经测试win10 22h2 和 win11 25h2 均可使用此特征码


2. 对函数进行Hook后,以下是Hook回调伪代码

static __int64 CDXGISwapChain_PresentDWM_hook(IDXGISwapChain* _this, int a2, unsigned int a3, int a4, PVOID a5, unsigned int a6, PVOID a7, PVOID a8, unsigned int a9)
{	if (!g_imguiinited)
	{		// 仅初始化一次
		g_imguiinited = true;		
		// ImGui初始化
		_this->GetDevice(__uuidof(ID3D11Device), (void**)&g_pd3dDevice);
		g_pd3dDevice->GetImmediateContext(&g_pd3dContext);		ID3D11Texture2D* buf = nullptr;		_this->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)&buf);		if (!buf)
		{
			g_imguiinited = false;			return CDXGISwapChain_PresentDWM_orig(_this, a2, a3, a4, a5, a6, a7, a8, a9);
		}

		g_pd3dDevice->CreateRenderTargetView(buf, nullptr, &view);
		buf->Release();

		ImGui::CreateContext();
		ImGui_ImplDX11_Init(g_pd3dDevice, g_pd3dContext);

		log("[+] ImGui initialized successfully\n");
	}	// 获取当前后备缓冲区
	ID3D11Texture2D* backBuffer = nullptr;	if (FAILED(_this->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)&backBuffer)))		return CDXGISwapChain_PresentDWM_orig(_this, a2, a3, a4, a5, a6, a7, a8, a9);	// 获取后备缓冲区尺寸
	D3D11_TEXTURE2D_DESC bbDesc;
	backBuffer->GetDesc(&bbDesc);	// 设置 ImGui 显示尺寸
	ImGui::GetIO().DisplaySize = ImVec2((float)bbDesc.Width, (float)bbDesc.Height);	// 释放旧 RTV 并创建新 RTV
	if (view) { view->Release(); view = nullptr; }	if (FAILED(g_pd3dDevice->CreateRenderTargetView(backBuffer, nullptr, &view)))
	{
		backBuffer->Release();		return CDXGISwapChain_PresentDWM_orig(_this, a2, a3, a4, a5, a6, a7, a8, a9);
	}
	backBuffer->Release();	// 保存原始渲染目标
	ID3D11RenderTargetView* prevRTV = nullptr;	ID3D11DepthStencilView* prevDSV = nullptr;
	g_pd3dContext->OMGetRenderTargets(1, &prevRTV, &prevDSV);	// 设置我们的渲染目标
	g_pd3dContext->OMSetRenderTargets(1, &view, nullptr);	// 开始 ImGui 帧
	ImGui_ImplDX11_NewFrame();
	ImGui::NewFrame();	// 绘制矩形
	ImDrawList* draw_list = ImGui::GetForegroundDrawList();
	draw_list->AddRectFilled(ImVec2(100, 100), ImVec2(300, 200), IM_COL32(255, 0, 0, 255));

	ImGui::Render();
	ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData());	// 调用原函数
	return CDXGISwapChain_PresentDWM_orig(_this, a2, a3, a4, a5, a6, a7, a8, a9);
}

初始化ImGui后,就可以进行ImGui绘图了。如果需要ImGui鼠标事件与ImGui窗口交互,还需要安装全局鼠标钩子


3. 测试效果

win11 25h2

win10 22h2

五、总结

虚拟机测试正常后,然后到物理机就没有效果了。

经过调试发现物理机dwm进程没有创建 CDXGISwapChain 类实例对象,也就是没有使用 CDXGISwapChain 类.......................

应该是显卡驱动的原因吧


新手小白,大佬嘴下留情

源码地址:XiaoBeiik/Dwm-Injection-ImGui


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

最后于 1天前 被mb_pelomxiq编辑 ,原因:
收藏
免费 1
打赏
分享
最新回复 (2)
雪    币: 260
活跃值: (505)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
Win11 24H2 + NVIDIA 会使用CDDisplayRenderTarget 而不是 CLegacyRenderTarget
23小时前
0
雪    币: 245
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
3
Peyriat Win11 24H2 + NVIDIA 会使用CDDisplayRenderTarget 而不是 CLegacyRenderTarget
25h2 显示模式换到intel集成显卡也不会走CLegacyRenderTarget,看起来是25h2已经完全不使用旧的接口了,只有虚拟机才用
9小时前
1
游客
登录 | 注册 方可回帖
返回