从注入DLL挂钩的DirectX EndScene从注入DLL挂钩的DirectX EndScene

2019-05-13 02:09发布

我想绕道而行EndScene从任意的DirectX 9应用程序创建一个小的叠加。 举个例子,你可以采取FRAPS,这是在游戏启动时显示的帧计数器覆盖。

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

  1. 创建一个新的d3d9.dll,然后将其复制到游戏的路径。 由于当前文件夹首先搜索,才去SYSTEM32等等,我修改DLL被加载时,我执行额外的代码。

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

    • 与第一方法,但在直接SYSTEM32更换DLL。

    缺点:不能添加游戏特定的代码。 你不能排除您不希望加载您的DLL的应用程序。

    • 获得使用工具,如IDA Pro的4.9免费的EndScene直接从DLL偏移。 由于DLL被加载的是,你可以增加这个偏移量到DLL起始地址,当它被映射到游戏中,获得实际的偏移,然后把它捞起来。

    下行:偏移量是不是每个系统上的相同。

    • 钩住Direct3DCreate9得到D3D9,然后钩D3D9-> CreateDevice的获取设备指针,然后通过虚拟表钩住设备- > EndScene。

    下行:该DLL不能注入,当进程已经运行。 你必须与启动过程CREATE_SUSPENDED标志挂钩初始Direct3DCreate9。

    • 在新窗口中创建一个新的设备,只要该DLL注入获取。 然后,获得EndScene从此设备偏移和钩住,导致针对其使用的游戏设备的钩。

    缺点:由于一些信息我已阅读,创建第二装置可以与现有的设备干涉,并且它可以与错误窗口与全屏模式等

    • 同样作为第三方法。 但是,你会做一个花样扫描得到EndScene

    缺点:不看可靠的。

我如何能勾EndScene从注入DLL,它可以当游戏已经运行加载,而不必在其他系统上处理不同的d3d9.dll的,并与可靠的方法? 如何FRAPS例如执行它的DirectX挂钩? 该DLL不应该适用于所有的游戏,只是在那里我通过它注入特定的进程CreateRemoteThread

Answer 1:

您安装一个系统全局钩子。 (SetWindowsHookEx函数)完成这一操作,你要加载到每个进程。

现在,当钩子被调用时,你找一个装d3d9.dll。

如果一个人被加载,你创建一个临时D3D9对象,走在虚函数表,以获得EndScene方法的地址。

然后你就可以修补EndScene电话,用自己的方法。 (由你的方法调用替换EndScene的第一条指令。

当你完成,你需要修补的回电,打电话给原来的EndScene方法。 然后重新安装补丁。

这是FRAPS做它的方式。 ( 链接 )


你可以找到一个接口的虚函数表函数地址。

所以,你可以做以下(伪代码):

IDirect3DDevice9* pTempDev = ...;
const int EndSceneIndex = 26 (?);

typedef HRESULT (IDirect3DDevice9::* EndSceneFunc)( void );

BYTE* pVtable = reinterpret_cast<void*>( pTempDev );
EndSceneFunc = pVtable + sizeof(void*) * EndSceneIndex;

EndSceneFunc确实现在包含一个指向函数本身。 现在,我们可以修补所有调用点,或者我们可以修补功能本身。

要注意的是这一切都依赖于COM接口的Windows中执行的知识。 但是,这适用于所有Windows版本(32或64,而不是两个在同一时间)。



Answer 2:

稍微老问题,我知道-但如果有人有兴趣与C#这样做,这是我的例子挂钩使用C#Direct3D的9 API 。 这利用EasyHook一个开源.NET程序集,使您可以从托管代码“安全”安装挂钩非托管功能。 (注:EasyHook需要的周边DLL注入的所有问题护理 - 例如CREATE_SUSPENDED,ACL的,32比64位等)

我使用了类似的VTable方法,因为通过一个小的C ++助手DLL由Christopher提到动态地确定的的IDirect3DDevice9函数的地址钩。 这是通过创建一个临时的窗口句柄,并创建注入组件内的扔掉的IDirect3Device9然后挂接所需功能之前完成。 这使您的应用程序挂钩一个已经运行的目标(更新:请注意,这是有可能完全在C#也 - 查看链接页面的评论)。

更新 :有也是一个更新的版本挂钩的Direct3D 9,第10和11依然采用EasyHook与SharpDX代替SlimDX



Answer 3:

我知道这个问题是旧的,但应该使用DirectX9的,你基本上是创建自己的实例,然后获取指向虚函数表,那么你只要把它挂任何程序中工作。 您将需要弯路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);
}


文章来源: Hooking DirectX EndScene from an injected DLL