SetDllDirectory不级联,因此无法加载依赖项DLL

时间:2017-06-16 11:52:51

标签: windows winapi dll setdlldirectory

我从一个目录执行一个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(...)执行GetProcAddress时,我收到错误:

  

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

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

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

1 个答案:

答案 0 :(得分:4)

应该有效。 SetDllDirectory确实"级联"因此会影响依赖DLL的加载方式。基本上,SetDllDirectory允许您修改进程的default search order for DLLs,并且对此进行的任何更改都会影响整个进程,包括可能加载到该进程中的任何DLL。当Windows隐式加载子进程的依赖关系时,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加载lib2.dll并传递覆盖默认搜索顺序的许多标志之一,如LOAD_LIBRARY_SEARCH_APPLICATION_DIR

最佳解决方案是将您依赖的所有DLL放在应用程序目录中。在Windows上the application's directory is the application bundle,所以这是放置它们的最佳位置。用户永远不应该在这个目录中挖掘,所以"混乱了#34;不是一个问题。它解决了各种各样的问题,包括依赖注入攻击,其中有人将同名的DLL放在当前目录中。 (您可以通过调用SetDllDirectory并传递空字符串以从搜索顺序中删除当前目录来防止此类攻击,但现在我们又回到问题#1。如果您有访客修改DLL搜索顺序的房子,这不是安全问题的可靠修复。如果你把DLL放在应用程序目录中,它们将在当前之前找到 first 搜索目录,关闭攻击向量,然后才能被利用。)

如果你有一个非常好的理由将DLL放在不同的目录中,那么你的选项数量有限。

您无法使用AddDllDirectory,因为上述文档会继续提供建议,因为您无法控制lib1.dll中的代码,因此无法将其修改为使用LoadLibraryEx标记致电LOAD_LIBRARY_SEARCH_USER_DIRS

通过指定完整路径来加载lib1.dll无法正常工作,因为"如果DLL具有依赖关系,系统将搜索依赖DLL,就好像它们仅加载了模块名称一样。即使通过指定完整路径加载第一个DLL,也是如此。"

这为您提供了using DLL redirection选项,或者在您的应用程序manifest中添加有关您的依赖项的信息。