【发布时间】:2012-06-24 06:29:45
【问题描述】:
我正在编写我自己的 Windows 加载程序版本(尽管是一个非常简单的版本),到目前为止,一切进展顺利。但是,在递归遍历已加载模块的导入表时,我遇到了一些障碍。
对于大多数依赖项,一切都很好,我可以简单地递归加载模块。但是,对于某些依赖项,这只会破坏目标进程。经过进一步调查,我意识到这是因为 Windows 并行程序集。本质上,加载的 PE 中的依赖项是目标进程中使用的模块的不同 SxS 版本。
在一种情况下,我加载的 DLL 引用了 msvcr90.dll,但目标进程使用的是早期版本的运行时:msvcr71.dll。
现在,windows 加载器可以很好地处理这个问题,所以显然有一个“正确”的方法可以做到这一点。我已经阅读了一些关于 Activation Contexts 的内容,但它们并没有真正帮助我理解这个问题。
调用 LoadLibrary 本身也不会将 dll 解析为正确的版本
LoadLibraryW(L"msvcr90.dll");
只返回0。有谁知道
a) 如何检测导入是否为 SxS 程序集
b) 如何解决导入到正确的 SxS 版本的过程。
我真的很困惑如何做到这一点。我现在从研究中知道大部分 PE 文件格式,但我很确定 SxS 超出了 PE 结构的范围。
如果您需要更多信息,请发表评论。可执行文件没有外部清单,其嵌入式清单没有指定运行时版本。但是,它确实在其工作目录中包含 msvcr71.dll 的副本,如果这对任何人都有帮助的话。
干杯。
【问题讨论】:
-
您只是看到了泰坦尼克号沉没的冰山顶部。您还必须处理作为资源嵌入或在磁盘上提供的清单、发布者策略、绑定重定向、无注册表 COM、通过 CreateActCtx 动态激活、使用 SetDllDirectory 设置的自定义 DLL 搜索路径。文档很糟糕。
-
@HansPassant 我设法让这个工作。你说得对,这只是冰山一角哈哈。最后,我不得不编写一个 Resource Walker 来定位
.dll的内部清单 (RT_MANIFEST)。接下来,我必须编写一个汇编存根来处理所有Activation Context的东西。当然,我可以简单地用 C++ 编写它并将它包装在一个带有静态链接(即没有 SxS)的 .dll 中,然后用它来加载所有下一个库,但这似乎有点过头了,所以我在汇编中做了。基本上,我为汇编函数提供了一个以空分隔的所需依赖项的字符串... -
以及清单的路径(我将内部清单提取到一个临时文件中,
CreateActCtx需要清单的路径)。然后它创建激活上下文,遍历以 null 分隔的模块列表,并在每个模块上调用GetModuleHandle。如果GetModuleHandle返回0,它会继续调用LoadLibrary。如果仍为 0,则退出函数。我知道我通过在Activation Context中简单地使用LoadLibrary跳过了最困难的部分,但我真的只想使用我自己的加载程序来处理主dll,而不是它的依赖项。
标签: c++ windows portable-executable winsxs