



   本书最大的特色在于不从纯理论角度进行介绍,而是以源码与调试相结合来阐释。在ReactOS源码的基础上,剔除掉一些不那么重要,且影响大家整体把握Windows内核设计的部分,修改和整理出一个新的源码版本,通过对这个源码版本用调试工具Bochs和WinDbg进行调试,再结合重点模块的论述,以及关键函数完整详细的分析,使读者能对整个Windows内核框架透彻理解,并能根据自己的想法自由设计操作系统。
以下是书中介绍的读者可能比较感兴趣的知识点:
1.物理内存如何收集?
2.实模式和保护模式如何互相切换?
3.系统中断如何安装?
4.调试系统如何设计?
5.分页机制如何开启?
6.内核模块和启动型驱动如何加载?
7.结构化异常如何为编程语言提供支持?
8.如何为数据结构与算法学习提供支持?
9.物理内存和虚拟内存如何进行管理?
10.内核对象如何设计?
11.I/O管理器如何为驱动程序提供支持?
12.磁盘类驱动和微端口驱动如何读/写数据?
13.文件系统如何设计?缓存怎样提供支持?
14.原型PTE是什么?(section object)如何实现进程间共享?
15.NTDLL.DLL如何映射到进程地址空间?
16.第一个用户进程和线程怎样创建?线程如何切换?
为了使读者能从整体上把握本书讲述的内容,我们先做总体概述,提供一些视图供大家理解,这些视图跟部分章节相关。
本书主要探索的是Windows内核的设计部分,分析内核构架和代码细节。本书编写的理论基础源于ReactOS和WRK,为了保证本书编写的理论正确性,每一部分内容都经过了调试验证。学习流程从MBR(master boot record,即主引导记录)到内核创建的第一个用户进程(smss.exe),图1大体展示了内核初始化的各个阶段。
    图1
1.计算机启动时控制权交给MBR,MBR负责把NTLDR加载到物理内存0x20000。控制权交给NTLDR前半部分SU模块(startup.com)。
2.SU收集物理内存、开启A20、开启保护模式、解析NTLDR文件的后半部分Loader模块(osloader.exe)。解析PE文件格式重定位到物理内存0x00400000。控制权交给Loader模块。
3.Loader模块初始化调试系统,初始化内存管理器,开启分页机制,加载内核模块和启动型驱动程序到内核地址空间。控制权交给ntoskrnl。
4.KiSystemStartup进行内核初始化阶段0:初始化调试系统,初始化Idle进程和线程,初始化内核执行体,初始化HAL系统,初始化内存系统,初始化对象系统,初始化进程系统(创建System进程和线程)。最后这条主线程转到KiIdleLoop成为真正的空闲线程。
5.KiIdleLoop切换Idle线程到System线程执行,进行内核初始化阶段1:初始化HAL系统,初始化对象系统,初始化注册表系统,初始化I/O系统,初始化进程系统,创建第一个用户进程(smss.exe)。最后这条主线程成为零页面线程。
由于内核涉及的内容非常多,因此并不是每一部分都详细讲述,但是经过本书的学习,再去理解那些未讲述的部分,会相对容易得多。
图2是使用ntldr加载运行的WRK v1.2系统界面,物理内存为256MB,硬盘为16MB,调试器为WinDbg,通信端口为COM 1。我们使用的虚拟机是VMware Workstation。
    图2
图3所示是在内核初始化阶段1,函数IoInitSystem初始化启动型驱动程序后的界面。
    图3
系统加载的文件是从“Windows Server 2003 Enterprise Edition Server Pack 1”操作系统里复制过来的。可使用本书编写的简单文件系统ntfs.sys替换原版ntfs.sys。
图4是笔者自己编译的ReactOS的调试运行系统界面,物理内存为256MB,硬盘为16MB,调试器为WinDbg,通信端口为COM 1。通过修改文件boot.asm里面的代码,ntldr加载的就是ReactOS而不是WRK了。我们使用的虚拟机是Bochs。
    图4
图5所示是在内核初始化阶段1,函数IoInitSystem初始化启动型驱动后显示的界面。
    图5
