Direct3D 9 Hook v1.1

February 1, 2008

Update: Since new DLLs were pushed out a while back, this doesn’t work any longer. The function offsets are wrong, and the hook injection method is a little too flaky to be relied upon. Feel free to use this code as a basis, but I’d recommend the use of Microsoft Detours for the hook injection. One day I’ll write a new version along these lines but until then you’re on your own.

By popular demand, I’ve updated the Direct3D 9 Hooking Sample to accommodate Windows Vista. The same binary should work on both Vista and XP. I’ve only tested it on Vista 64-bit, so it’d be nice to know if it works with Vista 32 or not. Other than this, most of the same caveats apply as last time.

Screenshot

32 Responses to “Direct3D 9 Hook v1.1”

  1. Seems like it works fine in vista 32. Thanks

  2. First of all I’d like to thank you for sharing all this cool knowledge about direct3d hooks. I want to create something similar to a ventrilo/teamspeak overlay, and as a test I’m trying to recreate the ventrilo one. The problem I need to solve is how to extract information from a running ventrilo app, which is probably similar to the stuff you did in this update (getting locations of relevant functions/data). I’m not experienced in reverse engineering strategies, so any information on how to set this up, tools needed, the steps involved would be very much appreciated.

  3. Thanks, Joey. It’s good to hear that everything’s okay with Vista.

    Bill. I have scheduled another post on run-time virtual function resolution for a few days’ time, which may be useful to you. That’s all that was needed for this update. The remainder of function resolution work is static and should be far simpler, provided you are comfortable in a debugger (if not then nothing will further your abilities better than some solid practice in OllyDbg).

    As for analysis of key data locations, this is something I don’t have much experience with. However, I can tell you that there are plenty of tools you’ll find invaluable for tracking down such data. Take a look on this page for some good recommendations.

    Greg

  4. Do you think there is a way to make this thread safe?
    I hooked this way a function called by several threads, and quickly it crashed because another thread enters the dll function exactly when the other thread is restoring the hook.
    These very frequent accesses to memory make it very unsafe. If two threads call the same function every frame, you can expect it will crash after less than one minute.

    I see there are some functions like InterlockedExchange64 which allow to write 8 bytes atomically in memory.
    Do you think it is possible with this function to make hooking/unhooking atomic?

  5. Sure it’s possible. It’ll just take a bit more work. If you need multi-threading support I recommend you try out Microsoft Detours. As far as I know, it’s the only thread-safe option for API-hooking. A good discussion on the intricacies of the matter can be found on Celceo’s Windows Insight Blog.

    Anyway, may I ask which target this applies to? I was under the impression that thread-safety was not an issue at all in this situation since Direct3D is primarily single-threaded. While certain operations (in particular, asynchronous resource loading) are encouraged, the documentation says that rendering should be kept to a single thread, lest you risk losing state and crashing the API. For this reason I figured that no mainstream applications would cause any problems with my current design. I guess that’s not the case.

  6. Thank you for the link.
    It is not a directx function, it is TimeGetTime from the multimedia library. I wanted to know the time for every frame, and instead of calling this method myself I wanted to use time from the game. (as the game calls this method at least one time per frame…)

    And it appears that a gaming controller dll creates a thread which calls this method very often too. They all call TimeGetTime 4 times per frame (!)

    What I do not like with detours: in order to call the original function, it creates a trampoline function, containing the first 5 bytes of the original function, and a jump to the remaning code. To do so, it has to decompile these 5 bytes, and translates IPs in instructions if necessary, because the 5 bytes are moved somewhere else. This is thread safe, but really heavy and ugly code.
    And it seems their small decompiler does not support 64bits instructions…but it should work with 32bits apps on 64bits systems.

    Anyway, it seems I should call the time method myself or use detours, because InterlockedExchange will not work properly if the 5 bytes are across a 64bits boundary.

  7. Okay, well do what you have to. But before you commit yourself to anything, consider IAT hooking if you haven’t already. TimeGetTime is a static global function and you are only interested in hooking calls to it from a single known module. Also, the IAT is guaranteed to be DWORD-aligned in memory and an IAT entry is writeable within a single instruction. For these reasons, assuming that MSVCRT is linked dynamically, IAT-hooking is a good, thread-safe option and its implementation should be straightforward.

  8. Hi, IAT looks interesting I will check it.
    I found source code that may interest you. Simple and thread safe.
    It creates hook with a jmp as you do. And it re-builds the beginning of the original function somewhere else (with a jmp to remaining code). Like detour but a lot simplier.

    To rebuild the original function, it only takes care to move whole instructions (using tiny disassembly engine ADE32), it does not even try to update moved instructions according to their new address. And surprisingly it works for DX functions, and TimeGetTime…

  9. http://forum.gamedeception.net/showthread.php?t=10649

  10. Hi Greg,
    This is a newbie question but how can you have a pointer to the caller as 1st parameter in the hook functions? Does it have to do with the calling convention stdcall and the offset you specify?

    Greg and Juls, I don’t know if you’re aware of it, but there’s a library called Mhook that supports x86/x64 for XP and Vista (http://codefromthe70s.org/mhook2.asp). It seems like a lite version of Detours. No optimization for trampoline method memory allocations but meh, that’s no big deal in my opinion. I will check it out. It has a disassembler too. I will check DetourXS too.

    Thank you both,
    Alexandre

  11. Alexandre, the reason that the hook function declarations have an extra IDirect3DDevice9/IDirect3DSwapChain9 pointer as their first parameter is a consequence of the thiscall calling convention for virtual functions. Class member functions are compiled statically just like any other function, and invocation by different objects results in the same code being executed. The function understands which object to work on because the this pointer is passed implicitly. For basic member functions, this is passed in ECX and the remainder of the arguments on the stack as in stdcall, but for some reason VC++ treats virtual functions differently. In this case (as with variadic functions) the this pointer is pushed onto the stack before the first argument, which is why the functions in my code have the extra argument and need to explicitly specify __stdcall.

    As for Mhook, no I wasn’t aware of it. I could have sworn that there were no decent libraries for this type of thing when I first created the project, but that’s certainly not the case any longer :P .

  12. Thank you for the link…I googled everything possible about API hooking, detours alternative…never seen it before. Looks very promising, light and thread safe like detourxs, 64 bits support like professional detour!

  13. [...] Update: See the new version. [...]

  14. /*
    char* address_d3d9 = reinterpret_cast (GetModuleHandleA(path_d3d9_dll));
    */

    char* address_d3d9 = reinterpret_cast (GetModuleHandleA(“d3d9.dll”));

  15. Mikityak, that’s half way to a solution that fits all versions of Windows NT (including WoW64), but it’s liable to cause a crash if the versions don’t match up with the hard-coded addresses.

    The full solution would be to dynamically resolve the address from whichever version of the DLL happens to be loaded, but this requires a working instance of an IDirect3DDevice9 object to be available. In turn, this means either hooking the program from the beginning, or creating a window of your own and attaching a new device to it, which is a little clunky.

    Once I get a moment (something I haven’t seen the likes of for a long time) I’ll look into this and hopefully put all these problems to bed.

  16. Is there any chance of some explanation of how to make use of this, or a sample application, etc. I’ve never really played with DLLs before, I have a vague grounding in C++, and hooking into directx is exactly what I need to do. I’ve been hunting for something like this for ages, and now I’ve found it I can’t make use of it!

    Anyone that’s made a Visual Studio project that makes use of this feel like they can share?

    Thanks!

  17. InjHdc – программа выводящая время в окне игры.

    [Ed - I'm afraid I don't speak russian, but this link seems to be appropriate to the subject matter so we'll keep it.]

    http://www.injhdc.fidep.ru

  18. Hi Greg,

    Quick question I hope:

    In order to establish a hook into a Direct3D application, to hook it to use your example “D3DHOOK.DLL” to draw some text over the top of the image, what should I be passing as the “existing_module_name” and “hook_function_name” parameters in DLLInjection?

    Your example does this:

    // Hook a DLL function (User32!SetWindowTextW)
    HDLLHOOK swtw_hook = injection.InstallDLLHook(“C:/Windows/System32/User32.dll”, “SetWindowTextW”, “SetWindowTextHookW”);

    How should the above be modified to hook the Present function (and any other necessary functions) to the modified ones in the D3DHOOK.DLL?

    I tried:

    HDLLHOOK swtw_hook = injection.InstallDLLHook(“d3d9.dll”, “IDirect3DDevice9::Present”, “DevicePresentHook”);

    But this does not work as the hook fails in the call to GetRemoteProcAddress, not finding “IDirect3DDevice9::Present”.

    All I’m trying to do at the moment is hook into the Vertices DirectX demo (class name “D3D Tutorial”).

    Any help gratefully received. Is there a demo app showing how to hook into such a sample application?

    Many thanks, Mervin.

  19. Hi Mervin.

    Unfortunately, things aren’t so simple for the Direct3D hooks since the functions needing to be hooked aren’t static exports of d3d9.dll, but rather virtual functions of a class interface it exposes. For this reason, no set of parameters will do the job using that overload of InstallDLLHook. Rather, we need to resolve the address of the virtual function at run-time and install the hook using the resulting address directly. Hopefully, the motivation for this post is now obvious.

  20. thanks…

  21. Hi Greg,

    I am a newbie and interested in take screen of another D3D appliation. Your sample looks very good, but I don not know how can I inject to an application to take a screenshot. Can you explain this or attach a small source?

    Regards,

    Valer

  22. Oh, I am too lazy to read. Sry, found injection framework. Very nice job! Thanks a lot…

  23. Hi Greg,

    I’ve got a small problem, with the handling of this dll.
    I’ve loaded the dll successfuly to the targeted app.
    It displays the text correct if I modify the dllmain to call the Initialise func, but i wannt to call it with a CreateRemoteThread func

    I’ve tried these:
    LPTHREAD_START_ROUTINE DllInitialise = reinterpret_cast (GetProcAddress(LoadedDll,”Initialise”));

    – LoadedDll is the HMODULE returned from the GetExitCodeThread (the thread that loads the dll) (its not NULL),than the GetProcAddr fail and the return value will be NULL
    – LoadedDll is returned from a LoadLibrary call (from the injector app), then it returns a value but, when i try to call CreateRemoteThread with this value, than the targeted app crashes.

    I think the solution is really easy, just I’ve left out something …

    I would really apreceate some advice how to do this properly

    Thanks,

    Ferdinánd

  24. Ferdinand. There are many possible causes for this, but the first thing I’d guess is that the address you’ve resolved for Initialise isn’t valid in the target process. Understand that GetProcAddress returns an address in the address-space of the calling process, and that this isn’t necessarily valid in another process using the same DLL.

    The solution to this involves a small amount of offset acrobatics but is fairly straightforward. Nevertheless, to avoid reinventing this wheel I recommend you take a look at my injection framework. This will ease the tasks of injecting the DLL and invoking the remote procedure. If you find the need to hook any other functions, there’s also support for this :)

    One other thing. The reason this code hasn’t been written to call Initialise from DllMain is that it’s not a safe thing to do. Typically, it’s harmless but in the case where the target process doesn’t have d3d9.dll already loaded, it will attempt to load the DLL from a rather delicate state and may deadlock the process. For this reason I recommend you avoid such practice.

  25. this code in direct3d8 change? How?

  26. Aluizio, it should be pretty straightforward :)
    The first thing I’d recommend is changing all the Direct3D9* interfaces to their corresponding Direct3D8 ones then trying and build it, fixing one problem at a time (if any occur – I don’t remember Direct3D 8 so well).

    I can’t make any promises but I’d imagine that once it compiles, provided you haven’t done anything stupid, it would work fine.

  27. Ok, thx.

  28. Look this
    .\d3dhook.cpp(131) : error C2951: template declarations are only permitted at global, namespace, or class scope
    Build log was saved at “file://c:\Documents and Settings\Alice\Meus documentos\proxydll_8\Release\BuildLog.htm”
    proxydll – 1 error(s), 0 warning(s)
    ========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

  29. Greg, I’ve used this to hook the direct3d. But I get exit_code -1073741819… Dunno what I’m doing wrong! :( Can you help me?

    extern “C” __declspec(dllexport)int InstalaHook(const char *className, const char *windowName);
    extern “C” __declspec(dllexport)void RemoveHook();

    DLLInjection injection(“D:\\Cleandod\\trunk\\CleanDoD\\CleanDoD\\bin\\Release\\teste_dx_hook.dll”);

    int InstalaHook(const char *className, const char *windowName)
    {
    DWORD process_id = injection.GetProcessIDFromWindow(className, windowName);
    if(process_id == 0)
    return -7;
    // Inject the DLL
    HMODULE remote_module = injection.InjectDLL(process_id);
    if(remote_module == NULL)
    return -8;
    DWORD exit_code = 0;
    char retorno[65];

    if(!injection.CallThreadProc(“Initialise”, NULL, 10000, exit_code))
    exit_code = -9;///(LPCWSTR)”Falhou”;
    int ret = static_cast (exit_code);
    return ret;
    }

    void RemoveHook()
    {
    injection.RemoveAllHooks();
    }

  30. Lucas,

    That code ‘-1073741819′ is 0xC0000005, an access violation. I assume you’re getting it after remotely invoking Initialise (if not then there may be an easy fix). One way or another I recommend that you use Microsoft Detours for the injection, as my DllInjection framework is starting to show its age.

    However, I doubt this will fix your problem. The hooks supplied here were targeted specifically at the DirectX version out at the time of writing, but that was a while ago. It’s very likely that the hard-coded address have changed (what OS are you testing on?), and not impossible that an API change has been made that would render the technique invalid. Did you by any chance comment out the call to VerifyAddresses (to prevent it failing)? If so then that’s almost guaranteed to corrupt something important.

    Beyond this I’m afraid I can’t recommend anything better than to step through the Initialise method remotely in OllyDbg or WinDbg to make sure it’s behaving correctly. Either that or get hold of a more up-to-date hook implementation :P .

  31. Thanks for replying that fast…

    I’m using vista 32bits. Yes, that happen when I try to remote call Initialize. Anyway, I’m kind of noob in C++ and Dll Injection. I just want to hook the present function and capture what is in the buffer.

    I’m gonna research detours. Thanks for you help!

  32. Very nice lib!

    But I have problems in writing a main application which uses the library :(

    Maybe somebody can post his working code.

    That would be very nice!

Leave a Reply