避免包装器DLL中的堆栈溢出

时间:2010-05-03 19:41:59

标签: c++ visual-studio dll wrapper dynamic-linking

我有一个程序,我正在添加全屏幕后处理效果。我没有该程序的源代码(它是专有的,虽然开发人员确实向我发送了调试符号的副本,.map格式)。我有编写和工作的效果的代码,没有问题。

我现在的问题是将两者联系起来。

到目前为止,我尝试了两种方法:

使用Detours修改原始程序的导入表。这很好用并且保证稳定,但是我所谈到的用户对它不满意,它需要安装(除了提取存档之外),并且如果使用Detours修补程序在条款下有效则存在一些问题EULA。所以,那个选项就出来了。

另一种选择是传统的DLL替换。我已经包装了OpenGL(opengl32.dll),我需要程序来加载我的DLL而不是系统副本(只需将它放在程序文件夹中,使用正确的名称,这很容易)。

然后我需要我的DLL加载Cg框架和运行时(依赖于OpenGL)和其他一些东西。当Cg加载时,它调用我的一些函数,它调用Cg函数,我倾向于获得堆栈溢出和无限循环。我需要能够将Cg DLL包含在子目录中并仍然使用它们的函数(不确定是否可以将我的DLL导入表指向子目录中的DLL)或者我需要动态链接它们(我是d而不是做,只是为了简化构建过程),迫使他们引用系统的文件(而不是我的自定义替换)。

整个链是:程序加载DLL A(名为opengl32.dll)。 DLL A加载Cg.dll并动态链接(GetProcAddress)到sysdir / opengl32.dll。我现在需要Cg.dll来引用sysdir / opengl32.dll,不是 DLL A。

如何做到这一点? 修改:如何在不使用GetProcAddress的情况下轻松完成 ?如果没有别的办法,我愿意回过头来,但是如果可能的话,我宁愿不去。

Edit2:我偶然发现了MSDN文档中的函数SetDllDirectory(完全不相关的搜索)。乍一看,这看起来像我需要的。这是对的,还是我的错误判断? (现在试试)

编辑3:我通过做一些不同的事情来解决这个问题。我没有删除OpenGL32.dll,而是将我的DLL重命名为DInput.dll。它不仅具有导出一个函数而不是超过120的优势(对于程序,Cg和GLEW),我不必担心运行的函数(我可以像往常一样链接到OpenGL) 。为了进入我需要拦截的电话,我正在使用Detours。总而言之,它的效果要好得多。但是,这个问题仍然是一个有趣的问题(希望将来对其他任何试图做疯狂事情的​​人都有用)。答案都很好,所以我不确定要选哪个...

2 个答案:

答案 0 :(得分:1)

SetDllDirectory可能不会工作。 Cg.dll可能只是链接到OpenGL.dll。当操作系统加载Cg.dll时,它会看到已经有一个模块加载了该名称(你的),因此它将Cg链接到该模块而不是去寻找其他副本。也就是说,SetDllDirectory修改的搜索顺序甚至从未发挥作用,因为操作系统不进行任何搜索。

我怀疑你最好的选择是检测你的图书馆的重入调用。当您检测到一个,而不是进行自定义处理时,将调用直接转发到真正的OpenGL库,由于为每个库的函数调用LoadLibrary和GetProcAddress,所以您可以引用它。

答案 1 :(得分:1)

您可以使用激活上下文的魔力来尝试解决您的问题。

很大程度上取决于天气,系统中的第三方组件已经有清单 - 以及对这些清单进行多少篡改可能会导致许可证违规。

为了解决dll版本控制问题,Windows XP获得了一项名为激活上下文的技术。有时被称为并排集合,甚至像Application Isolation

那样可怕

总结大量阅读到一个小空间: 清单是可以描述程序集或描述程序集依赖关系的XML数据块。程序集是一个清单,加上它的dll。

存在的原因是程序集可以采用简单的dll。 “comctl32.dll”及其版本号(v6),并创建一个具有更大唯一名称的东西,这样简单的dll的多个版本可以安全地安装在同一个地方。程序集旨在安装在C:\Windows\WinSxS

当清单文件描述程序集中的dll时,它称为程序集清单。并且通常与dll有不同的名称。

当清单文件描述dll或exe使用的程序集时,它被称为应用程序清单,并且通常作为RT_MANIFEST资源嵌入到res ID为1的EXE中,在res中具有res值为2的Dll中 - 或者在磁盘上作为名为“appname.exe.manifest”/“dllname.dll.2.manifest”的文件。 应用程序清单定义了一个称为激活上下文的东西 - 它基本上是一个Windows将搜索内容的命名空间。 每个清单都会创建激活上下文。每个激活上下文都有一个简单的dll名称到程序集的映射。

因此,如果您使用您的 opengl32.dll文件创建程序集,并为app.exe引用(本地opengl32.dll)文件创建激活上下文,那么,可能,所有剩余的dll可以(并且将)继续使用系统opengl32.dll文件,尽管名称非常相似 coff

问题是,应用程序清单的res-id - 1 - 意味着它用于创建进程默认激活上下文 - 所以没有自己的显式清单(Cg?)的所有dll将搜索处理默认空间并找到opengl32.dll

所以你必须为的每个 dll创建一个尚未嵌入的清单,确保不引用你的opengl32.dll程序集,这样就可以恢复默认搜索顺序并在正常的system32位置找到它。

这意味着你的opengl32.dll不能在exe的文件夹中,因为在system32之前搜索了该文件夹的dll(你依赖挂钩的事实)。

我们通过搜索程序集时系统采用的相当简单的搜索顺序来保存。首先它在WinSxS中搜索。您的Opengl32.dll不会在那里,安装有一个难题。然后它在exe文件夹中搜索带有程序集名称的子文件夹,然后直接在exe文件夹中搜索程序集清单。

这意味着您可以创建一个程序集 - 称为“OpenGLHook” 您的文件夹结构如下所示:

\appfolder\
  app.exe
  app.exe.manifest                  - contains a dependentAssembly node to OpenGLHook
  OpenGLHook\OpenGLHook.manifest    - contains a file name=opengl32.dll
  OpenGLHook\opengl32.dll           - your hook dll
  yourimpl.dll                      - your implementation dll that linkgs to cg.dll
  cg.dll                            - cg libraries
  cg.dll.2.manifest                 - a stub manifest you put together to ensure cg
                                      doesnt use the app default activation ctx.
嗯,祝你好运?