从注入的DLL钩住DirectX EndScene
我想绕过任意DirectX 9应用程序的EndScene
来创建一个小覆盖。 举个例子,你可以采用FRAPS的帧计数器覆盖,当游戏被激活时显示。
我知道下面的方法来做到这一点:
创建一个新的d3d9.dll,然后将其复制到游戏路径。 由于当前文件夹是首先搜索,在去system32等之前,我修改的DLL被加载,执行我的附加代码。
下行:在开始游戏之前,你必须把它放在那里。
下行:你不能添加游戏特定的代码。 您不能排除不希望加载DLL的应用程序。
下行:每个系统的偏移量都不相同。
下行:当进程已经运行时,DLL不能被注入。 您必须使用CREATE_SUSPENDED
标志启动进程以挂钩初始Direct3DCreate9。
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#