Ring3 Circus
December 5th, 2007, 16:45
The theme of the moment is DLL hooking, and so I thought I’d present an applied example. I already explained how Fraps works ("http://www.ring3circus.com/gameprogramming/case-study-fraps/"), and since I’ve recently been roped into writing a similar tool for a stranger, I thought I’d share the wealth. There isn’t much new material here, but people like examples with source code, so you can download the DLL source (C++) here ("http://www.ring3circus.com/source/direct3d_9_hook.cpp").
http://www.ring3circus.com/wp-content/uploads/bioshock_hooked.thumbnail.png
If you don’t know how to inject this DLL into a foreign process, then you’ll need to read my previous post ("http://www.ring3circus.com/rce/dll-injection-via-createremotethread/") or wait for the injection framework I’m working on. But once it’s injected call the Initialise method, via CreateRemoteThread or otherwise, to install the hooks. It works with any program that uses IDirect3DDevice9::Present (or IDirect3DSwapChain::Present) to render, which is probably all of the DirectX 9 games. Similarly, invoke Release to remove the hooks. The source is fairly self-explanatory, with a few exceptions.
http://www.ring3circus.com/gameprogramming/drawing-on-another-direct3d-programs-viewport/
http://www.ring3circus.com/wp-content/uploads/bioshock_hooked.thumbnail.png
If you don’t know how to inject this DLL into a foreign process, then you’ll need to read my previous post ("http://www.ring3circus.com/rce/dll-injection-via-createremotethread/") or wait for the injection framework I’m working on. But once it’s injected call the Initialise method, via CreateRemoteThread or otherwise, to install the hooks. It works with any program that uses IDirect3DDevice9::Present (or IDirect3DSwapChain::Present) to render, which is probably all of the DirectX 9 games. Similarly, invoke Release to remove the hooks. The source is fairly self-explanatory, with a few exceptions.
It’s not safe for 64-bit consumption, though this should be obvious.
While there’s no reason it can’t be made to work with Unicode, I’ve written everything in ASCII, for simplicity.
By default, the DLL will increase its own reference count to prevent it being unloaded prior to termination of the host process. This is because there is a small risk of the DLL being unloaded by one thread, while a hooked function in another returns to the now dead memory. I figured that it’s best to waste a little bit of everybody’s memory than to crash unnecessarily.
The d3d9.dll function addresses (and prologues) are hard-coded, or at least their offsets are. While this may look very unprofessional and rather risky, I can assure you that it’s quite safe. The alternative would be to hack up some virtual-function tables and that’s a whole other story for a whole other post.
You may notice that the compiled DLL is dependent upon D3DX. This isn’t necessary for the hook itself, but I used ID3DXFont in my example for demonstrative purposes. The only reason I mention this is that there is no way to guarantee the existence of any D3DX DLLs on a DirectX 9 machine, and distributing them yourself is in violation of the DirectX Runtime EULA. So if you happen to need to distribute this code, you’ll either need to carry the huge runtime installer around, or avoid using D3DX altogether.
http://www.ring3circus.com/gameprogramming/drawing-on-another-direct3d-programs-viewport/