LoadLibraryExA 函数 (libloaderapi.h)
将指定的模块加载到调用进程的地址空间中。 指定的模块可能会导致加载其他模块。
语法
HMODULE LoadLibraryExA(
[in] LPCSTR lpLibFileName,
HANDLE hFile,
[in] DWORD dwFlags
);
参数
[in] lpLibFileName
一个字符串,指定要加载的模块的文件名。 此名称与存储在库模块本身中的名称无关,如模块定义 (.def) 文件中的 LIBRARY 关键字所指定。
该模块可以是库模块(.dll 文件)或可执行模块(.exe 文件)。 如果指定的模块是可执行模块,则不会加载静态导入;而是加载模块,就像指定了 DONT_RESOLVE_DLL_REFERENCES 一样。 有关详细信息,请参阅 dwFlags 参数。
如果字符串指定了没有路径的模块名称,并且省略文件扩展名,该函数会将默认库扩展名“.DLL”追加到模块名称。 若要防止函数将“.DLL”追加到模块名称,请在模块名称字符串中包含尾随点字符(.)。
如果字符串指定完全限定的路径,则函数仅搜索该模块的路径。 指定路径时,请务必使用反斜杠(\),而不是正斜杠(/)。 有关路径的详细信息,请参阅 命名文件、路径和命名空间。
如果字符串指定了没有路径的模块名称,并且多个加载的模块具有相同的基本名称和扩展,该函数将返回第一次加载的模块的句柄。
如果字符串指定了没有路径的模块名称,并且尚未加载同名的模块,或者如果字符串指定了具有相对路径的模块名称,则函数将搜索指定的模块。 如果加载指定的模块会导致系统加载其他关联模块(即模块具有依赖项),该函数还会搜索模块。 搜索的目录及其搜索顺序取决于指定的路径和 dwFlags 参数。 有关详细信息,请参阅“备注”。
如果函数找不到模块或其依赖项之一,该函数将失败。
hFile
此参数保留供将来使用。 它必须 NULL。
[in] dwFlags
加载模块时要执行的操作。 如果未指定任何标志,则此函数的行为与 LoadLibrary 函数的行为相同。 此参数可以是下列值之一。
价值 | 意义 |
---|---|
|
如果使用此值,并且可执行模块是 DLL,则系统不会调用 DllMain 来处理进程和线程初始化和终止。 此外,系统不会加载由指定模块引用的其他可执行模块。
注意 不要使用此值;它仅用于向后兼容性。 如果计划仅访问 DLL 中的数据或资源,请使用 LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE 或 LOAD_LIBRARY_AS_IMAGE_RESOURCE 或两者兼有。 否则,请使用 LoadLibrary 函数将库加载为 DLL 或可执行模块。
|
|
如果使用此值,则系统不会检查 appLocker 规则 Windows Server 2008 R2 和 Windows 7:在安装了KB2532445的系统上 ,调用方必须以“LocalSystem”或“TrustedInstaller”身份运行;否则,系统将忽略此标志。 有关详细信息,请参阅 https://support.microsoft.com/kb/2532445帮助和支持知识库中的“通过在运行 Windows 7 或 Windows Server 2008 R2 的计算机上使用 Office 宏来规避 AppLocker 规则”。 Windows Server 2008、Windows Vista、Windows Server 2003 和 Windows XP:AppLocker 在 Windows 7 和 Windows Server 2008 R2 中引入。 |
|
如果使用此值,系统会将文件映射到调用进程的虚拟地址空间,就好像它是数据文件一样。 不执行任何操作来执行或准备执行映射的文件。 因此,不能使用此 DLL 调用 GetModuleFileName、GetModuleHandle 或 GetProcAddress 等函数。 使用此值会导致写入只读内存以引发访问冲突。 如果要仅加载 DLL 以从其中提取消息或资源,请使用此标志。
此值可与 LOAD_LIBRARY_AS_IMAGE_RESOURCE一起使用。 有关详细信息,请参阅“备注”。 |
|
与 LOAD_LIBRARY_AS_DATAFILE类似,不同之处在于 DLL 文件是使用调用进程的独占写入访问权限打开的。 其他进程在使用时无法打开 DLL 文件进行写入访问。 但是,DLL 仍可由其他进程打开。
此值可与 LOAD_LIBRARY_AS_IMAGE_RESOURCE一起使用。 有关详细信息,请参阅“备注”。 Windows Server 2003 和 Windows XP:在 Windows Vista 之前不支持此值。 |
|
如果使用此值,系统将文件映射到进程的虚拟地址空间作为图像文件。
但是,加载程序不会加载静态导入或执行其他通常的初始化步骤。 如果要仅加载 DLL 以从其中提取消息或资源,请使用此标志。
除非应用程序依赖于具有图像内存中布局的文件,否则此值应与 LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE 或 LOAD_LIBRARY_AS_DATAFILE一起使用。 有关详细信息,请参阅“备注”部分。 Windows Server 2003 和 Windows XP:在 Windows Vista 之前不支持此值。 |
|
如果使用此值,则会搜索应用程序的安装目录来查找 DLL 及其依赖项。 不搜索标准搜索路径中的目录。 此值不能与 LOAD_WITH_ALTERED_SEARCH_PATH结合使用。
Windows 7、Windows Server 2008 R2、Windows Vista 和 Windows Server 2008:此值需要安装 KB2533623。 Windows Server 2003 和 Windows XP:不支持 此值。 |
|
此值是 LOAD_LIBRARY_SEARCH_APPLICATION_DIR、LOAD_LIBRARY_SEARCH_SYSTEM32和 LOAD_LIBRARY_SEARCH_USER_DIRS的组合。 不搜索标准搜索路径中的目录。 此值不能与 LOAD_WITH_ALTERED_SEARCH_PATH结合使用。
此值表示应用程序在其 DLL 搜索路径中应包含的建议最大目录数。 Windows 7、Windows Server 2008 R2、Windows Vista 和 Windows Server 2008:此值需要安装 KB2533623。 Windows Server 2003 和 Windows XP:不支持 此值。 |
|
如果使用此值,则包含 DLL 的目录会暂时添加到搜索 DLL 依赖项的目录列表的开头。 不搜索标准搜索路径中的目录。
lpFileName 参数必须指定完全限定的路径。 此值不能与 LOAD_WITH_ALTERED_SEARCH_PATH结合使用。 例如,如果 Lib2.dll 只是 c:\Dir1 中 C:\Dir1\Lib1.dll, loading Lib1.dll with this value causes the system to search for Lib2.dll 的依赖项。 若要在 C:\Dir1 中搜索 Lib2.dll 以及 DLL 搜索路径中的所有目录,请结合使用此值与 LOAD_LIBRARY_SEARCH_DEFAULT_DIRS。 Windows 7、Windows Server 2008 R2、Windows Vista 和 Windows Server 2008:此值需要安装 KB2533623。 Windows Server 2003 和 Windows XP:不支持 此值。 |
|
如果使用此值,%windows%\system32 搜索 DLL 及其依赖项。
不搜索标准搜索路径中的目录。 此值不能与 LOAD_WITH_ALTERED_SEARCH_PATH结合使用。
Windows 7、Windows Server 2008 R2、Windows Vista 和 Windows Server 2008:此值需要安装 KB2533623。 Windows Server 2003 和 Windows XP:不支持 此值。 |
|
如果使用此值,则使用 AddDllDirectory 添加的目录或 SetDllDirectory 函数将搜索 DLL 及其依赖项。 如果已添加多个目录,则未指定搜索目录的顺序。 不搜索标准搜索路径中的目录。 此值不能与 LOAD_WITH_ALTERED_SEARCH_PATH结合使用。
Windows 7、Windows Server 2008 R2、Windows Vista 和 Windows Server 2008:此值需要安装 KB2533623。 Windows Server 2003 和 Windows XP:不支持 此值。 |
|
如果使用此值并 lpFileName 指定绝对路径,则系统会使用“备注”部分中讨论的备用文件搜索策略来查找指定模块导致加载的关联可执行模块。 如果使用此值,lpFileName 指定相对路径,则行为是未定义的。
如果未使用此值,或者如果 lpFileName 未指定路径,则系统会使用“备注”部分中讨论的标准搜索策略来查找指定模块导致加载的关联可执行模块。 此值不能与任何 LOAD_LIBRARY_SEARCH 标志合并。 |
|
指定在加载时必须检查二进制图像的数字签名。
此值需要 Windows 8.1、Windows 10 或更高版本。 |
|
如果使用此值,则仅当 DLL 位于安全加载列表中的目录下时,才允许从当前目录加载 DLL 执行。 |
返回值
如果函数成功,则返回值是已加载模块的句柄。
如果函数失败,则返回值 NULL。 若要获取扩展的错误信息,请调用 GetLastError。
言论
LoadLibraryEx 函数与 LoadLibrary 函数非常相似。 区别包括一组可选行为,LoadLibraryEx 提供:
- LoadLibraryEx 可以加载 DLL 模块,而无需调用 DLL 的 DllMain 函数。
- LoadLibraryEx 可以采用针对永不执行模块的优化方式加载模块,就像是数据文件一样加载模块。
- LoadLibraryEx 可以使用两种搜索策略之一来查找模块及其关联的模块,也可以搜索特定于进程的目录集。
调用进程可以使用 LoadLibraryEx 返回的句柄来标识调用 GetProcAddress、FindResource和 LoadResource 函数的模块。
若要启用或禁用加载程序在 DLL 加载期间显示的错误消息,请使用 SetErrorMode 函数。
从 DllMain调用 LoadLibraryEx 是不安全的。 有关详细信息,请参阅 DllMain中的“备注”部分。
Visual C++:Visual C++ 编译器支持一种语法,可用于声明线程局部变量:_declspec(thread)。 如果在 DLL 中使用此语法,则无法在 Windows Vista 之前的 Windows 版本中使用 LoadLibraryEx 显式加载 DLL。 如果 DLL 将显式加载,则必须使用线程本地存储函数,而不是 _declspec(thread)。 有关示例,请参阅 使用动态链接库中的线程本地存储。
将 DLL 作为数据文件或图像资源加载
LOAD_LIBRARY_AS_DATAFILE、LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE和 LOAD_LIBRARY_AS_IMAGE_RESOURCE 值会影响每个进程引用计数和指定模块的加载。 如果为 dwFlags 参数指定了其中任何值,则加载程序将检查该模块是否已由进程加载为可执行 DLL。 如果是这样,则表示模块已映射到调用进程的虚拟地址空间。 在这种情况下,LoadLibraryEx 返回 DLL 的句柄,并递增 DLL 引用计数。 如果 DLL 模块尚未作为 DLL 加载,则系统会将模块映射为数据或图像文件,而不是作为可执行 DLL。 在这种情况下,LoadLibraryEx 返回加载的数据或图像文件的句柄,但不递增模块的引用计数,并且不会使模块对 CreateToolhelp32Snapshot 或 EnumProcessModules等函数可见。如果为同一文件调用 LoadLibraryEx 两次,LOAD_LIBRARY_AS_DATAFILE、LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE或 LOAD_LIBRARY_AS_IMAGE_RESOURCE,则会为该文件创建两个单独的映射。
使用 LOAD_LIBRARY_AS_IMAGE_RESOURCE 值时,将使用可移植可执行文件(PE)部分对齐扩展作为图像加载模块。 相对虚拟地址(RVA)不必映射到磁盘地址,因此可以从模块中更快地检索资源。 指定 LOAD_LIBRARY_AS_IMAGE_RESOURCE 可防止加载模块时修改其他进程。
除非应用程序依赖于特定的图像映射特征,否则 LOAD_LIBRARY_AS_IMAGE_RESOURCE 值应与 LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE 或 LOAD_LIBRARY_AS_DATAFILE一起使用。 这允许加载程序选择是将模块加载为图像资源还是数据文件,选择允许系统更有效地共享页面的选项。 FindResource 等资源函数可以使用任一映射。
若要确定模块的加载方式,请使用以下宏之一测试 LoadLibraryEx返回的句柄。
#define LDR_IS_DATAFILE(handle) (((ULONG_PTR)(handle)) & (ULONG_PTR)1)
#define LDR_IS_IMAGEMAPPING(handle) (((ULONG_PTR)(handle)) & (ULONG_PTR)2)
#define LDR_IS_RESOURCE(handle) (LDR_IS_IMAGEMAPPING(handle) || LDR_IS_DATAFILE(handle))
下表描述了这些宏。
宏观 | 描述 |
---|---|
LDR_IS_DATAFILE(句柄) | 如果此宏返回 TRUE,则模块已加载为数据文件(LOAD_LIBRARY_AS_DATAFILE 或 LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE)。 |
LDR_IS_IMAGEMAPPING(句柄) | 如果此宏返回 TRUE,则模块已加载为图像文件(LOAD_LIBRARY_AS_IMAGE_RESOURCE)。 |
LDR_IS_RESOURCE(句柄) | 如果此宏返回 true ,则模块将加载为数据文件或图像文件。 |
使用 FreeLibrary 函数释放加载的模块,无论加载模块是否导致其引用计数递增。 如果模块作为数据或图像文件加载,则映射将被销毁,但引用计数不会递减。 否则,DLL 引用计数将递减。 因此,使用 LoadLibraryEx返回的任何句柄 调用 freeLibrary 是安全的。
搜索 DLL 和依赖项
搜索路径是搜索 DLL 的目录集。 LoadLibraryEx 函数可以使用标准搜索路径或更改的搜索路径来搜索 DLL,也可以使用与 SetDefaultDllDirectories 和 AddDllDirectory 函数建立的进程特定的搜索路径。 有关目录的列表及其搜索顺序,请参阅 Dynamic-Link 库搜索顺序。LoadLibraryEx 函数在以下情况下使用标准搜索路径:
- 文件名未指定路径,并且基文件名与已加载模块的基文件名不匹配,并且不使用任何 LOAD_LIBRARY_SEARCH 标志。
- 指定了路径,但未使用 LOAD_WITH_ALTERED_SEARCH_PATH。
- 应用程序未使用 SetDefaultDllDirectories指定进程的默认 DLL 搜索路径。
如果 lpFileName 指定相对路径,则整个相对路径将追加到 DLL 搜索路径中的每个标记。 若要从相对路径加载模块而不搜索任何其他路径,请使用 GetFullPathName 获取非关系路径,并使用非关系路径调用 LoadLibraryEx。 如果模块作为数据文件加载,并且相对路径以“.”或“..”开头,则相对路径被视为绝对路径。
如果 lpFileName 指定绝对路径,dwFlags 设置为 LOAD_WITH_ALTERED_SEARCH_PATH,LoadLibraryEx 使用更改的搜索路径。 设置 LOAD_WITH_ALTERED_SEARCH_PATH 标志时,行为是未定义的,lpFileName 指定相对路径。
SetDllDirectory 函数可用于修改搜索路径。 此解决方案优于使用 SetCurrentDirectory 或硬编码 DLL 的完整路径。 但是,请注意,使用 SetDllDirectory 有效禁用安全 DLL 搜索模式,而指定的目录位于搜索路径中,并且不是线程安全的。 如果可能,最好使用 AddDllDirectory 修改默认进程搜索路径。 有关详细信息,请参阅 Dynamic-Link 库搜索顺序。
应用程序可以使用 LOAD_LIBRARY_SEARCH_* 标志指定要搜索单个 LoadLibraryEx 调用的目录。 如果指定了多个 LOAD_LIBRARY_SEARCH 标志,则按以下顺序搜索目录:
- 包含 DLL 的目录(LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR)。 此目录仅搜索要加载的 DLL 的依赖项。
- 应用程序目录(LOAD_LIBRARY_SEARCH_APPLICATION_DIR)。
- 使用 AddDllDirectory 函数(LOAD_LIBRARY_SEARCH_USER_DIRS)或 SetDllDirectory 函数显式添加到应用程序搜索路径的路径。 如果添加了多个路径,则搜索路径的顺序未指定。
- System32 目录(LOAD_LIBRARY_SEARCH_SYSTEM32)。
Windows 7、Windows Server 2008 R2、Windows Vista 和 Windows Server 2008:已安装 KB2533623 的系统上提供了 LOAD_LIBRARY_SEARCH_ 标志。 若要确定标志是否可用,请使用
如果应用程序已使用 SetDefaultDllDirectories 函数为进程建立 DLL 搜索路径,并且未使用 LOAD_LIBRARY_SEARCH_* 标志,则 LoadLibraryEx 函数使用进程 DLL 搜索路径而不是标准搜索路径。
如果指定了路径,并且存在与应用程序关联的重定向文件,LoadLibraryEx 函数将在应用程序目录中搜索该模块。 如果模块存在于应用程序目录中,LoadLibraryEx 将忽略路径规范并从应用程序目录中加载模块。 如果应用程序目录中不存在该模块,该函数将从指定的目录中加载该模块。 有关详细信息,请参阅 动态链接库重定向。
如果使用不带路径规范的程序集名称调用 LoadLibraryEx,并且程序集列在系统兼容清单中,则调用会自动重定向到并排程序集。
安全备注
LOAD_LIBRARY_AS_DATAFILE 不会阻止其他进程在加载模块时修改该模块。 由于这样可以降低应用程序的安全性,因此在将模块加载为数据文件时,应使用 LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE 而不是 LOAD_LIBRARY_AS_DATAFILE,除非你特别需要使用 LOAD_LIBRARY_AS_DATAFILE。 指定 LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE 可防止加载模块时修改其他进程。 不要在同一调用中指定 LOAD_LIBRARY_AS_DATAFILE 和 LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE。请勿使用 SearchPath 函数检索后续 LoadLibraryEx 调用的 DLL 路径。 SearchPath 函数使用与 LoadLibraryEx 不同的搜索顺序,除非通过 调用具有 BASE_SEARCH_PATH_ENABLE_SAFE_SEARCHMODE的 setSearchPathMode 显式启用此功能,否则它不使用安全进程搜索模式。 因此,SearchPath 可能首先搜索用户的当前工作目录以获取指定的 DLL。 如果攻击者将 DLL 的恶意版本复制到当前工作目录中,SearchPath 检索的路径将指向恶意 DLL,LoadLibraryEx 将加载该 DLL。
不要根据搜索 DLL 的 LoadLibraryEx 调用对操作系统版本做出假设。 如果应用程序在 DLL 合法不存在但 DLL 的恶意版本位于搜索路径中的环境中运行,则可能会加载 DLL 的恶意版本。 请改用 获取系统版本中所述的建议技术。
有关 DLL 安全问题的一般讨论,请参阅 Dynamic-Link 库安全性。
例子
下面的代码示例演示如何调用 LoadLibraryExA。
//Load the FMAPI DLL
hLib = ::LoadLibraryEx(L"fmapi.dll", NULL, NULL);
if ( !hLib )
{
wprintf(L"Could not load fmapi.dll, Error #%d.\n", GetLastError());
return;
}
有关其他示例,请参阅 查找错误代码号的文本。
注意
libloaderapi.h 标头将 LoadLibraryEx 定义为别名,该别名根据 UNICODE 预处理器常量的定义自动选择此函数的 ANSI 或 Unicode 版本。 将非中性编码别名与非非编码的代码混合使用可能会导致编译或运行时错误不匹配。 有关详细信息,请参阅函数原型的
要求
要求 | 价值 |
---|---|
最低支持的客户端 | Windows XP [仅限桌面应用] |
支持的最低服务器 | Windows Server 2003 [仅限桌面应用] |
目标平台 | 窗户 |
标头 | libloaderapi.h (包括 Windows.h) |
库 | Kernel32.lib |
DLL | Kernel32.dll |