代码之家  ›  专栏  ›  技术社区  ›  ssube

避免包装DLL中的堆栈溢出

  •  6
  • ssube  · 技术社区  · 14 年前

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

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

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

    使用迂回路线修改原始程序的导入表。这很好,而且保证稳定,但是我所说的用户对它不满意,它需要安装(除了提取一个档案),还有一个问题,如果用绕道修补程序在EULA的条款下是有效的。所以,这个选择已经过时了。

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

    然后我需要我的dll来加载CG框架和运行时(它依赖于OpenGL)以及其他一些东西。当CG加载时,它调用了我的一些函数,这些函数调用CG函数,我倾向于得到堆栈溢出和无限循环。我需要能够在子目录中包含CG DLL,并且仍然使用它们的功能(不确定是否可以让我的DLL导入表指向子目录中的DLL),或者需要动态链接它们(我宁愿不这样做,只是为了简化构建过程),一些强制它们引用系统的文件(而不是我的客户替换汤姆)。

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

    怎么做? 编辑: 怎么做呢 容易地 不使用GetProcAddress?如果别的都不起作用,我愿意回到过去,但如果可能的话,我宁愿不这样做。

    编辑2: 我刚刚在msdn文档中偶然发现了函数setdllddirectory(在完全无关的搜索中)。乍一看,这正是我需要的。是这样吗?还是我判断错误?(现在开始测试)

    EdTe3: 我通过做一些不同的事情来解决这个问题。我没有删除opengl32.dll,而是将自己的dll重命名为dinput.dll。它不仅具有必须导出一个函数而不是超过120个函数的优点(对于程序、CG和GLEW),而且不必担心函数重新运行(我可以像往常一样链接到OpenGL)。为了进入我需要拦截的电话,我在绕道而行。总之,它工作得更好。尽管如此,这个问题仍然是一个有趣的问题(并且希望对将来试图做疯狂事情的任何人都有用)。两个答案都很好,所以我还不确定该选哪一个…

    2 回复  |  直到 14 年前
        1
  •  1
  •   Rob Kennedy    14 年前

    可能是setdllddirectory 不会 工作。cg.dll可能只是链接到opengl.dll。当操作系统加载cg.dll时,会发现已经有一个模块加载了这个名称(您的),因此它将cg与这个名称链接起来,而不是去寻找其他副本。也就是说,setdllddirectory修改的搜索顺序甚至不会起作用,因为操作系统不进行任何搜索。

    我怀疑你最好的办法是检测到你图书馆的再入者呼叫。当您检测到一个调用时,不要进行自定义处理,而是将调用直接转发到真正的OpenGL库,因为调用了LoadLibrary,所以您可以引用该库,然后针对每个库的函数使用getProcAddress。

        2
  •  1
  •   Chris Becke    14 年前

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

    很大程度上取决于系统中的第三方组件是否已经有清单-以及篡改这些清单的程度可能构成许可证违规。

    为了解决DLL版本控制问题,WindowsXP采用了一种称为激活上下文的技术。有时被称为并排装配,甚至是可怕的 Application Isolation

    把大量的阅读总结成一个小空间: 清单是可以描述程序集或对程序集的依赖关系的XML数据块。程序集是清单及其dll。

    之所以存在,是因为程序集可以采用简单的dll。”comctl32.dll”及其版本号(v6),并创建一个更大、更唯一的名称,这样简单dll的多个版本就可以安全地安装在同一位置。组件将安装在 C:\Windows\WinSxS .

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

    当清单文件描述dll或exe使用的程序集时,它称为应用程序清单,通常嵌入为rt_清单资源-在res id为1的exes中,在res id为2的dll中-或在磁盘上作为名为“appname.exe.manifest”/“dll name.dll.2.manifest”的文件。 应用程序清单定义了一个称为激活上下文的东西——它基本上是一个Windows将搜索的名称空间。 每个清单都创建一个激活上下文。每个激活上下文都有一个简单的dll名称到程序集的映射。

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

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

    所以你必须为 每一个 尚未嵌入的dll,请确保不引用opengl32.dll程序集,该程序集应允许还原为默认搜索顺序并在正常system32位置找到该程序集。

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

    我们通过系统在搜索程序集时采用的相当简单的搜索顺序来保存。首先,它在WinSx中搜索。您的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.
    

    嗯,祝你好运?