1

评估Vista系统内核模式安全性_深入底层

来源:网络 作者:微雨花间 0

评估Vista系统内核模式安全性_深入底层

Windows Vista与之前的MS Windows版本(包括Windows XP SP2)相比增加了很多的安全性。Vista新安全性的特征可以包括以下几个方面:

驱动签名

路径保护

内核模式代码完整性检查

可选择支持使用TPM芯片的安全启动

限制用户模式访问DevicePhysicalMemory

上述的这些功能使得Vista64位版本与Linux或MacOS相比更具备安全性。该文档的主要贡献在:通过拟向工程较全面的分析内核模式的安全组件以及评估可能存在的内核模式攻击。

该文档检查新的安全特性,通过这些安全特性来阻止恶意代码危及内核。由于这些特性都仅存在于64位的Windows Vista系统内,因此该文档的关注点在Vista64位版本。

该文档没有分析PatchGuard的执行,针对PatchGuard的分析在前期已经有Skape和Skywing[6]进行了较全面的分析,值得注意的是PatchGuard发展到目前已经有所改变(在skape与skywing分析完后)。仅当下面章节对PatchGuard进行攻击评估时才会讨论这些问题。针对Vista用户模式的安全性评估在前面已经有所讨论[7]。

由于无法访问Windows Vista的源代码,我们通过debugger(调试器)、disassembler(反编译)、hex editor(16进制编辑器,例如UE)学习了Windows Vista Community Technical PrevIEw (CTP) Build 5365版本。如果读者不熟悉X86体系架构和汇编语言的知识,推荐大家一本不错的关于X86汇编语言的在线图书[8]。另外,在看该文档前你需要熟悉一些Windows系统架构的知识,推荐大家阅读[9],该书讲解了Windows系统架构的知识,同时这本书的一些知识同样可以应用到Vista系统上。在该文档公布时Vista系统还在测试阶段,但Vista在后来版本的安全性方面又做了一些改动。我们希望Vista在最终的发布版本上有更多的改变,同时我们也计划继续对未来的Vista版本的内核改动进行研究。

Vista引导过程

Windows Vista支持从PC/AT BIOS和Intel新的EFI(可扩展固件接口)启动。我们的分析过程忽略了EFI部分。在本章节的最后部分,引用了bootmgr入口点的开始指令(DllMail为EFI的入口点指令,offset 0为PC/AT的入口点指令)这个过程从Vista启动管理器开始,定位%SystemDrive%bootmgr 文件 (for PC/AT legacy BIOS)或%SystemDrive%BootEFIbootmgr.efi (for EFI BIOS)。Vista Boot Manager是启动Vista的必须环节,但也适用于启动Windows Vista之前的Windows版本。

Vista Boot Manager首先调用InitializeLibrary,然后依次调用BlpArchInitialize (GDT, IDT, etc.), BlMmInitialize (memory management), BlpFwInitialize (firmware=固件?), BlpTpmInitialize (TPM), BlpIoInitialize (file systems), BlpPltInitialize (PCI configuration), BlBdInitialize (debugging), BlDisplayInitialize, BlpResourceInitialize (finds its own .rsrc section), and BlNetInitialize。

在Vista系统内,Windows传统的boot.ini配置文件已经被启动配置数据文件(BCD)所代替,Vista下该文件位于%SystemDrive%BootBCD,该文件也是注册表的值(在Vista下被挂载在HKEY_LOCAL_MACHINEBCD00000000下)。可以使用bcdedit.exe来查看该文件的内容。

一个典型的Boot Manager的BCD配置文件如下:

Windows;Boot;Manager Identifier:;{bootmgr} Type:;10100002 Device:;partition=C: Description:;Windows;Boot;Manager Locale:;en-US Inherit;options:;{globalsettings} Boot;debugger:;No Pre-boot;EMS;Enabled:;No Default:;{current} Resume;application:;{3ced334e-a0a5-11da-8c2b-cbb6baaeea6d} Display;order:;{current} Timeout:;30

如果只有一个启动入口在BCD文件内,启动管理器会直接从该入口启动。如果多于一个启动入口,Boot Manager会给用户一个可选择的列表,并提示用户选择启动那个OS。如果启动阶段激活了日志记录,启动管理器会把状态信息写入%SystemDrive%Bootbootstat.dat文件内(通过BmpInitializeBootStatusDataLog)。紧接着启动管理器会使用BlResourceFindHTML把bootmgr.xsl定位在资源节点,而后把它传给BlXmiInitialize。bootmgr.xsl文件控制启动菜单和位于启动菜单的选项。

