在VISTA 和WINDOWS 7 (ALL SP,全补丁)的内核代码完整性校验组件中,存在一处解析PE的BUG,可引发系统蓝屏。不过从现在看来,此问题似乎需要LoadDriver权限才能触发,因此不能算安全性问题,属于稳定性问题。
在VISTA以后的操作系统,系统使用MmLoadSystemImage加载驱动之前,会调用MmCheckSystemImage函数来检查镜像正确性,在VISTA及以后的操作系统中,MmCheckSystemImage发生了一个有意思的变化.
原本MmCheckSystemImage(vista以前的系统上),会使用SEC_IMAGE作为AllocationAttributes来调用ZwCreateSection为驱动文件创建Section,但是VISTA以后的系统上,该参数被换成了一个未公开的值: 0x100000(注意,SEC_IMAGE是0x1000000,6个0)。
在ZwCreateSection 中,系统会检查如果调用线程的上个模式不是KernelMode,则不允许使用这个未公开的AllocationAttributes:
代码:
NtCreateSection: ............无关部分........ //取当前线程上个模式 if (KeGetPreviousMode() != KernelMode) { //如果是用户模式,如果Attributes有0x2000000或0x10000的话,则返回无效参数 v13 = 0; if ( !(Attributes & 0x2100000) ) { .....无关处理.... } return STATUS_INVALID_PARAMETER_6; }
接着系统会调用SeValidateImageHeader函数,这个函数只是简单地为_g_CiCallbacks中存放的函数准备函数,便调用_g_CiCallbacks存放的函数。_g_CiCallbacks这个全局变量中存放着系统初始化时(SeInitSystem->SepInitializationPhase1->SepInitializeCodeIntegrity)存入的 ci.dll的CiValidateImageHeader函数。
CiValidateImageHeader首先会对镜像进行一些检查工作,然后开始调用CipValidateFileHash函数,CipValidateFileHash函数对文件做一些解析工作后,开始调用CipImageGetImageHash,此函数会分析PE的每一个节,并对其节内数据调用SHA签名算法函数A_SHAUpdate。
注意前面加粗的文字,由于是按整页数来分配和COPY数据的,因此如果某一个节的数据长度(SizeOfRawData)超出了页对齐的范围(MiMapImageInSystemCache似乎并不将这个数据算成一个新的节),那么A_SHAUpdate中的数据COPY函数将触及到未分配内存,从而引发BSOD。
这里提供一个简单的例子.bsodxx.rar
这个PE文件的最后一个节的SizeOfRawData是0x1004,使用任意一个加载工具加载此文件,系统将立即BSOD,BSOD时的Stack类似:
代码:
kd> kc nt!MmAccessFault nt!KiTrap0E nt!memcpy CI!A_SHAUpdate CI!CipImageGetImageHash CI!CipValidateFileHash CI!CiValidateImageHeader nt!SeValidateImageHeader nt!MiValidateImageHeader nt!MmCreateSection nt!NtCreateSection nt!KiFastCallEntry nt!ZwCreateSection nt!MmCheckSystemImage nt!MiCreateSectionForDriver nt!MiObtainSectionForDriver nt!MmLoadSystemImage nt!IopLoadDriver nt!IopLoadUnloadDriver