本文内容非商业用途可无需授权转载,请务必注明作者、微博ID:唐僧_huangliang,以便更好地与读者互动。
作者简介:
王之业,现就职于Arcserve,任开发经理。长期从事数据备份与恢复领域研发与管理工作,对行业发展高度关注,同时对数据保护与恢复有自己非常独到的见解。
原文地址:http://www.docin.com/p-1843467578.html
Windows 其实可以支持多种引导方式。 除了本地硬盘引导外,还有例如PXE引导、iSCSI引导、RAM Disk引导、VHD引导等。但本文将只关注磁盘引导的方式。
先上一张图。 这个图和上次介绍Grub 2引导过程时展示的图类似。它主要描述了引导过程的每个阶段,以及所涉及磁盘存储的位置、内存地址和CPU模式的情况。
你可能会注意到MBR的内存载入和PBR是一样的。确实如此。MBR中的程序代码将自身从内存0x7C00的位置复制到0x0600的位置,而后把PBR读入到0x7C00。后面有更多相关介绍。BootMgr首先被载入到内存地址0x20000的位置,而它的后半部分(bootmgr.exe)会被重新定位到0x400000的位置。
MBR是磁盘的第一个扇区。其中包含启动代码、磁盘ID,分区表。
有人可能会问,MBR作为从磁盘读上来的第一块数据,为什么要放在内存0x7C00的位置,而不是放在内存的开始处,或者内存的结尾处?其实,在最初设计的时候(30多年前),0x7C00就是内存的结尾处。那时候内存只有32KB大小。而内存开始的位置,一般被用于存放中断向量和BIOS的一些数据。后来,为了保持兼容,这个规则就一直这么延续下来了。
A20地址线是另一个关于“兼容”的故事。A20实际是第21条CPU地址线(计算机的世界里都是从零开始计数的)。它对应的是1MB之后的内存地址。早期的Intel 8086 只能访问1MB的内存。如果内存寻址超出了1MB,就会重新从零开始(相当与取模计算)。当时有些软见就利用这个特性来提高内存访问效率。后续的CPU虽然提高了内存寻址范围,但为了兼容当时的现有软件,不得不在CPU处于实模式的时候,继续模拟8086的行为。遗憾的是,Intel 80286 在出厂后才发现没有处理好这个兼容问题。当时的PC制造商IBM决定自己在主板上解决这个问题:在A20地址线上加个开关,并让它缺省处于关闭状态。估计当时的工程师急于快速解决问题,竟然把对这个开关的控制关联在了主板的键盘控制器上。所以MBR中的代码会通过向键盘控制器的端口发送指令来打开A20地址线。
TCG_CompactHashLogExtendEvent 是TPM规范中定义的例程的名字。MBR代码通过中断INT 1A来调用这个例程。
第一个分区的标志位为0x80,所以是活动分区。MBR代码会读入这个分区的第一个扇区,并继续引导过程。上图中每个分区的类型都为0x07,即NTFS文件系统的分区。当前基于BIOS的引导方式有两种磁盘寻址方法:CHS和LBA。CHS即柱面(Cylinder)、磁头(Head)和扇区(Sector),听起来与磁盘结构强相关,但也是所有硬件都支持的方法;LAB即Logical Block Addressing,从0开始按扇区数量定位磁盘上的数据块。应该说现在的硬件也都支持LBA了,但10多年前生产的设备就不一定了。
最后两个字节即为引导扇区标志位了。
以上是PBR在磁盘上的数据。以下的介绍将以0x100000作为基址。
开头3个字节是一条跳转指令。跳转到0x54继续执行。也就是说0x54后面都是代码了(或者错误信息字符串),除了最后两个字节为引导标志位。从Windows 7到Windows 10,这部分代码总体上变化不大。
从0x03到0x53之间的空间存储了文件系统的重要信息。可以和Linux文件系统的super block相对应。
从0x03到0x0A之间的8个字节为文件系统的标志字符串。这里是NTFS文件系统。没有用完的空间用空格填充。NTFS视整个磁盘卷为固定长度数据块组成的数组。这个“固定长度数据块”被称为cluster。
NTFS将cluster作为磁盘的最小访问单位。Cluster的大小就记录在0x0D的位置。Cluster可以对应为Linux文件系统中的block。
MBR代码在寄存器DL里存储了当前引导磁盘的驱动器号(一般为0x80)。PBR代码把这一信息存储在偏移0x0E(一个字节)对应的内存位置,以供PBR后续代码及Boot Area代码使用。
这里就不一一解释后续的每个字段了。图中特别给出了File Record Segment(MFT中每个文件记录占用的字节数)和Index Block(索引块占用的字节数)的计算方法。特别之处在于如何处理当这些字段为负数的情况。
到此终于要单独介绍一下BitLocker了。前面几乎每一节都有BitLocker的身影。
对于一台计算机来讲,衡量其安全性需要考察两个阶段:在操作系统正常运行之后,可以由操作系统的安全策略(如账户登录,权限控制等)和文件级别的加密来确保用户数据的安全;而在操作系统正常运行之前,就需要像类似于BitLocker这样的功能。它的重要功能之一就是确保操作系统本身是安全的(未被篡改),否则后续的安全的价值都会大打折扣。BitLocker可以用于加密操作系统所在的磁盘卷,也可以用于加密数据磁盘卷。
BitLocker用FVEK加密数据,再用VMK加密FVEK。这样的策略是为了便于更换秘钥。当有更换秘钥的需求时,只需要更换VMK,而FVEK可以保持不变。要知道FVEK的变化意味着需要解密然后重新加密整个磁盘卷,难免要花很长时间。
BitLocker可以利用TPM来提高安全性。引导过程每个阶段的代码(或在固件里,或在磁盘上)都被计算了哈希值,并存于TPM的PCR寄存器里。这些哈希值与TPM内部的秘钥一起被用于解密VMK:只有它们和加密VMK时的值相一致时,才有可能解密成功。这可以阻止引导的早期阶段的安全攻击(在MBR等汇编语言阶段植入恶意程序)。这也意味着硬盘与计算机主板之间的绑定:即使把硬盘拔下来,再插到其他机器上,也是无法解密的。其实,这种方法甚至意味着你对BIOS设置做一点改动,都会导致无法解密。这个时候恢复秘钥就派上用场了。
BitLocker的最高安全策略是用TPM(what it is) USB Key (what you have) PIN(what you know)来保护VMK。当然也可以只以一个口令来保护VMK。Windows缺省的安全策略并不允许在没有TPM支持的情况下使用BitLocker保护系统所在的磁盘卷。如果你很想尝试一下BitLocker但又没有支持TPM的计算机,可以使用gpedit.msc修改如下安全策略,之后就可以使用口令来保护系统所在的磁盘卷了。
BitLocker不仅可以用于本地硬盘卷的加密,还可以用于U盘的加密。
WinLoad.exe一般位于C:WindowsSystem32WinLoad.exe。顺便说一句,你在C:Windows下看到的大多数文件(EXE, dll, MUI等)都是到C:Windowswinsxs里对应文件的硬连接。也就是说这些文件本身被安装在C:Windowswinsxs目录下。Windows用这种方法来解决可执行程序不同模块之间版本的匹配问题。进一步的细节可以在网上搜索一下。
系统注册表文件在引导过程中扮演着非常重要的角色。除了少数一些文件是WinLoad根据内置列表载入之外,其他大部分文件都是根据注册表的配置载入的。
Windows的注册表不仅从外观上看像是文件系统(通过regedit.exe浏览),其内部结构也像是一个文件系统。它把全部空间按4KB分块管理,就像是文件系统的“cluster”。这也是它分配空间的最小单元。文件开头的4KB叫base block,记录了全局重要信息(以字符串“regf”为签名标记),就像是文件系统的引导扇区。一个或多个4KB组成一个Bin,就像是文件系统的“run”或“extent”。Bin可以被认为是cell的容器。它的开头为32字节的头部信息(以字符串“hbin”为签名标记),紧随其后就是一个或多个cell。一个cell包括4字节的长度信息和变长的数据信息。Cell用于存储单个key,或value,或注册表中的其他对象。当然,用了一段时间之后,注册表文件也会像文件系统那样出现碎片。
除BCD外,Windows系统的注册表文件都存在于C:WindowsSystem32config目录下。如果你开启了“显示隐藏文件”功能,你会发现每个注册表文件都伴随有多个日志文件。这些日志文件用于确保注册表更新后保持数据一致性。Windows每隔5秒钟将内存中对注册表的修改刷新到日志文件,然后再将日志的内容刷新的注册表文件中。如果在刷新注册表文件过程中出现系统故障,可以在系统重启后根据日志文件从头再次刷新。
WinLoad实际上会载入两个注册表文件: SYSTEM 和 ELAM(从Windows 8开始)。前者用于保存系统配置,后者是那些需要早期载入的反病毒驱动程序的配置(早期载入以监控引导型驱动程序)。WinLoad会将这两个注册表文件整个读入内存(所以他们的大小是有限制的)。然后,如果需要的话,根据日志重新刷新内存中的注册表(WinLoad是不会写注册表的)。
Ntoskrnl.exe即是Windows内核程序。HAL.dll名字的含义为Hardware Abstraction Layer,是内核用于跟硬件交互的函数库。每种硬件平台会有自己的HAL.dll。CI.dll用于代码完整性校验;PSSHED.dll是一个与硬件错误报告相关的动态库;BootVID.dll用于支持VGA显示模式。还有其他一些文件,这里没有都列出来。
WinLoad会验证它载入的程序的数字签名。它会将每个程序的签名和存在于硬盘上的catalog文件(C:WindowsSystem32catroot目录下)中的标准签名进行对比。如果比较失败,就停止引导,打印错误信息以及出问题的文件的名字。为了确保catalog文件没有被修改过,WinLoad还需要验证catalog文件的数字签名。而用于验证的公钥证书就内置在WinLoad文件内部。WinLoad自身的数字签名可以被BootMgr验证,所以不用担心有人修改WinLoad的代码绕过这些验证。
bootstat.dat文件在这里再次出现,只是这次它是在C:Windows目录下。这个文件会被WinLoad、内核以及第一个用户态程序smss.exe共享使用。它的作用是让WinLoad了解上次引导(或关机)的情况,以决定是否显示对应的选项(系统修复、安全模式等)。它的格式和BootMgr的那个bootstat.dat文件基本相同,只是在64KB的前面加了一段长度为0x800字节的数据。所以它的大小固定为66KB。目前还不清楚这额外0x800字节的用途。
注:本文只代表作者个人观点,与任何组织机构无关,如有错误和不足之处欢迎在留言中批评指正。进一步交流技术,可以加我的QQ/微信:490834312。如果您想在这个公众号上分享自己的技术干货,也欢迎联系我:)
尊重知识,转载时请保留全文。感谢您的阅读和支持!《企业存储技术》微信公众号:huangliang_storage
原文链接:http://mp.weixin.qq.com/s?__biz=MzAwODExNjI3NA==&mid=2649775489&idx=1&sn=d8f460a7273255cd27e4778c6dacf6fa&chksm=83773cdcb400b5ca368a9e4c3e8510273fe906dce8d72e7c4e9da475f25bd5ba54507f5fdf8d#rd