动态链接库搜索顺序

系统可以包含同一动态链接库的多个版本 (DLL) 。 应用程序可以通过指定完整路径或使用其他机制(如清单)来控制 DLL 从中加载的位置。 如果未使用这些方法,系统将在加载时搜索 DLL,如本主题中所述。

影响搜索的因素

以下因素会影响系统是否搜索 DLL:

  • 如果内存中已加载具有相同模块名称的 DLL,则系统仅在解析到加载的 DLL 之前检查重定向和清单,无论它位于哪个目录中。 系统不搜索 DLL。
  • 如果 DLL 位于运行应用程序的Windows版本的已知 DLL 列表中,则系统会使用已知 DLL 的副本 (和已知 DLL 的依赖 DLL(如果有) 而不是搜索 DLL)。 有关当前系统上已知 DLL 的列表,请参阅以下注册表项: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\KnownDLLs
  • 如果 DLL 具有依赖项,系统会搜索依赖 DLL,就像只使用模块名称加载它们一样。 即使第一个 DLL 是通过指定完整路径加载的,也是如此。

UWP 应用的搜索顺序

当用于 Windows 10 (的 UWP 应用或用于 Windows 8.x) 的 Microsoft Store 应用通过调用 LoadPackagedLibrary 函数加载打包模块时,DLL 必须位于进程的包依赖项关系图中。 有关详细信息,请参阅 LoadPackagedLibrary。 当 UWP 应用以其他方式加载模块但不指定完整路径时,系统会在加载时搜索 DLL 及其依赖项,如本部分所述。

在系统搜索 DLL 之前,它会检查以下内容:

  • 如果内存中已加载具有相同模块名称的 DLL,则无论它位于哪个目录中,系统都使用加载的 DLL。 系统不搜索 DLL。
  • 如果 DLL 位于运行应用程序的Windows版本的已知 DLL 列表中,则系统会使用已知 DLL 的副本 (和已知 DLL 的依赖 DLL(如果有) )。 系统不搜索 DLL。 有关当前系统上已知 DLL 的列表,请参阅以下注册表项: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\KnownDLLs

如果系统必须搜索模块或其依赖项,它始终使用 UWP 应用的搜索顺序,即使依赖项不是 UWP 应用代码。

UWP 应用的标准搜索顺序

如果模块尚未加载或在已知 DLL 列表中,则系统按以下顺序搜索这些位置:

  1. 进程的包依赖项关系图。 这是应用程序的包以及应用程序包清单节中指定的<Dependencies>任何依赖项<PackageDependency>。 依赖项按它们在清单中显示的顺序进行搜索。
  2. 从中加载调用进程的目录。
  3. 系统目录 (%SystemRoot%\system32) 。

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

UWP 应用的备用搜索顺序

如果模块使用 LOAD_WITH_ALTERED_SEARCH_PATH 调用 LoadLibraryEx 函数来更改标准搜索顺序,则系统会搜索从中加载指定模块的目录,而不是调用进程的目录。 系统按以下顺序搜索这些位置:

  1. 进程的包依赖项关系图。 这是应用程序的包以及应用程序包清单节中指定的<Dependencies>任何依赖项<PackageDependency>。 依赖项按它们在清单中显示的顺序进行搜索。
  2. 从中加载指定模块的目录。
  3. 系统目录 (%SystemRoot%\system32) 。

桌面应用程序的搜索顺序

桌面应用程序可以通过指定完整路径、使用 DLL 重定向或使用 清单来控制 DLL 从中加载的位置。 如果未使用这些方法,系统将在加载时搜索 DLL,如本部分所述。

在系统搜索 DLL 之前,它会检查以下内容:

  • 如果内存中已加载具有相同模块名称的 DLL,则无论它位于哪个目录中,系统都使用加载的 DLL。 系统不搜索 DLL。
  • 如果 DLL 位于运行应用程序的Windows版本的已知 DLL 列表中,则系统会使用已知 DLL 的副本 (和已知 DLL 的依赖 DLL(如果有) )。 系统不搜索 DLL。 有关当前系统上已知 DLL 的列表,请参阅以下注册表项: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\KnownDLLs

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

重要

如果攻击者能够控制搜索的某个目录,则它可以在该目录中放置 DLL 的恶意副本。 有关帮助防止此类攻击的方法,请参阅 动态链接库安全性

桌面应用程序的标准搜索顺序

系统使用的标准 DLL 搜索顺序取决于是启用或禁用安全 DLL 搜索模式。 保险箱 DLL 搜索模式稍后按搜索顺序放置用户的当前目录。

默认情况下,保险箱 DLL 搜索模式处于启用状态。 若要禁用此功能,请创建 HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\SafeDllSearchMode 注册表值并将其设置为 0。 调用 SetDllDirectory 函数实际上禁用 SafeDllSearchMode ,而指定的目录位于搜索路径中,并更改本主题中所述的搜索顺序。