如果启动列表的某个条目被选择,跟随BmpTransferExecution之后,将使用BmpLaunchBootEntry对该条目进行加载。BmpTransferExecution将重新找回启动选项(通过BlGetBootOptionString)并把他们交给BlImgLoadBootApplication。如果FVE(Full Volume Encryption)被激活,BlFveSecureBootUnlockBootDevice和 BlFveSecureBootCheckpointBootApp将被调用。由于Windows分区被加密,必须在把控制权交给Vista OS Loader前对分区进行解密。

最后,Boot Manager调用BlImgStartBootApplication把控制权交给Vista OS Loader。

Windows Vista操作系统加载

bootmgr调用了位于%SystemRoot%System32WINLOAD.EXE下的Vista OS Loader。WINLOAD.EXE替换了NTLDR(Windows NT OS Loader),该小节的最后部分,会引用WINLOAD.EXE在开始入口点(OslMain)的指令。

一个典型的Vista OS载入的BCD入口配置文件如下:

Windows;Boot;Loader IdentifIEr:;{current} Type:;10200003 Device:;partition=C: SYMANTEC;ADVANCED;THREAT;RESEARCH;3 Path:;Windowssystem32WINLOAD.EXE Description:;Microsoft;Windows Locale:;en-US Inherit;options:;{bootloadersettings} Boot;debugger:;No Pre-boot;EMS;Enabled:;No Advanced;options:;No Options;editor:;No Windows;device:;partition=C: Windows;root:;Windows Resume;application:;{3ced334e-a0a5-11da-8c2b-cbb6baaeea6d} No;Execute;policy:;OptIn Detect;HAL:;No No;integrity;checks:;No Disable;boot;display:;No Boot;processor;only:;No Firmware;PCI;settings:;No Log;initialization:;No OS;boot;information:;No Kernel;debugger:;No HAL;breakpoint:;No EMS;enabled;in;OS:;No

执行从OslMain开始。它重用了与bootmgr阶段相同的代码,因此InitializeLibrary在bootmgr内的工作原理与在WINLOAD.EXE内的工作原理相似。在InitializeLibrary之后,控制权交给OslMain。

如果启动状态日志记录被激活,WINLOAD.EXE将会把结果写入%SystemDrive%Bootbootstat.dat (通过 OslpInitializeBootStatusDataLog和OslpSetBootStatusData)。接下来WINLOAD.EXE调用OslDisplayInitialize,并使用BlResourceFindHTML定位osloader.xsl所在的资源节点。控制权转交给BlXmiInitialize。在系统启动过程中osloader.xsl控制着高级启动选项。在操作完高级启动选项(使用OslDisplayAdvancedOptionsProcess),WINLOAD.EXE现在就准备开始启动。启动阶段首先会使用BlDeviceOpen打开启动设备。根据设备类型,BlDeviceOpen会使用不同的设备函数集来打开设备。

全盘加密(_FvebDeviceFunctionTable) 如下:

