2

我从一个目录执行一个 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,出现错误:

“程序无法启动,因为您的计算机中缺少 lib2.dll。请尝试重新安装程序以解决此问题。”

如果我移动lib2.dll到“C:/test”,就会找到它。这意味着这SetDllDirectory()仅对加载第一个 DLL 有效。

有谁知道为什么以及如何解决它?

4

1 回答 1

7

应该有效。SetDllDirectory会“级联”,因此会影响相关 DLL 的加载方式。基本上,SetDllDirectory允许您修改进程对 DLLs 的默认搜索顺序,并且对此进行的任何更改都会影响整个进程,包括可能加载到该进程中的任何 DLL。当 Windows 隐式加载子进程的依赖项时,也会使用此搜索顺序。

但是,如文档SetDllDirectory中所述,存在一个致命缺陷:

每次SetDllDirectory调用该函数时,它都会替换上一次SetDllDirectory调用中指定的目录。

如果您的进程中的其他代码正在调用SetDllDirectory,那么它正在撤消您的第一次调用。如果是 lib1.dll 中的代码在尝试加载 lib2.dll 之前执行此操作,则加载 lib2.dll 的尝试将失败。

现在,当然,这是 lib1.dll 的不良行为。DLL 是应用程序进程中的客人,因此不应该去改变地毯。但并非所有代码都表现良好,这使得这是一个脆弱的策略。

另一种可能出错的方法是,如果 lib1.dll 通过调用LoadLibraryEx和传递覆盖默认搜索顺序的众多标志之一来加载 lib2.dll,例如LOAD_LIBRARY_SEARCH_APPLICATION_DIR.

最好的解决方案是将所有依赖的 DLL 放在应用程序目录中。在 Windows 上,应用程序的目录是应用程序包,所以这是放置它们的最佳位置。用户永远不应该翻遍这个目录,所以“把它弄得乱七八糟”不是问题。它解决了各种问题,包括依赖注入攻击,即有人将同名的 DLL 放在当前目录中。(您可以通过调用来防止这种类型的攻击SetDllDirectory并传递一个空字符串以从搜索顺序中删除当前目录,但现在我们回到问题 #1。如果您家中有客人正在修改 DLL 搜索顺序,则这不是解决安全问题的可靠方法。如果将 DLL 放在应用程序目录中,它们将在当前目录被搜索之前首先被找到,从而在攻击向量被利用之前关闭它。)

如果您有充分的理由将 DLL 放在不同的目录中,那么您的选择数量有限。

您不能使用AddDllDirectory上面引用的文档继续建议,因为您不控制 lib1.dll 中的代码,因此无法修改它以LoadLibraryEx使用LOAD_LIBRARY_SEARCH_USER_DIRS标志调用。

通过指定完整路径加载 lib1.dll 将不起作用,因为“如果 DLL 具有依赖项,系统会搜索依赖的 DLL,就好像它们只加载了它们的模块名称一样。即使加载了第一个 DLL,也是如此。通过指定完整路径。”

这使您可以选择使用 DLL 重定向,或在应用程序的清单中添加有关您的依赖项的信息。

于 2017-06-16T12:13:45.690 回答