我想绕道而行EndScene
从任意的DirectX 9应用程序创建一个小的叠加。 举个例子,你可以采取FRAPS,这是在游戏启动时显示的帧计数器覆盖。
我知道下面的方法来做到这一点:
创建一个新的d3d9.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
。
您安装一个系统全局钩子。 (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,而不是两个在同一时间)。
稍微老问题,我知道-但如果有人有兴趣与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
我知道这个问题是旧的,但应该使用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);
}