dd;0;;;FVE;has;no;EnumerateDeviceClass;callback dd;offset;_FvebOpen@8;;;FvebOpen(x,x) dd;offset;_FvebClose@4;;;FvebClose(x) dd;offset;_FvebRead@16;;;FvebRead(x,x,x,x) dd;offset;_FvebWrite@16;;;FvebWrite(x,x,x,x) dd;offset;_FvebGetInformation@8;;;FvebGetInformation(x,x) dd;offset;_FvebSetInformation@8;;;FvebSetInformation(x,x) dd;offset;_FvebReset@4;;;FvebReset(x) For;block;I/O;(_BlockIoDeviceFunctionTable);these;are: dd;offset;_BlockIoEnumerateDeviceClass@12;;;BlockIoEnumerateDeviceClass(x,x,x) dd;offset;_BlockIoOpen@8;;;BlockIoOpen(x,;x) dd;offset;_BlockIoClose@4;;;BlockIoClose(x) dd;offset;_BlockIoReadUsingCache@16;;;BlockIoReadUsingCache(x,x,x,x) dd;offset;_BlockIoWrite@16;;;BlockIoWrite(x,x,x,x) dd;offset;_BlockIoGetInformation@8;;;BlockIoGetInformation(x,x) dd;offset;_BlockIoSetInformation@8;;;BlockIoSetInformation(x,x) dd;offset;?handleInputChar@OsxmlMeter@@UAEHG@Z;;;OsxmlMeter::handleInputChar(ushort) dd;offset;_BlockIoCreate@12;;;BlockIoCreate(x,x,x) For;console;(_ConsoleDeviceFunctionTable);these;are: dd;offset;_UdpEnumerateDeviceClass@12;;;UdpEnumerateDeviceClass(x,x,x) dd;offset;_ConsoleOpen@8;;;ConsoleOpen(x,x) dd;offset;_ConsoleClose@4;;;ConsoleClose(x) dd;offset;_ConsoleRead@16;;;ConsoleRead(x,x,x,x) dd;offset;_ConsoleWrite@16;;;ConsoleWrite(x,x,x,x) dd;offset;_ConsoleGetInformation@8;;;ConsoleGetInformation(x,x) dd;offset;_ConsoleSetInformation@8;;;ConsoleSetInformation(x,x) dd;offset;_ConsoleReset@4;;;ConsoleReset(x) For;serial;port;(_SerialPortFunctionTable);these;are: dd;offset;_UdpEnumerateDeviceClass@12;;;UdpEnumerateDeviceClass(x,x,x) dd;offset;_SpClose@4;;;SpClose(x) dd;offset;_SpRead@16;;;SpRead(x,x,x,x) dd;offset;_SpWrite@16;;;SpWrite(x,x,x,x) dd;offset;_SpGetInformation@8;;;SpGetInformation(x,x) dd;offset;_SpSetInformation@8;;;SpSetInformation(x,x) dd;offset;_SpReset@4;;;SpReset(x) For;PXE;(_UdpFunctionTable): dd;offset;_UdpEnumerateDeviceClass@12;;;UdpEnumerateDeviceClass(x,x,x) dd;offset;_UdpOpen@8;;;UdpOpen(x,x) dd;offset;_SpClose@4;;;SpClose(x) dd;offset;_UdpRead@16;;;UdpRead(x,x,x,x) dd;offset;_UdpWrite@16;;;UdpWrite(x,x,x,x) dd;offset;_UdpGetInformation@8;;;UdpGetInformation(x,x) dd;offset;_UdpSetInformation@8;;;UdpSetInformation(x,x) dd;offset;_UdpReset@4;;;UdpReset(x)

你可能注意到有些函数的返回在不同类别之间会存在共享(例如:serial port和PXE)。

接着LOADER_PARAMETER_BLOCK结构通过OslInitializeLoaderBlock进行初始化,LOADER_PARAMETER_BLOCK包含了一些系统状态信息,如:启动设备、ACPI、SMBIOS表等。下面为LOADER_PARAMETER_BLOCK在Vista64位版本的结构:

