前言
本章讲述了Microsoft Windows操作系统中四种基本的机制,它们对于系统的管理和配置至关重要,它们是:
- 注册表
- 服务
- 统一的背景进程管理器
- Windows管理设施
- Windows诊断基础设施
4.1 注册表
注册表在Windows系统的配置和控制方面扮演了一个非常关键的角色。
- 它既是系统全局设置的存储仓库,(HKLM等根键)
- 也是每个用户的设置信息的存储仓库。(HKU,HKCU等根键)
虽然大多数人都把注册表想象成存储在磁盘上的静态数据
,
但是,在这一节中你将会看到,注册表也是Windows执行体和内核所维护的各种内存中数据结构的一个窗口
。
我们首先从总体上介绍注册表的结构,并讨论一下它所支持的数据类型,简要地浏览一下Windows在注册表中维护的关键信息。然后,我们进一步讨论配置管理器( Configuration Manager)的内部机理。
这里的配置管理器是负责实现注册表数据库的执行体组件。我们将会涉及的话题有:
- 注册表在磁盘上的内部结构、
- 当一个应用程序请求配置信息时Windows如何获得相应的信息
- 以及Windows采用了哪些手段来保护这一关键的系统数据库。
查看和修改注册表
一般来说,你应该永远不需要直接编辑注册表:
- 如果存储在注册表中的应用程序设置和系统设置需要手工修改,那么,它们应该有一个对应的用户界面来控制其修改。
然而,正如你在本书中已经多次看到过的那样,有些高级设置和调试设置并没有相应的编辑用户界面。因此,Windows中包含了图形用户界面(GUI)和命令行工具,用于查看和修改注册表。
Windows随带了一个主要的GUI工具可用于编辑注册表,Regedit.exe
,还有一些命令行注册表工具。例如,Reg.exe
具有导入、导出、备份和恢复注册表键的能力,也可以比较、修改和删除注册表键和值。它也可以设置或者查询在UAC虚拟化中所用到的各种标记。而Regini.exe
则允许你根据一个包括ASCII或Unicode配置数据的文本文件来导入注册表数据.
WDK (Windows DriverKit)也提供了一个可以再分发的组件:Offreg.dll,称为离线注册表库
。通过该库,可以以二进制格式来加载注册表储巢文件,以及在这些储巢文件上应用各种操作,因而绕过了Windows所要求的常规注册表操作的逻辑:
- 先加载、再映射的过程。
这种用法主要是为了帮助离线访问注册表,比如出于完整性检查或有效性检查的目的
。如果底层的数据不必对系统可见的话,这种用法还可以获得性能上的优势,因为对数据的访问是通过本地文件I/O来完成,而不是通过注册表系统调用来完成的。
注册表用法
配置数据主要在四个时间点上被读取:
在初始的引导过程中
,引导加载器读入配置数据和引导设备驱动程序的列表,以便在初始化内核以前将它们加载到内存中。因为BCD(引导配置数据库,BootConfiguration Database)实际上存放在注册表储巢中,有人可能会争辩说,对注册表的访问发生在更早的时候(当引导管理器显示操作系统列表的时候)。在内核引导过程中
,内核读取有关的设置信息,这些设置信息指定了应该加载哪些设备驱动程序,以及各个系统部件(比如内存管理器和进程管理器(process manager))该如何配置以及该如何调整系统的行为。在登录过程中
,Explorer和其他的Windows组件从注册表中读取到每个用户的参数选择,包括网络驱动器字母映射、桌面墙纸、屏幕保护程序、菜单行为和图标的摆放,以及可能更重要的是,哪些启动程序需要激发起来,以及哪些文件最近被访问过。在应用程序启动过程中
,它们读取系统全局范围的设置,比如所有可选安装的组件列表和许可数据,还读取一些针对每个用户的设置信息,可能包括菜单和工具栏的摆放,以及最近访问过的文档的列表。
然而,在其他时间点上也可以读取注册表,比如在响应注册表值或键的修改的时候
。
注册表提供了异步回调机制,这是优先采用的接收注册表变化通知的方法,尽管如此,仍然有些应用程序会通过不停查询的做法,来监视它们存放在注册表中的设置信息,以便自动地让更新过的设置信息起作用。然而,一般来说,在一个空闲的系统上,注册表不应该有任何活动,显然这样的应用程序违反了注册表的最佳实践原则。(Sysinternals的Process Monitor是一个追查这种活动和错误应用程序的极佳工具。)
在下面的情形下,注册表通常会被修改:
- 虽然算不上是修改,但是,注册表的初始结构和许多默认设置是由一个原型版本的注册表来定义的,此原型版本随Windows的安装介质一起发行,
在安装的时候被拷贝到一个新的系统中
。 应用安装工具创建了默认的应用程序设置
,以及一些可反映出安装配置选项的设置信息。在设备驱动程序的安装过程中
,即插即用系统在注册表中创建了一些设置,告诉I/O管理器如何启动此驱动程序;
还创建了其他一些用于配置该驱动程序如何操作的设置(有关设备驱动程序如何被安装到系统中的更多信息,参见本书下册第8章“I/O系统”)。当你通过用户界面改变了应用程序或者系统设置时
,这些改变通常被保存在注册表中。
注册表数据类型
注册表是一个数据库,其结构类似于磁盘卷的结构。注册表包含了键(key)和值( value)。键类似于磁盘的目录,而值则好比是磁盘上的文件。键是一个容器,可以包含其他的键(子键)或值。而值存储的是数据。最顶级的键是根键(root key)。在本节中,我们将相互交换着使用子键和键这两个词。
键和值两者都借用了文件系统的命名规范。因此,可以用名称“trade\mark”唯一标识一个存储在名为“trade”的键下面的、名为“mark”的值。此命名方案的一个例外是,每个键都有一个未命名的值。Regedit将未命名的值显示为“(默认)”。
注册表的值存储了不同种类的数据,它们可以是表4.1中所列出的12种类型之一。大多数注册表值是REG_DWORD、REG_BINARY或REG_Sz。REG_DWORD类型的值可以存储整数或者布尔值(开/关值);REG_BINARY值可以存储超过32位的整数值,或者诸如加密后的口令之类的原始数据;REG_Sz值存储字符串(当然是Unicode),可以表达诸如名称、文件名、路径和类型等元素。
REG_LINK类型特别值得注意,因为它让一个键可以透明地指向另一个键。当你搜索注册表而碰到一个链接时,路经搜索过程会在此链接的目标处继续进行。例如,如果\Root1\Link是一个指向\Root2\RegKey的REG_LINK值,并且RegKey包含了值RegValue,那么,可以有两条路径标识RegValue:\Root1\Link\RegValue和\Root2(RegKey\RegValue
。
正如下一小节将要解释的那样,Windows自己也显式地使用了注册表链接:
- 六个注册表根键中有三个其实是链接,它们指向另三个非链接的根键中的子键。
注册表逻辑结构
利用注册表中存储的数据,你可以画出注册表的组织结构。
总共有6个根键(你不能加入新的根键,也不能删除已有的根键)可以存储信息,如表4.2所示。
为什么根键的名称都以“H”开头?因为根键的名称代表了指向键(KEY)的Windows句柄(H)。正如第1章“”中所提及的那样,HKLM是用于HKEY_LOCAL_MACHINE的缩写。表4.3列出了所有的根键以及它们的缩写。下面的几小节详细地解释了这六个根键中每一个根键的内容和用途。
HKEY_CURRENT_USER
HKCU根键包含了与当前本地登录用户的参数和软件配置有关的数据。它指向当前登录用户的用户轮廓,位于硬盘上的\Users<用户名>\Ntuser.dat中(要想知道根键是如何被映射到硬盘文件的,请参见本章后面的“注册表的内部机理”一节)。无论何时当一个用户的轮廓信息被加载的时候(比如在登录时候,或者当一个服务进程运行在某个特定用户名的环境中时),HKCU就会被创建出来,映射到HKEY_USERS下该用户的键上。
表4.4列出了HKCU下面的一些子键。
HKEY_USERS
HKU为系统中每个加载的用户轮廓和用户类注册数据库包含了一个子键。它也包含一个名为HKU\DEFAULT的子键;这是一个链接,指向该系统的轮廓(对于那些运行在本地系统账户下的进程,它们会用到该轮廓信息;本章后面的“服务”一节中更加详细地讲述了有关该轮廓的信息)。譬如,这是Winlogon使用的轮廓,所以,改变了该轮廓中的桌面背景设置,就可以在登录屏幕上体现出来。当一个用户第一次登录到一个系统中,并且他的账户不依赖于一个漫游域轮廓(也就是说,用户的轮廓是在域控制器的指示下,从一个中心网络位置上获得的)的时候,系统以%SystemDrive%\Users\Default
下存放的轮廓为基础,为她的账户创建一个轮廓。
系统将这些轮廓存储在哪里呢?
此位置是由注册表值HKLM\Software\Microsoft\WindowsNT\CurrentVersion\ProfileList\ProfilesDirectory
来定义的,其默认设置是%SystemDrive%\Users。ProfileList键也存放了一个系统上所有出现过的轮廓的列表。针对每个轮廓的信息存放在一个对应的子键下面,其名称反映了该轮廓所对应账户的安全标识符(SID,Security ldentifier)(有关SID的更多信息,参见第6章“安全性”)。在每个轮廓的键所存储的数据中,sid值中存放的是该账户SID的二进制表示,而在ProfilelmagePath目录中存放的则是该轮廓所对应的储巢( hive,参见本章后面的“储巢”一节中的介绍)的硬盘路径。Windows在用户轮廓管理对话框中显示了一个系统中存储的轮廓列表,如图4.1所示。你只需在控制面板的System小程序的AdvancedSystem Settings中的Advanced标签视图的User Profiles部分单击Setting,就可以看到该对话框。
HKEY_CLASSES_ROOT
HKCR包含了三种类型的信息:
- 文件扩展名关联
- COM类注册信息
- 以及UAC(User AccountControl)虚拟化注册表根。(关于UAC的更多信息,请参见第6章。)
针对每个已注册的文件扩展名,都有一个对应的键。大多数键中包含一个REG_Sz值,指向HKCR中的另一个键,此键中包含了与该扩展名所代表的文件类相关联的信息。
例如,HKCR.xls指向了在另一个键(比如HKCU.xls\Excel.Sheet.8)中包含的有关MicrosoftExcel文件的信息。HKCR中其他的键包含了已注册到当前系统上的COM对象的详细配置信息。UAC虚拟化注册表位于VirtualStore键下,它与HKCR中保存的其他种类的数据没有关系。
HKEY_CLASSES_ROOT下的数据有以下两个来源途径:
- 针对每个用户的类注册数据:位于HKCU\SOFTWARE\Classes下(被映射至磁盘文件
\Users<username>\AppData\Local\Microsoft\Windows\Usrclass.dat)。 - 整个系统范围的类注册数据:位于HKLM\SOFTWARE\Classes下。
针对每个用户的注册数据为什么要与系统全局范围的注册数据分开呢,其原因在于,这样做以后,可漫游的轮廓就能够包含这些定制的用户数据。它同时也关闭了一个安全漏洞:非特权用户无法改变或者删除系统全局版本HKEY_CLAsSES_ROOT中的键,因此也就无法影响到系统中应用程序的操作。非特权用户和应用程序可以读取系统全局范围的数据,也可以在系统全局数据中增加新的键和值(在它们的用户数据中这些键和值也被镜像过来了),但是它们只能修改其私有数据中已有的键和值。
HKEY_LOCAL_MACHINE
根键HKLM包含了所有系统全局范围的配置子键:BCDO0000000、COMPONENTS(根据需要动态加载)、HARDWARE、SAM、SECURITY、SOFTWARE和SYSTEM。
HKLM\BCDO0000000子键包含了引导配置数据库(BCD)信息,这是作为一个注册表储巢被加载进来的。该数据库代替了以前在Windows Vista以前使用的Boot.ini文件,为每次安装Windows的引导配置数据增加了极大的灵活性和隔离性。(有关BCD的更多信息,请参考本书下册第13章“启动和停机”。)
在BCD中的每一项,比如一次安装的Windows,或者针对这一次安装的命令行设置,都保存在Objects子键下,它或者是一个可通过GUID来引用的对象(针对引导项的情形),或者是一个称为元素(element)的数值子键。这些原始元素,绝大多数在MSDN Library的BCD参考材料部分有文档描述,它们定义了各种命令行设置或者引导参数。与每个元素子键相关联的值对应于相应的命令行标记或者引导参数的值。
BCDEdit命令行工具使得你可以通过元素和对象的符号名称来修改BCD。它也提供了关于所有可用的引导选项的大量帮助信息;不幸的是,它只能工作在本地系统环境中。因为注册表可以被远程打开,也可以从储巢文件中导入进来,所以,你可以利用注册表编辑器来修改或读取一台远程计算机的BCD。下面的实验显示了你可以利用注册表编辑器来打开内核调试功能。
子键HKLM\COMPONENTS
包含的信息与CBS(Component Based Servicing
,基于组件的服务)栈有关。此CBSs栈包含了各种文件和资源,它们是Windows安装映像(用于自动化的安装包或者OEM预安装包)的一部分,或者是一次活动的Windows安装的一部分。为了服务目的而定义的CBS AP利用此注册表键中的信息来标识出已安装的组件和它们的配置信息。无论何时当单独地或者成组地安装、更新或者移除组件(分别称为单元unit或包package)时,这些信息都会被用到。因为该键可能会非常大,所以,为了优化系统资源,如果CBs栈在服务一个请求时,它只是被动态地加载到系统中,然后根据需要被卸载。
子键HKLM\HARDWARE维护了有关当前系统中的遗留硬件,以及一些从硬件设备至驱动程序的映射关系的描述信息。在现代系统上,只有一些外设,比如键盘、鼠标和ACPIBIOS数据,有可能在这里能找得到。设备管理器工具(从控制面板中运行System小程序,然后单击DeviceManager〉使你可以查看注册表硬件信息,这些信息只是简单地从HARDWARE键中读取出来的值(尽管它主要使用了HKLM\SYSTEM\CurrentControlSet\Enum树)。
HKLM\SAM存放了本地账户和组的信息,比如用户口令、组定义和域关联信息。作为域控制器运行的Windows Server系统将域账户和组的信息存放在活动目录(Active Directory)中。所谓活动目录,是一个用于存放域范围的各种设置和信息的数据库(本书并没有介绍活动目录)。在默认情况下,SAM键上的安全描述符被配置成:即使管理员账户也不能访问。
HKLM\SECURITY存放了系统全局范围的安全策略和用户权限分配。HKLM\SAM被链接到HKLM\SECURITY\SAM下的SECURITY子键。在默认情况下,你不能查看HKLM\SECURITY或者HKLM\SAM\SAM键的内容,因为这些键的安全设置只允许System账户才能访问(本章后面将会极其详细地讨论System账户)。如果你想要检查这些键的话,你可以改变此安全描述符,以便允许管理员组中的用户可以读访问这些键,或者,你可以利用PsExec,在本地系统账户中运行Regedit。然而,仅仅看一眼这些数据是不会有多大用处的,因为这些数据是没有文档说明的,其中的口令已经通过一个单向映射关系加了密,也就是说,你是无法从加密形式得到一个口令的。
HKLM\SOFTWARE是Windows存储系统全局配置信息的地方,这些配置信息在系统引导的时候并不需要。而且,第三方应用程序也将它们的系统全局范围的设置存放在这里,比如应用程序文件和目录的路径、授权许可信息和过期日期信息。
HKLM\SYSTEM包含了引导系统所需要的全局配置信息,比如该加载哪些设备驱动程序、该启动哪些服务。因为这些信息对于启动系统是至关重要的,所以,Windows也在该键下维护了这份信息的一份拷贝,称为“last known good control set(最后已知的好控制集)”。由于维护了这样一份拷贝,因此,万一对当前控制集做了修改以后,系统无法正常引导了,管理员可以选择以前的一份正常工作的控制集。关于Windows何时声明当前控制集是“好”的,更详细的信息请参见本章“接受当前引导和最后已知的好控制集”一节。