也谈用Bochs调试NTLDR
今天聊点启动扇区的小玩意~ 关于用 Bochs 启动 / 调试 Win32 的 Ntldr。
其实这是一个很老的话题了,早在我上大二的时候,绿盟的 tk前辈 就在文章《用Bochs调试NTLDR》中有过一定的尝试。不过,如果仅仅是为了调试 252KB 大小的 Ntldr 就创建出 500MB 的虚拟硬盘文件似乎显得大材小用了些;而真正在 Bochs 上用“NT安装光盘的ISO文件”或“直接用光盘安装”调试 Win32 内核又一定会让你有一种奔向黑洞的感觉... 所以我们还是以小为美,写个软盘引导扇区的代码作为桩吧~
等到真正去写这段代码的时候,一个 BIOS INT13 调用上的 Bug 却花了我将近一个下午的时间用 Bochs 单步调试,这占到了整个研究时间的1/3,而且过程非常郁闷。由此也可见汇编语言和调试技术相辅相成的关系及重要性 —— 而这正是 Advdbg.org 一直以来所强调的。
关于编码:
软盘 FAT12/16 文件系统的文档、资料多的满天飞,写代码实际是不困难的。回想一下只有两个小地方需要留点意:(1) LBA 到 CHS 的转换;(2) FAT12 的 FATEntry (文件链表) 拼接。
-- 关于前者,这个问题实际可转化为“IMB当年是如何定义磁盘写入顺序的?” —— 您只需牢记“CHS”就是进位的原则即可(S -> H -> C)。
-- 关于后者,这是个依赖文件系统特性,随文件系统变化而变化的问题。以 FAT12 为例,奇数 FATEntry 和偶数 FATEntry 的拼接方法是不一样的。和偶数的直接 0xFFFh Mask 操作相比,奇数 FATEntry 需要先 SHR 一下,以过滤一些无用信息。
关于截图:
(1) NTLDR 选用 Win32-XP SP2 下的。
(2) 程序在 25*80 字符模式下启动 NTLDR,每加载一个扇区打印一个“.”号,所以您可以轻易计算出图中 NTLDR 的大小。
PS: 关于25*80 字符模式:
00(00h) 79(4fh)
00(00h)┏━━━━━━━━━━━━━━━━┓
┃ ┃
┃ ┃
┃ ┃
┃ 显示器 25*80 显示方式 ┃
┃ ┃
┃ ┃
┃ ┃
24(18h)┗━━━━━━━━━━━━━━━━┛

(3) 调试 NTLDR。如您所见 NTLDR 被我加载到基址 4000:0000h 开始处,由于没有处理 NtDetect.com 等模块,所以这里的调试也只是部分调试。

NUPT WANGyu