从注入的DLL钩住DirectX EndScene

我想绕过任意DirectX 9应用程序的EndScene来创建一个小覆盖。 举个例子,你可以采用FRAPS的帧计数器覆盖,当游戏被激活时显示。

我知道下面的方法来做到这一点:

  • 创建一个新的d3d9.dll,然后将其复制到游戏路径。 由于当前文件夹是首先搜索,在去system32等之前,我修改的DLL被加载,执行我的附加代码。

    下行:在开始游戏之前,你必须把它放在那里。

  • 与第一种方法相同,但直接替换system32中的DLL。
  • 下行:你不能添加游戏特定的代码。 您不能排除不希望加载DLL的应用程序。

  • 使用IDA Pro 4.9 Free等工具直接从DLL获得EndScene偏移量。 由于DLL是按原样加载的,因此可以将该偏移量添加到DLL起始地址,将其映射到游戏时获取实际偏移量,然后挂钩它。
  • 下行:每个系统的偏移量都不相同。

  • 挂接Direct3DCreate9以获取D3D9,然后挂接D3D9-> CreateDevice以获取设备指针,然后通过虚拟表钩住Device-> EndScene。
  • 下行:当进程已经运行时,DLL不能被注入。 您必须使用CREATE_SUSPENDED标志启动进程以挂钩初始Direct3DCreate9。

  • 一旦DLL被注入,在新窗口中创建一个新的设备。 然后,从该设备获取EndScene偏移量并将其挂钩,从而导致游戏使用的设备挂钩。
  • 下行:根据我读过的一些信息,创建第二个设备可能会干扰现有设备,并且可能会出现窗口模式与全屏模式等问题。

  • 与第三种方法相同。 但是,您将执行模式扫描以获取EndScene
  • 下行:看起来并不可靠。

    我怎样才能从一个注入DLL中挂钩EndScene ,这个DLL可以在游戏运行时加载,而不必在其他系统上处理不同的d3d9.dll,并且使用可靠的方法。 例如,FRAPS如何执行它的DirectX挂钩? 该DLL不应该适用于所有游戏,只适用于通过CreateRemoteThread注入的特定进程。


    你安装一个系统钩子。 (SetWindowsHookEx)完成后,您可以加载到每个进程中。

    现在当钩子被调用时,你会看到一个加载的d3d9.dll。

    如果加载了一个,则创建一个临时D3D9对象,然后遍历vtable以获取EndScene方法的地址。

    然后你可以用你自己的方法修补EndScene调用。 (通过调用您的方法替换EndScene中的第一条指令。

    完成后,您必须修补回调,以调用原始的EndScene方法。 然后重新安装你的补丁。

    这是FRAPS的做法。 (链接)


    您可以从界面的vtable中找到函数地址。

    所以你可以做到以下几点(伪码):

    IDirect3DDevice9* pTempDev = ...;
    const int EndSceneIndex = 26 (?);
    
    typedef HRESULT (IDirect3DDevice9::* EndSceneFunc)( void );
    
    BYTE* pVtable = reinterpret_cast<void*>( pTempDev );
    EndSceneFunc = pVtable + sizeof(void*) * EndSceneIndex;
    

    EndSceneFunc现在包含一个指向函数本身的指针。 我们现在可以修补所有呼叫站点,也可以修补功能本身。

    注意这一切都取决于Windows中COM接口实现的知识。 但是,这适用于所有Windows版本(32或64,而不是同时)。


    我知道一个稍微老的问题 - 但是如果有人对C#这么做感兴趣,下面是我使用C#钩住Direct3D 9 API的例子。 这利用了EasyHook一个开放源代码的.NET程序集,它允许你'安全地'将托管代码中的钩子安装到非托管函数中。 (注意:EasyHook处理所有与DLL注入有关的问题 - 例如CREATE_SUSPENDED,ACL,32和64位等)

    我使用了与Christopher通过一个小型C ++助手dll所提到的类似的VTable方法来动态确定要挂接的IDirect3DDevice9函数的地址。 这是通过创建一个临时窗口句柄,然后在注入所需函数之前在注入的程序集中创建一个抛弃的IDirect3Device9来完成的。 这允许您的应用程序钩住已经运行的目标(更新:请注意,这完全可以在C#中实现 - 请参阅链接页面上的注释)。

    更新 :还有一个更新版本,用于连接仍然使用EasyHook和SharpDX而不是SlimDX的Direct3D 9,10和11


    我知道这个问题是旧的,但这应该适用于任何使用DirectX9的程序,您基本上创建您自己的实例,然后获取指向VTable的指针,然后将其挂钩。 你将需要绕道3.X btw:

    //Just some typedefs:
    typedef HRESULT (WINAPI* oEndScene) (LPDIRECT3DDEVICE9 D3DDevice);
    static oEndScene EndScene;
    
    //Do this in a function or whatever
    HMODULE hDLL=GetModuleHandleA("d3d9");
    LPDIRECT3D9(__stdcall*pDirect3DCreate9)(UINT) = (LPDIRECT3D9(__stdcall*)(UINT))GetProcAddress( hDLL, "Direct3DCreate9");
    
    LPDIRECT3D9 pD3D = pDirect3DCreate9(D3D_SDK_VERSION);
    
    D3DDISPLAYMODE d3ddm;
    HRESULT hRes = pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &d3ddm );
    D3DPRESENT_PARAMETERS d3dpp; 
    ZeroMemory( &d3dpp, sizeof(d3dpp));
    d3dpp.Windowed = true;
    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
    d3dpp.BackBufferFormat = d3ddm.Format;
    
    WNDCLASSEX wc = { sizeof(WNDCLASSEX),CS_CLASSDC,TempWndProc,0L,0L,GetModuleHandle(NULL),NULL,NULL,NULL,NULL,("1"),NULL};
    RegisterClassEx(&wc);
    HWND hWnd = CreateWindow(("1"),NULL,WS_OVERLAPPEDWINDOW,100,100,300,300,GetDesktopWindow(),NULL,wc.hInstance,NULL);
    
    hRes = pD3D->CreateDevice( 
        D3DADAPTER_DEFAULT,
        D3DDEVTYPE_HAL,
        hWnd,
        D3DCREATE_SOFTWARE_VERTEXPROCESSING | D3DCREATE_DISABLE_DRIVER_MANAGEMENT,
        &d3dpp, &ppReturnedDeviceInterface);
    
    pD3D->Release();
    DestroyWindow(hWnd);
    
    if(pD3D == NULL){
        //printf ("WARNING: D3D FAILED");
        return false;
    }
    pInterface = (unsigned long*)*((unsigned long*)ppReturnedDeviceInterface);
    
    
    EndScene = (oEndScene) (DWORD) pInterface[42];
    DetourTransactionBegin();
    DetourUpdateThread(GetCurrentThread());
    DetourAttach(&(PVOID&)EndScene, newEndScene);
    DetourTransactionCommit();
    

    然后你的功能:

    HRESULT WINAPI D3D9Hook::newEndScene(LPDIRECT3DDEVICE9 pDevice)
    {   
        //Do your stuff here
    
        //Call the original (if you want)
        return EndScene(pDevice);
    }
    
    链接地址: http://www.djcxy.com/p/60307.html

    上一篇: Hooking DirectX EndScene from an injected DLL

    下一篇: c#