这些驱动程序全部以源码方式编译,可跟踪调试。FASTFAT是我们自已实现的简单文件系统驱动(重新构架)。磁盘类驱动DISK和微端口驱动UNIATA实现了对磁盘数据的读/写支持。通过I/O管理器,弄清楚一个文件如何解析,如何从分区读到内存。
一直跟随ReactOS成长的读者,可以按照下面的操作替换内核模块。从http://sourceforge.net/projects/reactos/files/ReactOS/0.3.15/下载ReactOS-0.3.15-REL-iso.zip,解压安装ReactOS 0.3.15系统,注意虚拟磁盘类型选择IDE(默认是SCSI)。系统安装完成后,虽然ReactOS默认提供了调试器RosDBG.exe可供调试,但是它并不友好,也无法进行源码调试,非常不利于学习。现在我们寻求一种替代方案——WinDbg。我们已经编译好了内核模块ntoskrnl.exe,这个模块自带了kd调试组件,现在我们把ntoskrnl.exe替换原版ReactOS中的ntoskrnl.exe。编辑虚拟机参数:在主界面中单击“Edit virtual machine settings”,弹出如图6所示窗口。
    图6
单击设备“Hard Disk(IDE)”,在右边的“Utilities”下拉菜单中选择“Map”,在弹出的窗口中取消勾选“Open file in read-only mode(recommended)”,单击“OK”按钮确认。这样我们就使用映射的方式打开了ReactOS系统盘。找到目录Z:\ReactOS\system32,把原文件ntoskrnl.exe改名为ntoskrnl2.exe,方便以后我们需要时再改回去。复制我们的ntoskrnl项目生成的文件ntoskrnl.exe(在ntos\Debug目录下)到Z:\ReactOS\system32。复制完成后关闭窗口,再在“Utilities”下拉菜单中选择“Disconnect”,如果弹出提示框,单击“Force Disconnect”。这样就替换了ntoskrnl.exe。如果需要可以通过同样的方式替换生成的启动型驱动程序acpi.sys、pci.sys和disk.sys。说到这里,我们简单提一点,在第2章中,我们讲述到LDFS文件格式,我们也可以使用NTFS文件格式,映射ntos.vmdk到虚拟盘符后,格式成NTFS分区就行。但是这样一来,我们要修改不少代码,MBR代码需要重写,因为需要解析NTFS格式来找到NTLDR。
替换完内核模块后,还需要开启com_1端口用于WinDbg连接通信。启动系统后,在屏幕提示选项中按上下键选择“ReactOS(Debug)”回车,如图7所示。
    图7
等待一小会,WinDbg和ReactOS就连接上了。通过这种方式,我们在学习时可以进行扩展,对不同的模块,可以分块编译后替换,尝试运行,看和原版中的有什么差别,也可以按自已的设计修改部分代码,再编译、链接、运行。这样学习才能对系统的整体构架比较熟悉,理解也会比较深刻。图8所示是在内核初始化阶段1,函数IoInitSystem初始化启动型驱动后显示的界面。
    图8
这里我们能观察到启动型(SERVICE_BOOT_START)驱动的加载和系统初始化阶段型(SERVICE_SYSTEM_START)驱动的加载。
在本书的某些章节中,有些函数相对较长,比如第7 章讲述的查找对象名函数(ObpLookupObjectName)就占用了十几页,书中我们保留了全部的细节,是为了保持函数的完整性,而且一旦读者熟悉了这个函数,整个对象管理器的核心就一目了然了。
在将章节内容整理成书时,难免出现一些错误,有些章节虽然经过了多次修改,也仍然有不如意的地方,读者在阅读时要结合源码调试去理解,以免出现理解偏差。
本书配套资源下载地址:http://www.broadview.com.cn/25314。
本书成书过程中主要参考了Windows Internals,6th Edition(Mark Russinovich、David A.Solomon和Alex lonescu合著,中文版为《深入解析Windows操作系统(第6版)》)和Intel 64 and IA-32 Architectures Software Developer’s Manual。此外,还参考了ReactOS官方网站(http://www.reactos.org)、微软网站(http://www.microsoft.com)、维基百科(http://en.wikipedia.org)及http://www.debuginfo.com/articles/debuginfomatch.html上的一些资料。