动态链接库搜索规则
同一动态链接库 (DLL) 的多个版本通常存在于操作系统 (OS) 内的不同文件系统位置。 可以通过指定完整路径来控制从中加载任何给定 DLL 的特定位置。 但是,如果不使用该方法,则系统会在加载时搜索 DLL。 DLL 加载程序是操作系统 的一部分,用于加载 DLL 和/或解析对 DLL 的引用。
打包应用的搜索顺序
当打包的应用专门加载打包的模块时,DLL 必须位于进程的包依赖项关系图中。 当打包的应用通过其他方式加载模块并且未指定完整路径时,系统会在加载时搜索 DLL 及其依赖项,如本部分所述。
当系统搜索模块或其依赖项时,它始终使用打包应用的搜索顺序;即使依赖项不是打包的应用代码。
打包应用的系统按以下顺序搜索:
- DLL 加载器的 重定向;
- API 集,打包应用指定;
- 桌面应用仅 (UWP 应用) , SxS 清单重定向;
- Loaded-module 列表;
- 已知 DLL;
- 进程的包依赖项关系图。 这是应用程序的包,以及应用程序包清单的 节<Dependencies>中指定的任何依赖项<PackageDependency>。 依赖项按它们在清单中的出现顺序进行搜索;
- 调用进程从加载的文件夹 (可执行文件的文件夹) 。
- 系统文件夹 (%SystemRoot%\system32) ;
如果 DLL 具有依赖项,则系统会搜索依赖 DLL,就好像只加载了其模块名称,即使第一个 DLL 是通过指定完整路径加载的。
打包应用的备用搜索顺序,如果模块通过使用 LOAD_WITH_ALTERED_SEARCH_PATH 调用 LoadLibraryEx 函数更改标准搜索顺序,则搜索顺序与标准搜索顺序相同,只是在步骤 7 中,系统搜索从加载指定模块的文件夹 (顶部加载模块的文件夹) ,而不是可执行文件的文件夹。
未打包应用的搜索顺序
当未打包的应用加载模块且未指定完整路径时,系统会在加载时搜索 DLL。注意如果攻击者控制了搜索的某个目录,则可以在该文件夹中放置 DLL 的恶意副本。 系统使用的标准 DLL 搜索顺序取决于是否启用了 安全 DLL 搜索模式 。
默认情况下启用的安全 DLL 搜索模式按搜索顺序移动用户的当前文件夹。 若要禁用安全 DLL 搜索模式,请 HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\SafeDllSearchMode 创建注册表值并将其设置为 0。 当指定文件夹位于搜索路径 时,调用 SetDllDirectory 函数可有效地禁用安全 DLL 搜索模式,并更改这部分中所述的搜索顺序。
如果启用了安全 DLL 搜索模式,则搜索顺序如下所示:
- DLL 加载器的 重定向;
- API 集合;
- SxS 清单重定向 ;
- Loaded-module 链表;
- 已知的DLLs;
- Windows 11,版本 21H2 (10.0;内部版本 22000) 及更高版本。 流程的包依赖关系图。这是应用程序的包加上在应用程序包清单的< dependencies >部分中指定为<PackageDependency>的任何依赖项。依赖项按照它们在清单中出现的顺序进行搜索;
- 从中加载应用程序的文件夹;
- 系统文件夹。 使用 GetSystemDirectory 函数检索此文件夹的路径;
- 16 位系统文件夹。 没有获取此文件夹路径的函数,但会对其进行搜索;
- Windows 文件夹。 使用 GetWindowsDirectory 函数获取此文件夹的路径;
- 当前文件夹;
- 环境变量中列出的 PATH 目录。 这不包括由应用路径注册表项指定的每 应用程序路径 。 计算 DLL 搜索路径时,不使用 应用 路径键;
- 如果 禁用安全 DLL 搜索模式,则搜索顺序相同,只是 当前文件夹 在步骤 7 之后立即从序列 (从位置 11 移动到位置 8 。应用程序从中加载) 的文件夹 ;
未打包应用的备用搜索顺序
若要更改系统使用的标准搜索顺序,可以使用 LOAD_WITH_ALTERED_SEARCH_PATH调用 LoadLibraryEx 函数。 还可以通过调用 SetDllDirectory 函数来更改标准搜索顺序。
在当前进程开始之前,在父进程中调用 SetDllDirectory 函数也会影响进程的标准搜索顺序。
如果指定备用搜索策略,则其行为会一直持续到找到所有关联的可执行模块。在系统开始处理 DLL 初始化例程后,系统将恢复为标准搜索策略。
如果调用指定LOAD_WITH_ALTERED_SEARCH_PATH,并且 lpFileName 参数指定绝对路径,则 LoadLibraryEx 函数支持备用搜索顺序:
- 在调用应用程序的文件夹中初始步骤后,标准搜索策略开始;
- 在 LoadLibraryEx 正在加载的可执行模块的文件夹中的初始步骤后,使用 LOAD_WITH_ALTERED_SEARCH_PATH 的LoadLibraryEx 指定的备用搜索策略开始 ;
如果启用了安全 DLL 搜索模式,则备用搜索顺序如下所示:
- 步骤 1-6 与标准搜索顺序相同;
- 由 lpFileName 指定的文件夹;
- 系统文件夹,使用 GetSystemDirectory 可以获取;
- 16 位系统文件夹。 没有获取此文件夹路径的函数,但会对其进行搜索;
- Windows 文件夹. 使用 GetWindowsDirectory 函数获取此文件夹的路径;
- 当前文件夹;
- 环境变量中列出的 PATH 目录。 这不包括应用路径注册表项指定的每 应用程序路径 。 计算 DLL 搜索路径时,不使用 应用 路径密钥;
如果 禁用安全 DLL 搜索模式,则备用搜索顺序是相同的,只是 当前文件夹 在步骤 7 后,顺序从位置 11 移动到位置 8 ,由 lpFileName 指定的文件夹。
如果 lpPathName 参数指定路径,SetDllDirectory 函数支持备用搜索顺序。 备用搜索顺序如下:
- 步骤 1-6 与标准搜索顺序相同;
- 从中加载应用程序的文件夹;
- 由 SetDllDirectory 的 lpPathName 参数指定的文件夹;
- 系统文件夹;
- 16 位系统文件夹;
- Windows 文件夹;
- 环境变量中列出的 PATH 目录;
如果 lpPathName 参数为空字符串,则调用将从搜索顺序中删除当前文件夹;
当指定文件夹位于搜索路径中时,SetDllDirectory 可有效地禁用安全 DLL 搜索模式。 若要基于 SafeDllSearchMode 注册表值还原安全 DLL 搜索模式,并将当前文件夹还原到搜索顺序,请调用 SetDllDirectory , lpPathName 为 NULL。
使用LOAD_LIBRARY_SEARCH标志搜索顺序
可以通过将一个或多个 LOAD_LIBRARY_SEARCH 标志与 LoadLibraryEx 函数配合使用来指定搜索顺序。 还可以将 LOAD_LIBRARY_SEARCH 标志与 SetDefaultDllDirectories 函数一起使用,以建立进程的 DLL 搜索顺序。 可以使用 AddDllDirectory 或 SetDllDirectory 函数为进程 DLL 搜索顺序指定其他目录。
搜索的目录取决于使用 SetDefaultDllDirectories 或 LoadLibraryEx 指定的标志。 如果使用多个标志,则按以下顺序搜索相应的目录:
- LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR。 搜索包含 DLL 的文件夹。 此文件夹仅搜索要加载的 DLL 的依赖项;
- LOAD_LIBRARY_SEARCH_APPLICATION_DIR。 搜索应用程序文件夹;
- LOAD_LIBRARY_SEARCH_USER_DIRS。 搜索使用 AddDllDirectory 函数或 SetDllDirectory 函数显式添加的路径。 如果添加多个路径,则未指定搜索路径的顺序;
- LOAD_LIBRARY_SEARCH_SYSTEM32。 搜索“系统”文件夹;
如果调用 LoadLibraryEx 时没有 LOAD_LIBRARY_SEARCH 标志,或者为进程建立 DLL 搜索顺序,则系统将使用标准搜索顺序或备用搜索顺序搜索 DLL。