我从一个目录执行一个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有效。
有谁知道为什么以及如何解决它?
答案 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中添加有关您的依赖项的信息。