为什么直接获取导出函数的指针 return 同一个模块中的地址?

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

我正在使用经典设置来挂接 d3d9 函数:注入 DLL,然后获取目标函数地址并使用 JMP 指令修补它们。

但是我 运行 遇到了一些我不太明白的事情。考虑我将注入目标进程的 DLL 中的以下片段:

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);

其中D3D9Create_Original和D3D9Create_Original2是函数指针类型:

IDirect3D9*(__stdcall *)(UINT)

基本上我进行了通常的 GetModuleHandle 调用并获取了该文件的名称。然后我得到函数指针并使用 GetModuleHandleExGET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS 来基本上确定该地址来自哪个 DLL。

所以ModuleBasedOnGetAPI_path是d3d9.dll文件的实际路径。 虽然 ModuleBasedOnAddress_path 似乎是从中获取此代码段的我的 DLL 的路径。

那是为什么呢?为什么 Direct3DCreate9 函数同时存在于我的 DLL 和 d3d9.dll 中?这与我在构建 DLL 时链接 d3d9.lib 有什么关系吗?

您的构建配置是什么(即调试或发布)?看起来编译器的优化在这里也很重要。

对于发布版本,我无法重现该问题 - 两个地址相同。

对于调试版本,您的假设是正确的。这是因为当你在代码中直接引用Direct3DCreate9时,你是在调用自己模块中的存根代码,它会进一步从Import Address Table中获取真正的Direct3DCreate9地址。

为了更好地说明这个概念:

请注意Visual Studio已经告诉你这两个地址来自不同的模块。

我们来看看地址0x008f1249:

不过是一个jmp。进一步看0x08FCFAD

再跳一次。最后 0x0913220:

请记住 D3D9Create_Original 的值 - 这是与 D3D9Create_Original 相同的真实地址。