虫趣:除0引起的崩溃
【作者:张佩】【原文: http://www.yiiyee.cn/Blog/0x7f-1/】
内核之所以脆弱,是因为它没有办法很好地隔离自己。它是一个大整体,属于一荣俱荣、一损俱损的大整体。它需要一切都按部就班地执行有序。否则,一个角落里的蝴蝶扇动翅膀,就能招来太平洋上的绝大风暴。现在看到的是一个内核中的除0错误。用户程序中的除零导致进程崩溃,内核中则系统崩溃。
int AlwaysDivide (int par0) { Return random (100)/par0; }
上面这个无意义的函数代码,写得很不慎重。如果输入参数par0为0的话,程序就崩溃了。Windbg的自动分析命令能够很好地检测这个类型错误:
0: kd> !analyze -v ******************************************************************************* * * * Bugcheck Analysis * * * ******************************************************************************* UNEXPECTED_KERNEL_MODE_TRAP (7f) This means a trap occurred in kernel mode, and it's a trap of a kind that the kernel isn't allowed to have/catch (bound trap) or that is always instant death (double fault). The first number in the bugcheck params is the number of the trap (8 = double fault, etc) Consult an Intel x86 family manual to learn more about what these traps are. Here is a *portion* of those codes: If kv shows a taskGate use .tss on the part before the colon, then kv. Else if kv shows a trapframe use .trap on that value Else .trap on the appropriate frame will show where the trap was taken (on x86, this will be the ebp that goes with the procedure KiTrap) Endif kb will then show the corrected stack. Arguments: Arg1: 00000000, EXCEPTION_DIVIDED_BY_ZERO Arg2: 00000000 Arg3: 00000000 Arg4: 00000000 Debugging Details: ------------------ BUGCHECK_STR: 0x7f_0 TRAP_FRAME: 8969b7e0 -- (.trap 0xffffffff8969b7e0) ErrCode = 00000000 eax=0000000a ebx=982834fc ecx=00000000 edx=00000000 esi=8991d698 edi=00000000 eip=a780dcb3 esp=8969b854 ebp=8969b874 iopl=0 nv up ei pl zr na pe nc cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00010246 a780dcb3 f7f9 idiv eax,ecx Resetting default scope DEFAULT_BUCKET_ID: WIN7_DRIVER_FAULT PROCESS_NAME: svchost.exe CURRENT_IRQL: 2 LAST_CONTROL_TRANSFER: from 82efdd53 to 82e99768
上面自动分析文字中,红色字体醒目地指出了错误类型是除零错误:EXCEPTION_DIVIDED_BY_ZERO。
出现异常时候的一条指令是:idiv eax,ecx,此时ecx的值是0。构成了典型的除零异常。这个BSOD的描述符是UNEXPECTED_KERNEL_MODE_TRAP。当一个异常发生的时候,系统根据异常类型,调用异常处理函数。除零异常的异常号是0:
0: kd> !idt 0 Dumping IDT: 80b95400 00: 82e5d670 nt!KiTrap00
因为这个异常是无法恢复的,所以异常处理函数最终会调用KeBugCheck2函数令系统崩溃:
STACK_TEXT: 8969b3ac 82efdd53 00000003 a93950d9 00000065 nt!RtlpBreakWithStatusInstruction 8969b3fc 82efe851 00000003 a780dcb3 8991d698 nt!KiBugCheckDebugBreak+0x1c 8969b7c0 82e5d6fb 0000007f 00000000 00000000 nt!KeBugCheck2+0x68b 8969b7c0 a780dcb3 0000007f 00000000 00000000 nt!KiTrap00+0x8b