Search code examples
c++dlldirect3ddll-injection

Why does getting an exported function's pointer directly return an address in the same module?


I'm using a classic setup for hooking d3d9 functions: Injecting a DLL then getting target function addresses and patching them with a JMP instruction.

However I have run into something I don't quite understand. Consider the following snippet from the DLL I'll inject into the target process:

HMODULE ModuleBasedOnGetAPI = NULL;
HMODULE ModuleBasedOnAddress = NULL;

ModuleBasedOnGetAPI = GetModuleHandleA("d3d9.dll");
D3D9Create_Original = (t_D3D9Create)GetProcAddress(ModuleBasedOnGetAPI,
                      "Direct3DCreate9");

D3D9Create_Original2 = &Direct3DCreate9;
GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
                   GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
                   (LPCSTR)D3D9Create_Original2, &ModuleBasedOnAddress);

char ModuleBasedOnGetAPI_path[_MAX_PATH];
GetModuleFileNameA(ModuleBasedOnGetAPI, ModuleBasedOnGetAPI_path, _MAX_PATH);

char ModuleBasedOnAddress_path[_MAX_PATH];
GetModuleFileNameA(ModuleBasedOnAddress, ModuleBasedOnAddress_path,
                  _MAX_PATH);

Where D3D9Create_Original and D3D9Create_Original2 are function pointers of type:

IDirect3D9*(__stdcall *)(UINT)

Basically I did the usual GetModuleHandle call and got that file's name. And then I got the function pointer and used GetModuleHandleEx with the GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS to basically determine which DLL that address comes from.

So ModuleBasedOnGetAPI_path is the actual path of the d3d9.dll file. While ModuleBasedOnAddress_path seems to be the path of my DLL from which this snippet was taken.

So why is that? why does the Direct3DCreate9 function reside both in my DLL and in d3d9.dll? Does it have something todo with the fact that I linked d3d9.lib when building my DLL?


Solution

  • What's your build configuration (i.e. Debug or Release)? Looks like compiler's optimization also matters here.

    For Release build, I cannot reproduce the issue - the two addresses are the same.

    For Debug build, your assumption is correct. It is because when you reference Direct3DCreate9 directly in your code, you are the calling the stub code in your own module, which will further get the real Direct3DCreate9 address from the Import Address Table.

    To better illustrate the concept:

    enter image description here

    Please pay attention that Visual Studio already tells you that the two addresses are from different modules.

    Lets take a look at the address 0x008f1249:

    enter image description here

    It's no more than a jmp. Take a look at 0x08FCFAD further:

    enter image description here

    Another jump. And finally 0x0913220:

    enter image description here

    Please recall the value of D3D9Create_Original - here is the real address which is the same with D3D9Create_Original.