AARDvarks in your code - [2004-08-12]
这篇是早期Windows与DOS互相折磨的故事。我完全没有折腾过早期Windows 3.0的内部细节,所以对该文中所述技术细节无法有效翻译,但我推测得出大致意思。
先说一下背景,早期Windows并不是独立的OS,它需要在DOS上启动。当Windows团队遇上一个问题时,他们非常不讲究解决方式。Windows假设它是整个系统的上帝,它知道底层DOS系统的内部数据结构,它知道这些结构的位置和大小,它毫不犹豫地在内存中用Windows的某种实现替换这些DOS内部结构。不用说,从DOS开发人员的角度看,让Windows跑起来绝对是场噩梦。
举个简单例子,Windows启动时会增加DOS内部数据结构SFT的大小,以允许Windows同时打开20个以上的文件,多任务操作系统都有这种需求。正常情况下应该通过修改config.sys中的FILES=来增加SFT的大小,但Windows选择调用一个DOS未文档化的API,该API返回一个指针,该指针指向一组"有趣"的DOS内部指针,后者中有一个正是指向SFT的指针,然后Windows用自己的SFT替换了DOS的SFT。
我开发MS-DOS 4.0时,为了让Windows跑起来,不得不修改DOS加载器以监控win.com的加载,获取win.com在内存中的加载基址后,我需要对一个特定偏移处的Windows代码进行热Patch,以便让Windows能正确替换新版DOS的SFT,用Hacking满足Hacking。
由于上层的Windows高度依赖底层的DOS,所以Windows很担心运行在一个不适配的DOS上。过去Windows中含有一段称为AARD的代码,用于检测底层DOS是否是预期的原装货,如果不是就禁止启动Windows。Windows 3.1发布时,AARD的功能被取消了,但有残余代码留在Windows中。上个世纪90年代初期,Andrew Schulman通过逆向工程发现了AARD的残像,对之进行了非常彻底的剖析。Andrew指出,AARD代码被混淆过,还做了反调试处理,但Andrew仍然成功地进行了逆向工程。
我不知道为什么AARD代码要做混淆处理,对我来说,这很愚蠢。但我必须说,我完全认同AARD的初衷。Windows实际上做了很多重大假设,它直接操作DOS内部数据结构,它假设知道DOS内部函数如何工作,何时可以安全地调用它们,哪些函数是可重入的,哪些是不可重入的,它假设了DOS运作的方方面面。设想允许Windows在一个非预期原装版DOS上运行,它那些关于DOS的重大假设不一定成立,此时Windows将以神秘诡异的方式失败,应用程序可能会丢失数据,Windows可能会损坏磁盘。
鉴于Windows对DOS所做精细脑部手术的复杂度,Windows检查一下自己是否正在正确的术者身上操作并非没有道理。