C 获取实际函数LoadLibraryExW的地址而不是存根LoadLibraryExWStub

C 获取实际函数LoadLibraryExW的地址而不是存根LoadLibraryExWStub,c,winapi,C,Winapi,我试图获取DLLLoadLibraryExW中函数的地址。但是,当我尝试获取此函数的地址时,实际上我获取了一个LoadLibraryExWStub的地址 #include <stdio.h> #include <Windows.h> intptr_t getFuncAddr(const char* func, const char* dll) { return (intptr_t)GetProcAddress( GetModuleHandle(d

我试图获取DLL
LoadLibraryExW
中函数的地址。但是,当我尝试获取此函数的地址时,实际上我获取了一个
LoadLibraryExWStub
的地址

#include <stdio.h>
#include <Windows.h>

intptr_t getFuncAddr(const char* func, const char* dll)
{
    return (intptr_t)GetProcAddress(
        GetModuleHandle(dll),
        func);
}

int main()
{
    // Actual address: 000007FEFD28B2B0 Stub address I get instead: 0x00000000771d5680
    intptr_t loadLibExWAddr = getFuncAddr("LoadLibraryExW", "kernel32.dll");

    printf("%x\n", (int)loadLibExWAddr);
}
kernel32.dll
的程序集中,我还看到另一个名为
LoadLibraryExW
的函数,其定义如下:

LoadLibraryExW:
00000000771D5674 FF 25 CE 80 08 00    jmp         qword ptr [__imp_LoadLibraryExW (07725D748h)]  
00000000771D567A 90                   nop  
00000000771D567B 90                   nop  
00000000771D567C 90                   nop  
00000000771D567D 90                   nop  
00000000771D567E 90                   nop  
00000000771D567F 90                   nop  
这让我更加困惑。它们如何可以是两个
LoadLibraryExW
函数


因此,重申一下,我想获取实际执行DLL加载的核心
LoadLibraryExW
函数的函数地址;并不是所有其他的东西看起来都是这样的。

一节历史课在解释这一点时很有帮助

Windows95只有正常的导出功能,NT3&4可能有一些。底层Win32函数存在于kernel32、user32和gdi32中,仅此而已。NTDLL应该是完全没有文档记录和禁止的

在Vista时代,微软进行了一项名为的实验,该实验改变了某些组件的分层结构。在Windows 7中,一些函数实现大部分或全部迁移到新的kernelbase.dll

Win32 ABI和数百万应用程序当然依赖于内核32中的
LoadLibraryExW
,因此仍然存在一个简单的存根函数函数的名称仍然是
LoadLibraryExW
,但符号的名称中通常有一个存根后缀
,因为函数在跳转到新的主位置之前几乎不工作。Windows7还添加了“功能”,该功能通过不将函数绑定到特定的.dll,使这些类型的更改在将来变得更容易

挂钩图书馆不应该对此感到惊讶。忘记符号,关注
GetProcAddress
及其返回的地址。从ABI的角度来看,函数以
jmp
开头是合法的,任何类型的蹦床/挂钩库都必须能够处理它

如果您只关心符合文档化API的应用程序,那么您最好使用IAT挂钩。如果您想钩住“一切”,那么
LoadLibrary*
的深度永远不够

注意:加载程序的核心实际上在NTDLL中,
LoadLibrary*
在基于NT的系统上从不执行实际加载。如果您想得到有关加载模块的通知,真正的安全软件可能应该在内核中捕获映像部分


注意:
jmpqwordptr[\uu imp\uu…]
通常是对另一个.dll中的函数的调用。这是有道理的,因为转储文件中的
000007FEFD28B2B0
很可能不在内核32中。

在解释这一点时,上一节历史课很有帮助

Windows95只有正常的导出功能,NT3&4可能有一些。底层Win32函数存在于kernel32、user32和gdi32中,仅此而已。NTDLL应该是完全没有文档记录和禁止的

在Vista时代,微软进行了一项名为的实验,该实验改变了某些组件的分层结构。在Windows 7中,一些函数实现大部分或全部迁移到新的kernelbase.dll

Win32 ABI和数百万应用程序当然依赖于内核32中的
LoadLibraryExW
,因此仍然存在一个简单的存根函数函数的名称仍然是
LoadLibraryExW
,但符号的名称中通常有一个存根后缀
,因为函数在跳转到新的主位置之前几乎不工作。Windows7还添加了“功能”,该功能通过不将函数绑定到特定的.dll,使这些类型的更改在将来变得更容易

挂钩图书馆不应该对此感到惊讶。忘记符号,关注
GetProcAddress
及其返回的地址。从ABI的角度来看,函数以
jmp
开头是合法的,任何类型的蹦床/挂钩库都必须能够处理它

如果您只关心符合文档化API的应用程序,那么您最好使用IAT挂钩。如果您想钩住“一切”,那么
LoadLibrary*
的深度永远不够

注意:加载程序的核心实际上在NTDLL中,
LoadLibrary*
在基于NT的系统上从不执行实际加载。如果您想得到有关加载模块的通知,真正的安全软件可能应该在内核中捕获映像部分


注意:
jmpqwordptr[\uu imp\uu…]
通常是对另一个.dll中的函数的调用。这是有道理的,因为转储中的
000007FEFD28B2B0
很可能不在内核32中。

不可能。您得到的是DLL导出的内容,而不是您想要的内容。@MichaelChourdakis Hm,这也许可以解释“重复函数”的问题,但我仍然不知道为什么解析
LoadLibraryExW
的地址会给我
LoadLibraryExWStub
的地址。此外,我如何获得
LoadLibraryExW
的“实际”地址。如前所述,您所得到的只是DLL名称->符号的映射。该符号可以是任何与可能具有相同名称的实际函数无关的东西。你到底需要它做什么。热修补?@OverloadedOperator-热修补代码必须分析指令并具有最小的反汇编程序。所以这里没有问题-如果热补丁代码视图跳转(短)它-转到jmp@OverloadedOpeator-你的“实际”地址是什么(是什么?)。你只需要做补丁。全部的别忘了其他人都和你有相同的地址。不可能。您得到的是DLL导出的内容,而不是您想要的内容。@MichaelChourdakis Hm,这也许可以解释“重复函数”的问题,但我仍然不知道为什么解析
LoadLibraryExW
的地址会给我
LoadLibr的地址
LoadLibraryExW:
00000000771D5674 FF 25 CE 80 08 00    jmp         qword ptr [__imp_LoadLibraryExW (07725D748h)]  
00000000771D567A 90                   nop  
00000000771D567B 90                   nop  
00000000771D567C 90                   nop  
00000000771D567D 90                   nop  
00000000771D567E 90                   nop  
00000000771D567F 90                   nop