3

我尝试连接 DirectX 9 应用程序以从中获取屏幕截图。这就是我所做的:

  1. 我注入了我的 DLL,CreateRemoteThread并将LoadLibraryW地址作为参数传递。我假设目标应用程序此时已经在运行。
  2. 在 DLL 的DllMainICreateThread中,我创建了一个临时 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' 是 EndScene 在 VMT 中的索引,哈哈
    pID3DDevicevt[42] = my_EndScene;

    注意:VirtualProtect在重写之前的那个指针和 VirtualProtect它之后的指针,我只是省略了那个代码。

  4. 我以“经典”挂钩结束:我重写了 6 个字节的原始函数,因此它无条件地跳转到我的函数。然后我恢复原始字节,做我自己的事情,调用原始函数并再次重新挂钩该函数。有用。

当我尝试重写 Direct3D 设备EndScene函数的指针时,为什么没有任何反应?

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

4

2 回答 2

0

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

我还没有找到解决这个问题的正确方法。解决方法是执行定期重新修补 vtable 的后台线程。但它占用了 100% 的 CPU 并且不能捕获所有情况(由于竞争条件)。Yield/Sleep 不能放入这个线程,因为它会错过一些函数调用。

顺便说一句,那是什么“经典”挂钩?我已经阅读了一些关于它的内容,但我不确定如何将它用于 x64 进程(添加 jmp 指令、读取正确的参数、跳回原始函数等......)

于 2013-01-12T17:51:54.957 回答
-1

解决方案是不做 vtable 钩子。最好的解决方案是使用虚拟设备执行您正在执行的操作,获取 vtable,获取 EndScene 的索引,取消引用它以获取实际函数的地址,然后执行蹦床挂钩。

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

于 2020-04-06T04:40:58.363 回答