日期:2014-05-17  浏览次数:20756 次

[转载]Windows 机密:利用 EmulateHeap 还原早期内存行为
Windows 机密:利用 EmulateHeap 还原早期内存行为
Raymond Chen

应用程序兼容性工具包中提供了一项极其简单而又非常疯狂的兼容性行为:EmulateHeap。

如果您对进程启用此兼容性修复措施,则所有操作系统级的堆函数(从 HeapCreate 到 LocalLock 再到 GlobalReAlloc,以及其间的所有函数)都会重定向到替代函数,从而彻底模拟 Windows 95 堆。

例如,您可能有一个程序,该程序先分配两个内存块,再释放它们,然后分配第三个内存块,而您可以依赖于第三次分配所返回的指针与第一次分配所返回的指针在数值上相等的事实,因为在 Windows 95 上就是这样的。

您可能有一个程序,该程序会使堆缓冲区溢出,而不会造成任何严重后果,因为堆缓冲区之后的内存未用于其他任何用途,至少在 Windows 95 上是这样的。

您可能还会运行一个程序,该程序将释放内存,随后可能再次访问其释放的内存,并希望该内存仍然包含在其释放时所写入的值,并且没有被其他任何内存分配所重用,或者至少在 Windows 95 上没有被重用。(也许更可怕的是,该程序依赖于在释放内存后对该内存以非常特殊的方式更改的值!)

在旧版应用程序中,有一大堆很小的与此类似的奇特依赖性。编程人员并非特意采用这种方式对这些应用程序进行编码;这些行为不过是散布在各处的小错误,而由于程序在与 Windows 95 堆管理器联合运行时,这些错误凑巧没有引起问题,因此就蒙混过关了。但是,当这些程序在其他任何版本的 Windows 上运行时,它们就会崩溃,因为其他版本的 Windows 拥有不同的堆管理器。

因此,这并不能说明 Windows 95 堆管理器比其他版本“更好”或“更强大”。不过是不一样罢了。很可能只是因为有很多行为在 Windows 95 应该造成崩溃而实际上没有造成崩溃,所以在 Windows 7 上也要努力避免崩溃。您看到的效果不过是自我选择的结果:如果您在 1995 年编写了一个程序,而这个程序在 Windows 95 上会造成崩溃,您一定会注意到这个问题并将其修复,因为 Windows 95 是您的目标平台!

如果对进程启用 EmulateHeap 兼容性修复措施,堆管理器的行为就会变得完全与 1995 年的行为相匹配。所有会在 Windows 95 上发生的巧合 - 那些应用程序无意中所依赖的巧合 - 再次强制出现了,这使得包含这种错误的应用程序能够继续按照与以前完全相同的方式运行。提醒您,强制实现所有巧合还意味着必须关闭新的堆特性(例如减少碎片),因为这些特性可能会改变应用程序所依赖的巧合。

以上解释了为什么此项行为是简单的。

而此项行为还是疯狂的,其原因在于:应用程序兼容性人员为了尽量完美地模拟 Windows 95 堆管理器而采取的方式 - 他们直接复制了一份 Windows 95 堆管理器的源代码,重新编译,然后将其加入兼容性基础结构中。换句话说,在 Windows 应用程序兼容性框架中有一大块 Windows 95 内核的副本。虽然不是 Microsoft Bob 的完整副本,但是在这种情况下,这段从 Windows 95 中原封不动复制过来的代码仍然是不稳定因素;如果对进程启用了 EmulateHeap 兼容性修复措施,则这段古老的代码就会从硬盘加载到内存中,并且真的开始执行工作!

Windows 7 有一个新的容错堆子系统,该系统试图检测多种简单的应用程序堆内存错误并自动应用补救措施。例如,容错堆会检测并更正重复释放、堆缓冲区溢出(至少是少量溢出)以及在释放后再使用内存(至少是在释放之后的短时间内再次使用它)。这种更通用的解决方案有望使下一版 Windows 中不再需要在其兼容性基础结构文件中包含一个 Windows 7 堆管理器的副本。

原文链接: http://technet.microsoft.com/zh-cn/magazine/ff625273.aspx