DLL 重新加载到它们的首选地址

Posted

技术标签:

【中文标题】DLL 重新加载到它们的首选地址【英文标题】:DLLs reloaded to their preferred address 【发布时间】:2013-12-04 10:33:28 【问题描述】:

在 Windows Server 2003 上,我的应用程序在全新安装时开始需要很长时间才能加载。怀疑 DLL 没有加载到它们的首选地址,这需要一些时间(应用程序有 100 多个 DLL,包括第 3 方)我运行了 sysinternals listDLLs 实用程序,要求它标记每个已重定位的 dll。奇怪的是,对于列表中的大多数 DLL,我会得到如下内容:

Base        Size      Path
  ### Relocated from base of 0x44e90000:
0x44e90000  0x39000   validation.dll

也就是说:它们被标记为重定位(加载时间似乎肯定支持该理论),但它们的加载地址仍然是首选地址。

一些第三方 DLL 似乎不受此影响,但总的来说,应用程序加载的 DLL 中约有 90% 会出现这种情况。

在 Windows 7 上,似乎唯一被标记的 DLL 是实际移动的 DLL,并且加载时间(如预期的那样)明显更快。

这是什么原因造成的?我怎样才能阻止它?

已编辑:因为它(理论上)听起来像 ASLR 的效果,所以我检查了一下,虽然 OS DLL 确实启用了 ASLR,但我们的却不是。甚至那些也被重新定位,因此不会占用任何其他 DLL 的地址。

【问题讨论】:

【参考方案1】:

非常很常见,设置链接器的 /BASE 选项经常被忽略,并且在 DLL 增长时维护它是一项令人不快的维护任务。这往往不会在操作系统版本之间很好地重复,它们会在您之前加载不同的 DLL,这可能会强制重定位一个而不是另一个。此外,单个重定位可能会导致所有后续 DLL 上的一系列强制重定位。

在现代机器上显着影响加载时间有点遥远。重定位本身非常快,只是一个内存操作。您确实需要为重新定位的 DLL 使用的内存被提交。需要,因为原始 DLL 文件在被换出时不再适合重新加载代码,它现在由分页文件支持。如果它需要增长以适应提交大小,那么这会花费时间。这并不常见。

加载时间中更常见的问题是磁盘驱动器的速度。当您有大量 DLL 时,它们需要在冷启动时位于磁盘上。使用 100 个 DLL,这很容易花费 5 秒。当您没有在您终止程序并重新启动它时看到延迟时,您应该怀疑是冷启动问题。这是一个热启动,DLL 已经存在于文件系统缓存中,因此不必再次找到。解决冷启动问题需要更好的硬件,SSD 很好。或者机器学习您的使用模式,因此 SuperFetch 会在您启动程序之前为您预取 DLL。

无论如何,如果您确实怀疑存在变基问题,那么您需要创建自己的内存映射以找到不会强制重定位的良好基地址。您需要一个良好的起点,了解 DLL 的加载顺序和大小。你可以从 VS 调试器中得到它。 Output 窗口显示加载顺序,Debug + Windows + Modules 窗口显示 DLL 大小。链接器支持在 /BASE 选项中为基地址指定 .txt 文件,这是执行此操作的最佳方法,这样您就不必在代码不断增长的同时不断修改单个 /BASE 值。

【讨论】:

我们为所有的 dll 指定了基地址。 “同样,一次重定位可能会导致所有后续 DLL 上的一系列强制重定位。”就是这样:它们都没有被重定位到不同的地址 - 它们都在 i> 他们的首选地址,如果您相信 Process Explorer 的加载地址(以及上面 listDLLs 输出中的基址)。有些事情需要很长时间,并且 dll 被标记为重新定位,但它们都在 我们要求它们的位置...... 嗯,很好,这个世界是有道理的。显然,您现在将对追求我记录的“更常见的问题”更感兴趣。使用真正的调试器来追踪不稳定的重定位警告。

以上是关于DLL 重新加载到它们的首选地址的主要内容,如果未能解决你的问题,请参考以下文章

PE重定位表

DLLHijack漏洞原理

是否可以让 FORTRAN DLL 每次加载到随机地址?

DLL文件劫持应该怎么办 急啊

DLL 如何处理来自多个进程的并发?

更改地址栏中的完整 URL,无需重新加载页面