+0x000;LoadOrderListHead;:;struct;_LIST_ENTRY +0x010;MemoryDescriptorListHead;:;struct;_LIST_ENTRY +0x020;BootDriverListHead;:;struct;_LIST_ENTRY +0x030;KernelStack;:;Uint8B +0x038;Prcb;:;Uint8B +0x040;Process;:;Uint8B +0x048;Thread;:;Uint8B +0x050;RegistryLength;:;Uint4B +0x058;RegistryBase;:;Ptr64;to;Void +0x060;ConfigurationRoot;:;Ptr64;to;struct;_CONFIGURATION_COMPONENT_DATA +0x068;ArcBootDeviceName;:;Ptr64;to;Char +0x070;ArcHalDeviceName;:;Ptr64;to;Char +0x078;NtBootPathName;:;Ptr64;to;Char +0x080;NtHalPathName;:;Ptr64;to;Char +0x088;LoadOptions;:;Ptr64;to;Char +0x090;NlsData;:;Ptr64;to;struct;_NLS_DATA_BLOCK +0x098;ArcDiskInformation;:;Ptr64;to;struct;_ARC_DISK_INFORMATION +0x0a0;OemFontFile;:;Ptr64;to;Void +0x0a8;SetupLoaderBlock;:;Ptr64;to;struct;_SETUP_LOADER_BLOCK +0x0b0;Extension;:;Ptr64;to;struct;_LOADER_PARAMETER_EXTENSION +0x000;Size;:;Uint4B +0x004;Profile;:;struct;_PROFILE_PARAMETER_BLOCK +0x014;MajorVersion;:;Uint4B +0x018;MinorVersion;:;Uint4B +0x020;EmInfFileImage;:;Ptr64;to;Void +0x028;EmInfFileSize;:;Uint4B +0x030;TriageDumpBlock;:;Ptr64;to;Void +0x038;LoaderPagesSpanned;:;Uint4B +0x040;HeadlessLoaderBlock;:;Ptr64;to;struct;_HEADLESS_LOADER_BLOCK +0x048;SMBiosEPSHeader;:;Ptr64;to;struct;_SMBIOS_TABLE_HEADER +0x050;DrvDBImage;:;Ptr64;to;Void +0x058;DrvDBSize;:;Uint4B +0x060;NetworkLoaderBlock;:;Ptr64;to;struct;_NETWORK_LOADER_BLOCK;bytes +0x068;FirmwareDescriptorListHead;:;struct;_LIST_ENTRY +0x078;AcpiTable;:;Ptr64;to;Void +0x080;AcpiTableSize;:;Uint4B +0x084;BootViaWinload;:;Bitfield;Pos;0,;1;Bit +0x084;BootViaEFI;:;Bitfield;Pos;1,;1;Bit +0x084;Reserved;:;Bitfield;Pos;2,;30;Bits +0x088;LoaderPerformanceData;:;Ptr64;to;struct;_LOADER_PERFORMANCE_DATA +0x090;BootApplicationPersistentData;:;struct;_LIST_ENTRY +0x0a0;WmdTestResult;:;Ptr64;to;Void +0x0a8;BootIdentifier;:;struct;_GUID +0x0b8;u;:;union +0x000;I386;:;struct;_I386_LOADER_BLOCK +0x000;CommonDataArea;:;Ptr64;to;Void +0x008;MachineType;:;Uint4B +0x00c;VirtualBias;:;Uint4B

下面会寻找系统磁盘(通过OslEnumerateDisks)和加载系统注册表项HKEY_LOCAL_MACHINE(通过OslpLoadSystemHive)。当系统注册表项加载后,我们遇到了Vista在启动阶段的第一次代码完整性(通过OslInitializeCodeIntegrity)。在该处首先会调用MincrypL_SelfTest,MincrypL_SelfTest验证SHA1散列值,并使PKCS1的签名验证开始工作(using a pre-defined test case=通过预定义的测试样例?)。如果预先定义的测试样例失败了,会返回错误代码到0xC0000428。然后,检查调试器是否开启(通过BlBdDebuggerEnabled)。如果在这里检测到调试器在开启状态,会调用KnownAnswerTest。如果没有检测到调试器处在开启状态,会直接跳过该处。

接下来通过BlImgRegisterCodeIntegrityCatalogs从%SystemRoot%System32CatRoot{F750E6C3-38EE-11D1-85E5-00C04FC295EE}nt5.cat加载OS的编目录(在内部调用了API函数MinCrypL_AddCatalog)。

当OS 编目录 nt5.cat被加载后,WINLOAD.EXE通过SelfIntegrityCheck对其自身进行完整性检查,这里的检查做了两个事情:

1. 计算PE映像(image)的SHA1哈希值,然后与PE证书表内的SHA1哈希值进行对比,这里的对比必须是匹配的,如果不匹配就会返回一个错误信息。

2. 另外,他也调用ImgpValidateImageHash来验证映象(image)哈希值是否与nt5.cat内的相匹配。ImgpValidateImageHash会调用API函数MinCrypL_CheckSignedFile来验证证书,调用MinCrypL_CheckImageHash来寻找nt5.cat上的映象(image)匹配哈希值。在下面的章节III会讨论通过MinCrypL_CheckSignedFile和 MinCrypL_CheckImageHash进行驱动签名验证。

如果上述的签名过程不匹配,但是调试器在开启状态(BlBdDebuggerEnabled returns TRUE),那么在这里会打印处如下的调试信息:

***;Windows;is;unable;to;verify;the;signature;of;the;file;%s. It;will;be;allowed;to;load;because;the;boot;debugger;is;enabled. Use;g;to;continue!!

如果调试器是存在的,那么可以通过调用DbgBreakPoint来进行激活;另外,在这里通过调用ReportCodeIntegrityFailure替换了系统提示致命错误的错误形式。

