【问题标题】:SetDllDirectory does not cascade, so dependency DLLs cannot be loadedSetDllDirectory 不会级联,因此无法加载依赖 DLL
【发布时间】:2017-06-16 11:52:50
【问题描述】:

我从一个目录执行一个 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 有效。

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

【问题讨论】:

  • 它没有回答你的问题,但我还是要问:将 DLL 放在应用程序文件夹的“dlls”子目录中的动机是什么?在 Windows 上,the application's directory is the application bundle,所以你应该把 DLL 放在那里。这还可以防止您受到安全问题的影响,例如将恶意 DLL 放置在当前目录中并错误加载。
  • 您的诊断不正确。其他一些代码(可能在 lib1 中)正在将您的调用恢复为 SetDllDirectory。将所有 DLL 与可执行文件放在同一目录中,然后继续。
  • @DavidHeffernan:不,lib1 不会恢复调用
  • @CodyGray:因为我们有 70 个 DLL,我们想将它们分开。但也许你是对的,我们应该避免它,因为它只是为了“好看”的原因
  • 将 DLL 与什么分开?其他可执行模块?有什么特别的目的?它不像应用程序目录是用户可见的。

标签: windows winapi dll setdlldirectory


【解决方案1】:

应该工作。 SetDllDirectory 会“级联”,因此会影响相关 DLL 的加载方式。基本上,SetDllDirectory 允许您修改进程的default search order for DLLs,对此所做的任何更改都会影响整个进程,包括可能加载到该进程中的任何 DLL。当 Windows 为子进程隐式加载依赖项时,也会使用此搜索顺序。

但是,SetDllDirectory 中存在一个致命缺陷,正如 the documentation 中所指出的:

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

如果您的进程中的其他代码正在调用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 并传递覆盖默认搜索顺序的众多标志之一(例如 LOAD_LIBRARY_SEARCH_APPLICATION_DIR)来加载 lib2.dll,这可能会出错的另一种方式。

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

如果您有一个非常好的理由将 DLL 放在不同的目录中,那么您的选择是有限的。

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

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

这让您可以选择using DLL redirection,或在应用程序的manifest 中添加有关您的依赖项的信息。

【讨论】:

  • 好的,感谢您的详细解答。我会尽力说服我的团队按照你们在这里的建议去做。将 DLL 放在另一个目录中似乎是一个非常愚蠢的解决方案
  • 关于第一段,您的意思是讨论子进程吗?这里看起来像一个进程,我认为子进程不会继承修改后的 dll 搜索路径。
  • 是的,SetDllDirectory 影响整个进程所有子进程。或者,至少,它会影响 Windows 如何隐式加载子进程所依赖的 DLL。子进程调用LoadLibrary时无效。我想,无论哪种方式,措辞都很草率。会修复。 @大卫
  • 有点复杂。我们的 exe 正在将一个库注入到正在运行的进程中。另外,我是公司的新人,所以我仍然不清楚发生了什么。
  • 将 DLL 注入到另一个正在运行的进程中?你不是唯一一个不清楚发生了什么的人。我无法想象一个应用程序想要这样做的很多正当理由。恶意软件的目的大多浮现在脑海中。为什么你需要这样做?你不控制其他进程吗?这是什么应用程序?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-08-05
  • 1970-01-01
  • 2016-12-08
  • 2020-04-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多