SetDllDirectory 不级联,所以无法加载依赖DLL
SetDllDirectory does not cascade, so dependency DLLs cannot be loaded
我从一个目录执行一个 exe,比如 "C:/test"
DLL 位于目录 "C:/test/dlls" 中,因此,在此 exe 中,我调用:
SetDllDirectory("C:/test/dlls");
然后我打电话给
lib1 = LoadLibrary("lib1.dll)
和
ptrType pr = (ptrType) ::GetProcAddress(lib1, "test")
lib1.dll
需要目录 "C:/test/dlls" 中的其他 DLL,但是当我执行 pr(...)
got from GetProcAddress
时,出现错误:
"The program can't start because lib2.dll is missing from your computer. Try reinstalling the program to fix this problem."
如果我将 lib2.dll
移动到 "C:/test",它就会被发现。
这意味着 SetDllDirectory()
仅对第一个 DLL 的加载有效。
有谁知道为什么以及如何解决它?
这个应该有效。 SetDllDirectory
执行“级联”,因此会影响相关 DLL 的加载方式。基本上,SetDllDirectory
允许您修改进程的 default search order for DLLs,对此所做的任何更改都会影响整个进程,包括可能加载到该进程中的任何 DLL。 Windows 在隐式加载子进程的依赖项时也使用此搜索顺序。
然而,SetDllDirectory
中存在致命缺陷,如 the documentation 中所述:
Each time the SetDllDirectory
function is called, it replaces the directory specified in the previous SetDllDirectory
call.
如果您进程中的某些其他代码正在调用 SetDllDirectory
,那么它正在撤消您的第一个调用。如果 lib1.dll 中的代码在尝试加载 lib2.dll 之前执行此操作,则加载 lib2.dll 的尝试将失败。
当然,这是 lib1.dll 的不良行为。 DLL 为 guests in the application process and therefore should not go changing the carpet。但并不是所有的代码都表现良好,这使得这是一个脆弱的策略。
另一种可能出错的方式是,如果 lib1.dll 通过调用 LoadLibraryEx
加载 lib2.dll 并传递覆盖默认搜索顺序的许多标志之一,例如 LOAD_LIBRARY_SEARCH_APPLICATION_DIR
.
最佳解决方案是将您依赖的所有 DLL 放在应用程序目录中。在Windows、the application's directory is the application bundle上,所以这是放置它们的最佳位置。用户永远不应该翻阅这个目录,所以“弄乱它”不是问题。它解决了各种问题,包括有人在当前目录中放置同名 DLL 的依赖注入攻击。 (您可以通过调用 SetDllDirectory
并传递一个空字符串以从搜索顺序中删除当前目录来防止此类攻击,但现在我们回到问题 #1。如果您家里有客人修改 DLL 搜索顺序,这不是解决安全问题的可靠方法。如果将 DLL 放在应用程序目录中,将在搜索当前目录之前 first 找到它们,在攻击向量被利用之前关闭它。)
如果您有非常好的理由将 DLL 放在不同的目录中,那么您的选择就有限了。
您不能使用 AddDllDirectory
,因为上面引用的文档继续建议,因为您不控制 lib1.dll 中的代码,因此无法修改它以调用 LoadLibraryEx
带有 LOAD_LIBRARY_SEARCH_USER_DIRS
标志。
通过指定完整路径加载 lib1.dll 是行不通的,因为“如果 DLL 具有依赖项,系统会搜索依赖的 DLL,就好像它们仅使用模块名称加载一样。这是真的即使第一个 DLL 是通过指定完整路径加载的。"
这使您可以选择 using DLL redirection, or adding information about your dependencies in your application's manifest。
我从一个目录执行一个 exe,比如 "C:/test"
DLL 位于目录 "C:/test/dlls" 中,因此,在此 exe 中,我调用:
SetDllDirectory("C:/test/dlls");
然后我打电话给
lib1 = LoadLibrary("lib1.dll)
和
ptrType pr = (ptrType) ::GetProcAddress(lib1, "test")
lib1.dll
需要目录 "C:/test/dlls" 中的其他 DLL,但是当我执行 pr(...)
got from GetProcAddress
时,出现错误:
"The program can't start because lib2.dll is missing from your computer. Try reinstalling the program to fix this problem."
如果我将 lib2.dll
移动到 "C:/test",它就会被发现。
这意味着 SetDllDirectory()
仅对第一个 DLL 的加载有效。
有谁知道为什么以及如何解决它?
这个应该有效。 SetDllDirectory
执行“级联”,因此会影响相关 DLL 的加载方式。基本上,SetDllDirectory
允许您修改进程的 default search order for DLLs,对此所做的任何更改都会影响整个进程,包括可能加载到该进程中的任何 DLL。 Windows 在隐式加载子进程的依赖项时也使用此搜索顺序。
然而,SetDllDirectory
中存在致命缺陷,如 the documentation 中所述:
Each time the
SetDllDirectory
function is called, it replaces the directory specified in the previousSetDllDirectory
call.
如果您进程中的某些其他代码正在调用 SetDllDirectory
,那么它正在撤消您的第一个调用。如果 lib1.dll 中的代码在尝试加载 lib2.dll 之前执行此操作,则加载 lib2.dll 的尝试将失败。
当然,这是 lib1.dll 的不良行为。 DLL 为 guests in the application process and therefore should not go changing the carpet。但并不是所有的代码都表现良好,这使得这是一个脆弱的策略。
另一种可能出错的方式是,如果 lib1.dll 通过调用 LoadLibraryEx
加载 lib2.dll 并传递覆盖默认搜索顺序的许多标志之一,例如 LOAD_LIBRARY_SEARCH_APPLICATION_DIR
.
最佳解决方案是将您依赖的所有 DLL 放在应用程序目录中。在Windows、the application's directory is the application bundle上,所以这是放置它们的最佳位置。用户永远不应该翻阅这个目录,所以“弄乱它”不是问题。它解决了各种问题,包括有人在当前目录中放置同名 DLL 的依赖注入攻击。 (您可以通过调用 SetDllDirectory
并传递一个空字符串以从搜索顺序中删除当前目录来防止此类攻击,但现在我们回到问题 #1。如果您家里有客人修改 DLL 搜索顺序,这不是解决安全问题的可靠方法。如果将 DLL 放在应用程序目录中,将在搜索当前目录之前 first 找到它们,在攻击向量被利用之前关闭它。)
如果您有非常好的理由将 DLL 放在不同的目录中,那么您的选择就有限了。
您不能使用 AddDllDirectory
,因为上面引用的文档继续建议,因为您不控制 lib1.dll 中的代码,因此无法修改它以调用 LoadLibraryEx
带有 LOAD_LIBRARY_SEARCH_USER_DIRS
标志。
通过指定完整路径加载 lib1.dll 是行不通的,因为“如果 DLL 具有依赖项,系统会搜索依赖的 DLL,就好像它们仅使用模块名称加载一样。这是真的即使第一个 DLL 是通过指定完整路径加载的。"
这使您可以选择 using DLL redirection, or adding information about your dependencies in your application's manifest。