请看一段在驱动中判断PE文件格式的代码(代码很乱,勿喷):
pBaseADDR 是文件映射到内存之后的地址.
__try
{
[COLOR="Red"] ProbeForRead((PVOID)(dosheader->e_lfanew+(LONG)pBaseADDR),sizeof(IMAGE_NT_SIGNATURE),1);
if(MmIsAddressValid((PVOID)(dosheader->e_lfanew+(LONG)pBaseADDR)))[/COLOR]
{
if( *(DWORD*)(dosheader->e_lfanew+(LONG)pBaseADDR) != IMAGE_NT_SIGNATURE )
{
KdPrint(("不是PE文件(NT_SIGNATURE) %wZ\n",&nameInfo->Name));
}
}else{
KdPrint(("MmIsAddressValid error(IMAGE_NT_SIGNATURE):%wZ\n",&nameInfo->Name));
}
}__except(EXCEPTION_EXECUTE_HANDLER)
{
KdPrint(("ProbeForRead error(IMAGE_NT_SIGNATURE)\n"));
}
这段代码是为了检测PE文件NT头开始的4字节是不是"PE00", 如果是正常的32位PE文件,没有什么问题.但是如果是16位的PE文件,DOS头的e_lfanew字段,很可能是一个极大的数值(比文件尺寸还大),这个时候如果不加判断,直接读取这个位置的数据,直接蓝屏.
所以我加了一句ProbeForRead, 但是,加了这一句并不能避免因为e_lfanew过大而导致的蓝屏,即使e_lfanew比整个文件尺寸还大,他都没有抛出异常.但是如果访问的话,会蓝屏.
所以又加了一句MmIsAddressValid,加了这句之后,可以避免蓝屏.
但是有时候,虽然e_lfanew的数值很大,但是pBaseADDR加上e_lfanew,还处于我们映射的文件范围之内,实际上是可以读取的,但是MmIsAddressValid返回了"假".
XPSP3系统中windows目录下winhelp.exe,这是个16位的程序,如果按照32位PE文件的结构来看,它的e_lfanew值为1E00, 而这个文件的大小是0x3FDF0, 1E00是在文件映射内存的范围之内的,是可以读取的,但是mmisvalidaddress返回假.
从MSDN上看到的说明是:
mmisvalidaddress 仅检测内核地址是否会发生缺页,同时不推荐使用这个函数.
ProbeForRead 会确保内存地址是有效的且在用户空间中.
这样看的话, mmisvalidaddress 返回假 可以理解,可能是因为会发生缺页.
system32文件夹下,有一个dosx.exe,也是个16位的程序,按照32位PE格式来解析,e_lfanew为0x1A688F07,但是实际上这个文件的大小才0XD260, 这样读取会出错,但是ProbeForRead却没有抛出异常.
这种情况下,有什么办法能准确检测指定内存是否可读呢?
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课