动态链接库搜索顺序

同一动态链接库 (DLL) 的多个版本通常存在于操作系统 (OS) 内的不同文件系统位置。 可以通过指定完整路径来控制从中加载任何给定 DLL 的特定位置。 但是,如果不使用该方法,则系统会在加载时搜索 DLL,如本主题中所述。 DLL 加载程序是操作系统 (操作系统) 的一部分,用于加载 DLL 和/或解析对 DLL 的引用。

提示

有关 打包 应用和 未打包 应用的定义,请参阅 打包应用的优缺点

影响搜索的因素

下面是本主题中讨论的一些特殊搜索因素-你可以将其视为 DLL 搜索顺序的一部分。 本主题的后续部分按特定应用类型的相应搜索顺序以及其他搜索位置列出了这些因素。 本部分只是为了介绍概念,并为其提供名称,我们将在本主题的后面部分引用这些概念。

  • DLL 重定向。 有关详细信息,请参阅 动态链接库重定向
  • API 集。 有关详细信息,请参阅 Windows API 集
  • 并行 (SxS) 清单重定向 - 桌面应用仅 (不) UWP 应用。 可以使用应用程序清单 (也称为并行应用程序清单或融合清单) 进行重定向。 有关详细信息,请参阅 清单
  • Loaded-module 列表。 系统可以检查是否已将具有相同模块名称的 DLL 加载到内存 (,无论该 DLL 是从) 加载的。
  • 已知 DLL。 如果 DLL 位于运行应用程序的 Windows 版本的已知 DLL 列表中,则系统会使用其已知 DLL (副本和已知 DLL 的依赖 DLL(如果有任何) )。 有关当前系统上的已知 DLL 的列表,请参阅注册表项 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\KnownDLLs

如果 DLL 具有依赖项,则系统会搜索依赖 DLL,就像仅使用其模块名称加载一样。 即使通过指定完整路径加载了第一个 DLL,也是如此。

打包应用的搜索顺序

当打包的应用专门 (加载打包的模块时,库模块( .dll 通过调用 LoadPackagedLibrary 函数) 文件),DLL 必须位于进程的包依赖项关系图中。 有关详细信息,请参阅 LoadPackagedLibrary。 当打包的应用通过其他方式加载模块并且未指定完整路径时,系统会在加载时搜索 DLL 及其依赖项,如本部分所述。

当系统搜索模块或其依赖项时,它始终使用打包应用的搜索顺序;即使依赖项不是打包的应用代码。

打包应用的标准搜索顺序

系统按以下顺序搜索:

  1. DLL 重定向。
  2. API 集。
  3. 桌面应用仅 (UWP 应用) 。 SxS 清单重定向。
  4. Loaded-module 列表。
  5. 已知 DLL。
  6. 进程的包依赖项关系图。 这是应用程序的包,以及应用程序包清单的 节<Dependencies>中指定的任何依赖项<PackageDependency>。 依赖项按它们在清单中的出现顺序进行搜索。
  7. 调用进程从加载的文件夹 (可执行文件的文件夹) 。
  8. 系统文件夹 (%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 搜索模式,则搜索顺序如下所示:

  1. DLL 重定向。
  2. API sets.
  3. SxS manifest redirection.
  4. Loaded-module list.
  5. Known DLLs.
  6. Windows 11,版本 21H2 (10.0;内部版本 22000) 及更高版本。 The package dependency graph of the process. This is the application's package plus any dependencies specified as <PackageDependency> in the <Dependencies> section of the application's package manifest. Dependencies are searched in the order they appear in the manifest.
  7. 从中加载应用程序的文件夹。
  8. 系统文件夹。 使用 GetSystemDirectory 函数检索此文件夹的路径。
  9. 16 位系统文件夹。 没有获取此文件夹路径的函数,但会对其进行搜索。
  10. Windows 文件夹。 使用 GetWindowsDirectory 函数获取此文件夹的路径。
  11. 当前文件夹。
  12. 环境变量中列出的 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_PATHLoadLibraryEx 指定的备用搜索策略开始 (。

这是他们区别的唯一方式。

如果启用了安全 DLL 搜索模式,则备用搜索顺序如下所示:

步骤 1-6 与标准搜索顺序相同。

  1. 由 lpFileName 指定的文件夹。
  2. The system folder. Use the GetSystemDirectory function to retrieve the path of this folder.
  3. The 16-bit system folder. There's no function that obtains the path of this folder, but it is searched.
  4. The Windows folder. 使用 GetWindowsDirectory 函数获取此文件夹的路径。
  5. 当前文件夹。
  6. 环境变量中列出的 PATH 目录。 这不包括应用路径注册表项指定的每 应用程序路径 。 计算 DLL 搜索路径时,不使用 应用 路径密钥。

如果 禁用安全 DLL 搜索模式,则备用搜索顺序是相同的,只是 当前文件夹 在步骤 7 后立即从顺序 (从位置 11 移动到位置 8 。由 lpFileName 指定的文件夹) 。

如果 lpPathName 参数指定路径,SetDllDirectory 函数支持备用搜索顺序。 备用搜索顺序如下:

步骤 1-6 与标准搜索顺序相同。

  1. 从中加载应用程序的文件夹。
  2. 由 SetDllDirectorylpPathName 参数指定的文件夹。
  3. 系统文件夹。
  4. 16 位系统文件夹。
  5. Windows 文件夹。
  6. 环境变量中列出的 PATH 目录。

如果 lpPathName 参数为空字符串,则调用将从搜索顺序中删除当前文件夹。

当指定文件夹位于搜索路径中时,SetDllDirectory 可有效地禁用安全 DLL 搜索模式。 若要基于 SafeDllSearchMode 注册表值还原安全 DLL 搜索模式,并将当前文件夹还原到搜索顺序,请调用 SetDllDirectorylpPathName 为 NULL。

使用LOAD_LIBRARY_SEARCH标志搜索顺序

可以通过将一个或多个 LOAD_LIBRARY_SEARCH 标志与 LoadLibraryEx 函数配合使用来指定搜索顺序。 还可以将 LOAD_LIBRARY_SEARCH 标志与 SetDefaultDllDirectories 函数一起使用,以建立进程的 DLL 搜索顺序。 可以使用 AddDllDirectorySetDllDirectory 函数为进程 DLL 搜索顺序指定其他目录。

搜索的目录取决于使用 SetDefaultDllDirectoriesLoadLibraryEx 指定的标志。 如果使用多个标志,则按以下顺序搜索相应的目录:

  1. LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR。 搜索包含 DLL 的文件夹。 此文件夹仅搜索要加载的 DLL 的依赖项。
  2. LOAD_LIBRARY_SEARCH_APPLICATION_DIR。 搜索应用程序文件夹。
  3. LOAD_LIBRARY_SEARCH_USER_DIRS。 搜索使用 AddDllDirectory 函数或 SetDllDirectory 函数显式添加的路径。 如果添加多个路径,则未指定搜索路径的顺序。
  4. LOAD_LIBRARY_SEARCH_SYSTEM32。 搜索“系统”文件夹。

如果调用 LoadLibraryEx 时没有 LOAD_LIBRARY_SEARCH 标志,或者为进程建立 DLL 搜索顺序,则系统将使用标准搜索顺序或备用搜索顺序搜索 DLL。