为什么当我尝试重写指向Direct3D设备的`EndScene`函数的指针时?

问题描述 投票:3回答:2

我尝试挂钩DirectX 9应用程序以从中获取屏幕截图。那就是我的工作:

  1. 我用CreateRemoteThreadLoadLibraryW地址注入DLL作为参数传递。我假设目标应用程序已经正在运行。
  2. 内部DLL的DllMainCreateThread在其中创建临时目录Direct3D设备抓取它的VMT:

    自动pID3D9 = Direct3DCreate9(D3D_SDK_VERSION);D3DPRESENT_PARAMETERS pp = {};IDirect3DDevice9 * pID3DDevice = NULL;自动hr = pID3D9-> CreateDevice(D3DADAPTER_DEFAULT,D3DDEVTYPE_NULLREF,NULL,D3DCREATE_SOFTWARE_VERTEXPROCESSING,&pp和&pID3DDevice);自动pID3DDevicevt = * reinterpret_cast(pID3DDevice);
  3. 当我尝试重写指向Direct3D的指针时没有任何反应设备的EndScene功能:

    //这里'42'是VMT内EndScene的索引,大声笑pID3DDevicevt [42] = my_EndScene;

    注:VirtualProtect重写之前的那个指针,并且VirtualProtect之后,我只是省略了该代码。

  4. 我最终得到“经典”钩子:我重写了6个字节的原始字符功能,因此它无条件跳转到我的功能。然后我恢复原始字节,做我自己的事情,调用原始函数并重新挂钩再次功能。有效。

为什么当我尝试重写指向Direct3D设备的EndScene函数的指针时,什么也没发生?

我已经搜索并看到一些信息,必须使VMT挂钩足够早地放置才能使其正常工作。那是原因吗?

c++ directx hook
2个回答
0
投票

您的问题可能与我的问题非常相似(http://stackoverflow.com/questions/14224747/win7-8-dwm-draw-hooking),但我使用的是ID3D10Device1。似乎Direct3D包含某种保护,可以定期恢复某些方法的原始vtable指针。

我尚未找到解决此问题的正确方法。解决方法是执行定期重新修补vtable的后台线程。但是它消耗了100%的CPU,并且无法捕获所有情况(由于竞争状况)。无法将Yield / Sleep放入此线程,因为它会丢失一些函数调用。

btw,那是什么“经典”钩子?我已经阅读了有关它的内容,但是我不确定如何在x64进程中使用它(添加jmp指令,读取正确的参数,跳回到原始功能等...]


0
投票

解决方案是不执行vtable挂钩。最好的解决方案是使用虚拟设备进行操作,获取vtable,获取EndScene的索引,对其取消引用以获取实际功能的地址,然后执行蹦床挂钩。

我最近的其他答案中提供的完整解决方案,包括蹦床挂钩D3D9 Hooking (EndScene + DrawIndexedPrimitive)的代码

© www.soinside.com 2019 - 2024. All rights reserved.