一个系统可以包含同一动态链接库(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,也是如此。
当Windows 10的UWP应用程序(或Windows 8.x的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列表中,则系统将按以下顺序搜索这些位置:
- 程序的程序包依赖关系图。这是应用程序的包加上指定为任何依赖
于
应用程序的软件包清单的部分。按照它们在清单中出现的顺序搜索依赖关系。
- 调用进程从中加载的目录。
- 系统目录(%SystemRoot%\ system32)。
如果DLL具有依赖项,则系统将搜索依赖的DLL,就好像它们仅使用其模块名加载一样。即使通过指定完整路径加载了第一个DLL,也是如此。
UWP应用的替代搜索顺序如果模块通过使用LOAD_WITH_ALTERED_SEARCH_PATH调用LoadLibraryEx函数来更改标准搜索顺序,则系统将搜索指定模块的加载目录,而不是调用进程的目录。系统按以下顺序搜索这些位置:
- 程序的程序包依赖关系图。这是应用程序的包加上指定为任何依赖
于
应用程序的软件包清单的部分。按照它们在清单中出现的顺序搜索依赖关系。
- 指定模块的加载目录。
- 系统目录(%SystemRoot%\ system32)。
桌面应用程序可以通过指定完整路径,使用DLL重定向或使用manifest来控制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的恶意副本放置在该目录中。有关防止此类攻击的方法,请参见Dynamic-Link Library Security。
系统使用的标准DLL搜索顺序取决于是否启用安全DLL搜索模式。安全DLL搜索模式将用户的当前目录放在搜索顺序的后面。
默认情况下,安全DLL搜索模式处于启用状态。若要禁用此功能,请创建HKEY_LOCAL_MACHINE \ System \ CurrentControlSet \ Control \ Session Manager \ SafeDllSearchMode注册表值并将其设置为0。当指定目录在搜索路径中时,调用SetDllDirectory函数可有效禁用SafeDllSearchMode并按照说明更改搜索顺序在本主题中。
如果启用了SafeDllSearchMode,则搜索顺序如下:
- 从加载应用程序的目录中。
- 系统目录。使用GetSystemDirectory函数获取此目录的路径。
- 16位系统目录。没有获取该目录路径的函数,但会对其进行搜索。
- Windows目录。使用GetWindowsDirectory函数获取此目录的路径。
- 用户的当前目录。
- PATH环境变量中列出的目录。请注意,这不包括App Paths注册表项指定的每个应用程序路径。计算DLL搜索路径时不使用App Paths键。
如果禁用SafeDllSearchMode,则搜索顺序如下:
- 从加载应用程序的目录中。
- 用户的当前目录。
- 系统目录。使用GetSystemDirectory函数获取此目录的路径。
- 16位系统目录。没有获取该目录路径的函数,但会对其进行搜索。
- Windows目录。使用GetWindowsDirectory函数获取此目录的路径。
- PATH环境变量中列出的目录。请注意,这不包括App Paths注册表项指定的每个应用程序路径。计算DLL搜索路径时不使用App Paths键。
通过使用LOAD_WITH_ALTERED_SEARCH_PATH(将这个标志加到LoadLibraryEx中)调用LoadLibraryEx函数,可以更改系统使用的标准搜索顺序。也可以通过调用SetDllDirectory函数来更改标准搜索顺序。
备注
在当前进程开始之前,通过在父进程中调用SetDllDirectory函数也将影响该进程的标准搜索顺序。
如果指定备用搜索策略,则其行为将一直持续到找到所有关联的可执行模块为止。系统开始处理DLL初始化例程后,系统将还原为标准搜索策略。
如果调用指定LOAD_WITH_ALTERED_SEARCH_PATH且lpFileName参数指定绝对路径,则LoadLibraryEx函数支持备用搜索顺序。
请注意,LoadLibraryEx使用LOAD_WITH_ALTERED_SEARCH_PATH指定的标准搜索策略和替代搜索策略只有一种不同:标准搜索从调用应用程序的目录开始,替代搜索从LoadLibraryEx正在加载的可执行模块的目录开始。
如果启用了SafeDllSearchMode,则备用搜索顺序如下:
- lpFileName指定的目录。
- 系统目录。使用GetSystemDirectory函数获取此目录的路径。
- 16位系统目录。没有获取该目录路径的函数,但会对其进行搜索。
- Windows目录。使用GetWindowsDirectory函数获取此目录的路径。
- 当前目录。
- PATH环境变量中列出的目录。请注意,这不包括App Paths注册表项指定的每个应用程序路径。计算DLL搜索路径时不使用App Paths键。
如果SafeDllSearchMode被禁用,则替代搜索顺序如下:
- lpFileName指定的目录。
- 当前目录。
- 系统目录。使用GetSystemDirectory函数获取此目录的路径。
- 16位系统目录。没有获取该目录路径的函数,但会对其进行搜索。
- Windows目录。使用GetWindowsDirectory函数获取此目录的路径。
- PATH环境变量中列出的目录。请注意,这不包括App Paths注册表项指定的每个应用程序路径。计算DLL搜索路径时不使用App Paths键。
SetDllDirectory功能支持的替代搜索顺序如果lpPathName参数指定的路径。备用搜索顺序如下:
- 从加载应用程序的目录中。
- 由SetDllDirectory的lpPathName参数指定的目录。
- 系统目录。使用GetSystemDirectory函数获取此目录的路径。该目录的名称是System32。
- 16位系统目录。没有获取该目录路径的函数,但会对其进行搜索。该目录的名称是System。
- Windows目录。使用GetWindowsDirectory函数获取此目录的路径。
- PATH环境变量中列出的目录。请注意,这不包括App Paths注册表项指定的每个应用程序路径。计算DLL搜索路径时不使用App Paths键。
如果lpPathName参数为空字符串,则该调用将从搜索顺序中删除当前目录。
当指定目录位于搜索路径中时, SetDllDirectory有效地禁用安全DLL搜索模式。要恢复基于安全DLL搜索模式SafeDllSearchMode注册表值,并恢复当前目录搜索顺序,调用SetDllDirectory会与lpPathName为NULL。
使用LOAD_LIBRARY_SEARCH标志的搜索顺序应用程序可以通过将一个或多个LOAD_LIBRARY_SEARCH标志与LoadLibraryEx函数一起使用来指定搜索顺序。应用程序还可以将LOAD_LIBRARY_SEARCH标志与SetDefaultDllDirectories函数一起使用,以建立进程的DLL搜索顺序。应用程序可以使用AddDllDirectory或SetDllDirectory函数为进程DLL搜索顺序指定其他目录。
搜索的目录取决于SetDefaultDllDirectories或LoadLibraryEx指定的标志。如果使用多个标志,则按以下顺序搜索相应的目录:
- 包含DLL的目录(LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR)。仅在此目录中搜索要加载的DLL的依赖项。
- 应用程序目录(LOAD_LIBRARY_SEARCH_APPLICATION_DIR)。
- 使用AddDllDirectory函数(LOAD_LIBRARY_SEARCH_USER_DIRS)或SetDllDirectory函数显式添加的路径。如果添加了多个路径,则未指定搜索路径的顺序。
- 系统目录(LOAD_LIBRARY_SEARCH_SYSTEM32)。
如果应用程序未使用任何LOAD_LIBRARY_SEARCH标志调用LoadLibraryEx或未为该过程建立DLL搜索顺序,则系统将使用标准搜索顺序或替代搜索顺序搜索DLL。