当所有的完整性检查结束后(unless all integrity checks have been disabled),OslInitializeCodeIntegrity会返回成功状态,然后会继续从OslMain开始执行。接着,OslpLoadAllModules被调用并开始加载系统模块。首先,会调用OslLoadImage来加载NTOSKRNL.EXE和HAL.DLL,在这里仅仅是加载,此时没有解决Imports;第二,如果内核调试被开启,调试驱动会依靠启动调试选项的情况被加载(kdcom.dll for serial port, kd1394.dll for IEEE1394, or kdusb.dll for USB)。第三,NTOSKRNL.EXE的Imports被加载和初始化(使用LoadImports和BindImportRefences函数)。

OslLoadImage calls GetImageValidationFlags to check the filename against a pre-defined list of boot drivers in LoadBootImagesTable. If integrity checks are enabled, then boot drivers must be signed by a trusted root authority and all the image hashes must match the signed catalog file unless a debugger is enabled. If a debugger is enabled, WINLOAD.EXE does not enforce this requirement. Instead it will print an error message to the debugger, but will otherwise ignore the code integrity check failure. However, the following boot drivers (also listed in Appendix A) must pass the code integrity checks even if a debugger is enabled (otherwise WINLOAD.EXE will refuse to boot Windows Vista):

OslLoadImage调用GetImageValidationFlags来检查在LoadBootImagesTable中预先定义好的boot drivers文件名。如果启用了完整性检查,除非在这里调试器被开启,否则boot drivers必须进行可信任的root签名,并且所有的映象哈希值(image hashes)要与编目录签名相匹配。如果调试器处于开启状态,WINLOAD.EXE不会强制这些要求。安全后WINLOAD.EXE会打印一个错误信息给调试器,但是却忽略了代码完整性检查的失败。无论如何,接下来的boot drivers必须通过代码完整性检查,即使调试器在开启状态也必须检查。(如果没有进行检查,vista不会被启动起来):

Windowssystem32bootvid.dll Windowssystem32ci.dll Windowssystem32clfs.sys Windowssystem32hal.dll Windowssystem32kdcom.dll;(or;kd1394.sys;or;kdusb.dll,;depending;on;boot;options) Windowssystem32ntoskrnl.exe Windowssystem32pshed.dll Windowssystem32WINLOAD.EXE Windowssystem32driversksecdd.sys Windowssystem32driversspldr.sys Windowssystem32driverstpm.sys

加载映象和验证代码完整性都在BlImgLoadPEImageEx内,都使用了SelfIntegrityCheck(在前面章节有描述)函数。所有的映象(image)都通过代码完整性校验后,NTOSKRNL.EXE和它所有的Imports此时会被加载。列表(版本:Build 5363)如下:

Windowssystem32NTOSKRNL.exe Windowssystem32HAL.dll Windowssystem32PSHED.dll Windowssystem32BOOTVID.dll Windowssystem32CLFS.SYS Windowssystem32CI.dll

接下来使用OslHiveFindDrivers查找所有的boot drivers,并且根据组(which is ordered according to HKEY_LOCAL_MacHINECurrentControlSetControlGroupOrderList)和标记(an integer which determines each driver’s order within its respective group)对他们进行分类。这个分类好的boot drivers列表通过OslLoadDrivers进行加载。OslLoadDrivers为列表中的每个驱动调用LoadImageEx。LoadImageEx将会加载每个驱动及相关信息。

此时,剩余的boot drivers也被加载和初始化。列表如下(按照年月日排列,64位Vista):