如果已启用 SafeDllSearchMode ,则搜索顺序如下所示:

  1. 应用程序从中加载的目录。
  2. 系统目录。 使用 GetSystemDirectory 函数获取此目录的路径。
  3. 16 位系统目录。 没有可获取此目录的路径的函数,但搜索该函数。
  4. Windows 目录。 使用 GetWindowsDirectory 函数获取此目录的路径。
  5. 当前目录。
  6. PATH 环境变量中列出的目录。 请注意,这不包括 应用路径 注册表项指定的按应用程序路径路径。 计算 DLL 搜索路径时,不会使用 应用路径 密钥。

如果禁用 SafeDllSearchMode ,则搜索顺序如下所示:

  1. 应用程序从中加载的目录。
  2. 当前目录。
  3. 系统目录。 使用 GetSystemDirectory 函数获取此目录的路径。
  4. 16 位系统目录。 没有可获取此目录的路径的函数,但搜索该函数。
  5. Windows 目录。 使用 GetWindowsDirectory 函数获取此目录的路径。
  6. PATH 环境变量中列出的目录。 请注意,这不包括 应用路径 注册表项指定的按应用程序路径路径。 计算 DLL 搜索路径时,不会使用 应用路径 密钥。

桌面应用程序的备用搜索顺序

可以通过使用 LOAD_WITH_ALTERED_SEARCH_PATH 调用 LoadLibraryEx 函数来更改系统使用的标准搜索顺序。 还可以通过调用 SetDllDirectory 函数来更改标准搜索顺序。

注意

在启动当前进程之前,进程的标准搜索顺序也会受到在父进程中调用 SetDllDirectory 函数的影响。

如果指定备用搜索策略,则其行为会继续,直到找到所有关联的可执行模块。 系统开始处理 DLL 初始化例程后,系统将恢复为标准搜索策略。

如果调用指定LOAD_WITH_ALTERED_SEARCH_PATHlpFileName 参数指定绝对路径,则 LoadLibraryEx 函数支持备用搜索顺序。

请注意,使用 LOAD_WITH_ALTERED_SEARCH_PATHLoadLibraryEx 指定的标准搜索策略和备用搜索策略只是一种方式不同:标准搜索从调用应用程序的目录中开始,备用搜索从加载 LoadLibraryEx 的可执行模块的目录中开始。

如果已启用 SafeDllSearchMode ,则备用搜索顺序如下所示:

  1. 由 lpFileName 指定的目录。
  2. 系统目录。 使用 GetSystemDirectory 函数获取此目录的路径。
  3. 16 位系统目录。 没有可获取此目录的路径的函数,但搜索该函数。
  4. Windows 目录。 使用 GetWindowsDirectory 函数获取此目录的路径。
  5. 当前目录。
  6. PATH 环境变量中列出的目录。 请注意,这不包括 应用路径 注册表项指定的按应用程序路径路径。 计算 DLL 搜索路径时,不会使用 应用路径 密钥。

如果 禁用 SafeDllSearchMode ,则备用搜索顺序如下所示:

  1. 由 lpFileName 指定的目录。
  2. 当前目录。
  3. 系统目录。 使用 GetSystemDirectory 函数获取此目录的路径。
  4. 16 位系统目录。 没有可获取此目录的路径的函数,但搜索该函数。
  5. Windows 目录。 使用 GetWindowsDirectory 函数获取此目录的路径。
  6. PATH 环境变量中列出的目录。 请注意,这不包括 应用路径 注册表项指定的按应用程序路径路径。 计算 DLL 搜索路径时,不会使用 应用路径 密钥。

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

  1. 应用程序从中加载的目录。
  2. SetDllDirectorylpPathName 参数指定的目录。
  3. 系统目录。 使用 GetSystemDirectory 函数获取此目录的路径。 此目录的名称为 System32。
  4. 16 位系统目录。 没有可获取此目录的路径的函数,但搜索该函数。 此目录的名称为 System。
  5. Windows 目录。 使用 GetWindowsDirectory 函数获取此目录的路径。
  6. PATH 环境变量中列出的目录。 请注意,这不包括 应用路径 注册表项指定的按应用程序路径路径。 计算 DLL 搜索路径时,不会使用 应用路径 密钥。

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

SetDllDirectory 有效地禁用安全 DLL 搜索模式,而指定的目录位于搜索路径中。 若要基于 SafeDllSearchMode 注册表值还原安全 DLL 搜索模式,并将当前目录还原到搜索顺序,请使用 lpPathName 调用 SetDllDirectory 作为 NULL。

使用 LOAD_LIBRARY_SEARCH 标志搜索顺序

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

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

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

如果应用程序未使用任何LOAD_LIBRARY_SEARCH标志调用 LoadLibraryEx 或建立进程的 DLL 搜索顺序,则系统会使用标准搜索顺序或备用搜索顺序搜索 DLL。

AddDllDirectory

应用程序注册

动态链接库重定向

动态链接库安全性

LoadLibrary

LoadLibraryEx

LoadPackagedLibrary

SetDefaultDllDirectories

SetDllDirectory

并排组件