科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网安全频道评估Vista内核模式的安全性

评估Vista内核模式的安全性

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

如果上述的签名过程不匹配,但是调试器在开启状态(BlBdDebuggerEnabled returns TRUE),那么在这里会打印处如下的调试信息:如果调试器是存在的,那么可以通过调用DbgBreakPoint来进行激活;另外,在这里通过调用ReportCodeIntegrityFailure替换了系统提示致命错误的错误形式。

来源:比特网论坛 2008年11月12日

关键字:

  • 评论
  • 分享微博
  • 分享邮件

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

  [1]驱动签名

  [2]PatchGuard

  [3]内核模式代码完整性检查

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

  [5]限制用户模式访问DevicePhysicalMemory

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

  A、What’s Covered

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

  B、What’s Not Covered

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

  C、必要条件

  由于无法访问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版本的内核改动进行研究。

  Windows Vista Boot 管理

  Windows Vista支持从PC/AT BIOS和Intel新的EFI(可扩展固件接口)启动。我们的分析过程忽略了EFI部分。在本章节的最后部分,引用了bootmgr入口点的开始指令(DllMail为EFI的入口点指令,offset 0为PC/AT的入口点指令)这个过程从Vista启动管理器开始,定位%SystemDrive%ootmgr 文件 (for PC/AT legacy BIOS)或%SystemDrive%BootEFIootmgr.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配置文件如下:

  partition

  e-

  current

  application

  如果只有一个启动入口在BCD文件内,启动管理器会直接从该入口启动。如果多于一个启动入口,Boot Manager会给用户一个可选择的列表,并提示用户选择启动那个OS。如果启动阶段激活了日志记录,启动管理器会把状态信息写入%SystemDrive%Bootootstat.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)的指令。

  A typical BCD entry for the Windows Vista OS Loader looks like this:

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

  current

  partition

  Path

  e-

  application

  policy

  integrity

  processor

  Firmware

  initialization

  information

  Kernel

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

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

  For Full Volume Encryption

  callback

  dd offset _BlockIoEnumerateDeviceClass@12 ; BlockIoEnumerateDeviceClass(x,x,x)

  dd offset _BlockIoReadUsingCache@16 ; BlockIoReadUsingCache(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 _UdpEnumerateDeviceClass@12 ; UdpEnumerateDeviceClass(x,x,x)

  dd offset _ConsoleGetInformation@8 ; ConsoleGetInformation(x,x)

  dd offset _ConsoleSetInformation@8 ; ConsoleSetInformation(x,x)

  serialport

  dd offset _UdpEnumerateDeviceClass@12 ; UdpEnumerateDeviceClass(x,x,x)

  dd offset _UdpEnumerateDeviceClass@12 ; UdpEnumerateDeviceClass(x,x,x)

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

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

  Process

  Thread

  +0x060 ConfigurationRoot : Ptr64 to struct _CONFIGURATION_COMPONENT_DATA

  +0x098 ArcDiskInformation : Ptr64 to struct _ARC_DISK_INFORMATION

  Extension

  Profile

  +0x040 HeadlessLoaderBlock : Ptr64 to struct _HEADLESS_LOADER_BLOCK

  +0x060 NetworkLoaderBlock : Ptr64 to struct _NETWORK_LOADER_BLOCK bytes

  +0x088 LoaderPerformanceData : Ptr64 to struct _LOADER_PERFORMANCE_DATA

  接下来会寻找系统磁盘(通过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} t5.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),那么在这里会打印处如下的调试信息:

  file

  It will be allowed to load because the boot debugger is enabled.

  如果调试器是存在的,那么可以通过调用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调用GetImageValidationFlags来检查在LoadBootImagesTable中预先定义好的boot drivers文件名。如果启用了完整性检查,除非在这里调试器被开启,否则boot drivers必须进行可信任的root权威签名,并且所有的映象哈希值(image hashes)要与编目录签名相匹配。在上面提到调试器开启状态会使该处的完整性检查有些许不同,如果在这里调试器是开启的,WINLOAD.EXE不会强烈要求上面的要求。WINLOAD.EXE会打印一个错误信息给调试器,但是却忽略了代码完整性检查的失败。无论如何,接下来的boot drivers(参考附录A)必须通过代码完整性检查,即使调试器在开启状态也必须检查。(如果没有进行检查,vista不会被启动起来):

  Windowssystem32kdcom.dll (or kd1394.sys or kdusb.dll, depending on boot options)

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

  接下来使用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):

  此时,所有的boot drivers被加载(参考附录B,完整的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 OS Kernel

  Vista使用了与先前版本一样的名门惯例。64位Vista会在%SystemRoot%System32 toskrnl.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进行处理(会在后面部分讨论)。

  推荐文章:

  责任编辑:于捷

    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章