1.;Windowssystem32driversWdf01000.sys 2.;Windowssystem32driversWDFLDR.SYS 3.;Windowssystem32driversacpi.sys 4.;Windowssystem32driversWMILIB.SYS 5.;Windowssystem32driversmsisadrv.sys 6.;Windowssystem32driverspci.sys 7.;Windowssystem32driversvolmgr.sys 8.;Windowssystem32driversisapnp.sys 9.;Windowssystem32driversmpio.sys 10.;Windowssystem32driverscompbatt.sys 11.;Windowssystem32driversBATTC.SYS 12.;WindowsSystem32driversmountmgr.sys 13.;Windowssystem32driversintelide.sys 14.;Windowssystem32driversPCIIDEX.SYS 15.;Windowssystem32driverspcmcia.sys 16.;Windowssystem32driversaliide.sys 17.;Windowssystem32driversamdide.sys 18.;Windowssystem32driverscmdide.sys 19.;Windowssystem32driversmsdsm.sys 20.;Windowssystem32driverspciide.sys 21.;Windowssystem32driversviaide.sys 22.;WindowsSystem32driversvolmgrx.sys 23.;Windowssystem32driversatapi.sys 24.;Windowssystem32driversataport.SYS 25.;Windowssystem32drivershpcisss.sys 26.;Windowssystem32driversstorport.sys 27.;Windowssystem32driversadp94xx.sys 28.;Windowssystem32driversadpu160m.sys 29.;Windowssystem32driversSCSIPORT.SYS 30.;Windowssystem32driversadpu320.sys 31.;Windowssystem32driversdjsvs.sys 32.;Windowssystem32driversarc.sys 33.;Windowssystem32driversarcsas.sys 34.;Windowssystem32driverselxstor.sys 35.;Windowssystem32driversi2omp.sys 36.;Windowssystem32driversiirsp.sys 37.;Windowssystem32driversiteraid.sys 38.;Windowssystem32driverslsi_fc.sys 39.;Windowssystem32driverslsi_sas.sys 40.;Windowssystem32driverslsi_scsi.sys 41.;Windowssystem32driversmegasas.sys 42.;Windowssystem32driversmraid35x.sys 43.;Windowssystem32driversmsahci.sys 44.;Windowssystem32driversnfrd960.sys 45.;Windowssystem32driversql2300.sys 46.;Windowssystem32driversql40xx.sys 47.;Windowssystem32driverssisraid2.sys 48.;Windowssystem32driverssisraid4.sys 49.;Windowssystem32driverssymc8xx.sys 50.;Windowssystem32driverssym_hi.sys 51.;Windowssystem32driverssym_u3.sys 52.;Windowssystem32driversvsmraid.sys 53.;Windowssystem32driversfltmgr.sys 54.;Windowssystem32driversfileinfo.sys 55.;Windowssystem32driversndis.sys 56.;Windowssystem32driversmsrpc.sys 57.;Windowssystem32driversNETIO.SYS 58.;WindowsSystem32DriversNtfs.sys

此时,所有的boot drivers被加载。接下来,调用OslpLoadNlsData从注册表项HKEY_LOCAL_MACHINECurrentControlSetControlNLS加载操作系统的语言版本。最后调用OslpLoadAllModules做了下面的几个事情:

1. 显示Vista启动过程中的进度条。

2. 加载%SystemRoot%AppPatchdrvmain.sdb(the application compatability database)

3. 加载%SystemRoot%System32acpitabl.dat

4. 加载HKEY_LOCAL_MACHINECurrentControlSetControlErrataInfName注册表项的INF文件。

在OslpLoadAllModules结束后,OslMain保存启动日志(OslpLogSaveInformation),如果FVE(Full Volume Encryption)选项开启,结束FVE的加载(BlFveSecureBootRestrictToOne and BlTpmShutdown)。最后,调用OslArchTransferToKernel把控制权转交给NTOSKRNL.EXE。

Vista Windows系统内核

Vista使用了与先前版本一样的惯例。64位Vista会在%SystemRoot%System32ntoskrnl.exe查找NTOSKRNL.EXE,在本章节的剩余部分,会引用ntoskrnl.exe在开始入口点的操作指令(KiSystemStartup)。

执行首先从KiSystemStartup开始。Vista下的NTOSKRNL.EXE内的一些重要部分与Windows 2003 SP1版相比,并没有太多的改变,因此我们的重点为分析Vista下改变的特殊部分。在Vista下,NTOSKRNL.EXE添加了一个新函数SepInitializeCodeIntegrity,但该函数仅仅是把CL.DLL内的CiInitialize(关于CiInitialize会在后面的章节VI进行讨论)进行了另外的包装而已。如果代码完整性检查开启,SepInitializeCodeIntegrity会调用CiInitialize,除此之外,它没有做任何其它的事情。

WINLOAD.EXE还负责检查boot drivers签名的完整性。与WINLOAD.EXE相比,NTOSKRNL.EXE负责查证system drivers(在boot driver加载后)和运行时加载的drivers(即:当一个设备被插进系统)。当完整性检查开启,会使用SeValidateImageHeader(在CI.DLL内CiValidateImageHeader函数的包装)和SeValidateImageData(在CI.DLL内CiValidateImageData函数的包装)对加载的映象(image)进行代码完整性检查。只要一个执行映射进kernel memeory都会调用SeValidateImageHeader(通过MmCreateSection)。当一个内核模块加载时,都会调用SeValidateImageData对kernel drivers的代码段进行校验。运行时检查(例如:不断的检查kernel drivers的代码段是否被修改)由PatchGuard和CI.DLL进行处理。