【作者:张佩】【原文: http://www.yiiyee.cn/Blog/bsod-0x3b-1/】
这是一个BSOD 0x3B的dump文件,BSOD 0x3B所代表错误的描述是:SYSTEM_SERVICE_EXCEPTION,表示在一个系统线程里面发生了不可解决的系统异常,导致的系统错误。
系统线程是一个笼统的概念,凡是通过内核函数IoCreateSystemThread创建的线程,都是系统线程。内核是一个混沌的整体,内核里面不存在进程的概念。但是它却需要分配一些独立执行的任务,线程是执行这些独立任务的最佳载体。但是线程必须依附在进程中。为了解决这种矛盾,系统专门创建了一个SYSTEM进程,这个进程没有用户模式的代码,专门作为内核线程的载体存在。系统为SYTEM进程分配固定的进程号4。在Windbg内核调试会话中运行命令!process 4将列印SYSTEM进程信息:
0: kd> !process 4 0 Searching for Process with Cid == 4 Cid handle table at fffff8a000004e80 with 754 entries in use PROCESS fffffa8003699040 SessionId: none Cid: 0004 Peb: 00000000 ParentCid: 0000 DirBase: 00187000 ObjectTable: fffff8a0000019b0 HandleCount: 1559. Image: System
打开dump文件之后,执行kv; .echo; r命令:
0: kd> kv;.echo;r
Child-SP RetAddr : Args to Child : Call Site
0>fffff880`0afdb108 fffff800`02c76469 : 00000000`0000003b 00000000`c0000005 fffff880`03d1bf8f fffff880`0afdb9d0 : nt!KeBugCheckEx [d:\w7rtm\minkernel\ntos\ke\amd64\procstat.asm @ 177]
1>fffff880`0afdb110 fffff800`02c75dbc : fffff960`002d8888 fffff960`002bc74f 00000000`000d784c 00000000`000d784d : nt!KiBugCheckDispatch+0x69 [d:\w7rtm\minkernel\ntos\ke\amd64\trap.asm @ 2244]
2>fffff880`0afdb250 fffff800`02c9cbed : fffff960`00305314 fffff960`002d0420 fffff960`00020000 fffff880`0afdc178 : nt!KiSystemServiceHandler+0x7c [d:\w7rtm\minkernel\ntos\ke\amd64\trap.asm @ 1695]
3>fffff880`0afdb290 fffff800`02ca4250 : fffff800`02dc51e8 fffff880`0afdb308 fffff880`0afdc178 fffff800`02c05000 : nt!RtlpExecuteHandlerForException+0xd [d:\w7rtm\minkernel\ntos\rtl\amd64\xcptmisc.asm @ 131]
4>fffff880`0afdb2c0 fffff800`02cb11b5 : fffff880`0afdc178 fffff880`0afdb9d0 fffff880`00000000 fffff880`00000004 : nt!RtlDispatchException+0x410 [d:\w7rtm\minkernel\ntos\rtl\amd64\exdsptch.c @ 425]
5>fffff880`0afdb9a0 fffff800`02c76542 : fffff880`0afdc178 00000000`00000003 fffff880`0afdc220 fffffa80`0558a000 : nt!KiDispatchException+0x135 [d:\w7rtm\minkernel\ntos\ke\amd64\exceptn.c @ 724]
6>fffff880`0afdc040 fffff800`02c750ba : 00000000`00000000 00000000`00000003 00000000`000d8600 00000000`000d8647 : nt!KiExceptionDispatch+0xc2 [d:\w7rtm\minkernel\ntos\ke\amd64\trap.asm @ 2308]
7>fffff880`0afdc220 fffff880`03d1bf8f : fffff880`03d1c255 00000000`00000003 fffffa80`0558a000 00000000`ec5fa311 : nt!KiPageFault+0x23a (TrapFrame @ fffff880`0afdc220) [d:\w7rtm\minkernel\ntos\ke\amd64\trap.asm @ 1051]
8>fffff880`0afdc3b8 fffff880`03d1c255 : 00000000`00000003 fffffa80`0558a000 00000000`ec5fa311 00000000`00000000 : 0xfffff880`03d1bf8f
9>fffff880`0afdc3c0 00000000`00000003 : fffffa80`0558a000 00000000`ec5fa311 00000000`00000000 fffff880`0afdc470 : 0xfffff880`03d1c255
10>fffff880`0afdc3c8 fffffa80`0558a000 : 00000000`ec5fa311 00000000`00000000 fffff880`0afdc470 fffffa80`0558a000 : 0x3
11>fffff880`0afdc3d0 00000000`ec5fa311 : 00000000`00000000 fffff880`0afdc470 fffffa80`0558a000 011e0000`011e0000 : 0xfffffa80`0558a000
12>fffff880`0afdc3d8 00000000`00000000 : fffff880`0afdc470 fffffa80`0558a000 011e0000`011e0000 011e0000`00000004 : 0xec5fa311
rax=fffff8800afdb210 rbx=fffff80002dc51e8 rcx=000000000000003b
rdx=00000000c0000005 rsi=fffff80002c05000 rdi=0000000000000000
rip=fffff80002c76f00 rsp=fffff8800afdb108 rbp=0000000000000000
r8=fffff88003d1bf8f r9=fffff8800afdb9d0 r10=0000000000000000
r11=fffff8800afdb308 r12=fffff80002c76153 r13=fffff80002e83354
r14=fffff80002c75d40 r15=0000000000000000
iopl=0 nv up ei ng nz na pe nc
cs=0010 ss=0018 ds=002b es=002b fs=0053 gs=002b efl=00000282
nt!KeBugCheckEx:
fffff800`02c76f00 48894c2408 mov qword ptr [rsp+8],rcx ss:0018:fffff880`0afdb110=3b00000000000000
第8帧是第三方驱动执行的最后一个函数,发生异常后,系统的异常处理函数接管了执行权,并产生一个陷阱帧。在第7帧上可以看到TrapFrame关键字。这是一个什么异常呢?从函数名KiPageFault可以看出,系统认为发生了页错误异常。也就是第8帧的函数访问了一个无效的虚拟地址,系统视图解决这个虚拟地址。页错误对应的是0xE号中断,而KiPageFault是系统为64位系统注册的异常处理函数:
0: kd> !idt 0xe
Dumping IDT: fffff8011807f080
0e: fffff80116a8c980 nt!KiPageFault
下面一个步骤是切换到问题发生时候的场景,通过陷阱帧来实现:
0: kd> kv; .echo; r *** Stack trace for last set context - .thread/.cxr resets it Child-SP RetAddr : Args to Child : Call Site fffff880`0afdc3b8 fffff880`03d1c255 : 00000000`00000003 fffffa80`0558a000 00000000`ec5fa311 00000000`00000000 : 0xfffff880`03d1bf8f fffff880`0afdc3c0 00000000`00000003 : fffffa80`0558a000 00000000`ec5fa311 00000000`00000000 fffff880`0afdc470 : 0xfffff880`03d1c255 fffff880`0afdc3c8 fffffa80`0558a000 : 00000000`ec5fa311 00000000`00000000 fffff880`0afdc470 fffffa80`0558a000 : 0x3 fffff880`0afdc3d0 00000000`ec5fa311 : 00000000`00000000 fffff880`0afdc470 fffffa80`0558a000 011e0000`011e0000 : 0xfffffa80`0558a000 fffff880`0afdc3d8 00000000`00000000 : fffff880`0afdc470 fffffa80`0558a000 011e0000`011e0000 011e0000`00000004 : 0xec5fa311 Last set context: rax=fffffa800558a000 rbx=0000000000000000 rcx=0000000000000000 rdx=0000000000000001 rsi=0000000000000000 rdi=0000000000000000 rip=fffff88003d1bf8f rsp=fffff8800afdc3b8 rbp=0000000000000011 r8=fffff8800afdc3e0 r9=0000000000000003 r10=fffff8800afdc3e0 r11=00000000011e0080 r12=0000000000000000 r13=0000000000000000 r14=0000000000000000 r15=0000000000000000 iopl=0 nv up ei ng nz ac po cy cs=0010 ss=0018 ds=0000 es=0000 fs=0000 gs=0000 efl=00010297 fffff880`03d1bf8f 8a040a mov al,byte ptr [rdx+rcx] ds:00000000`00000001=??
最后一行指出了当前执行的指令。因为这是出问题时候的场景,所以这一个指令就和所发生的问题息息相关。
mov al,byte ptr [rdx+rcx] ds:00000000`00000001=??
指令的意思是把寄存在rcx所在地址处加上偏移rdx后所在地址处的一个字节的值赋给dl。问题出在哪里呢?问题出在rcx的当前值是0。这相当于下面的操作:
mov al, byte ptr [1] // error!
所以这是个空指针引用错误。有了这个分析之后,拿到符号文件后,发现rcx对应的是一个结构体,它的前面两个变量都是boolean类型。这个操作是要获取第二个boolean变量的值。类似下面的代码:
void funcNotSafeWithInputPara (myStruct* pStruct) { // 没有检测指针有效性 if (pStruct->bDo){…} }
这个函数的错误在于它没有检查输入参数的有效性。如果输入的是空指针,就会引发蓝屏。
操作系统对空指针错误有一个聪明的预防办法,就是永远让从0开始的一个页面(page)无效,这个措施针对所有的虚拟地址空间。所以所有引用地址0到0xFFF的指令都是错误的,并且会立刻引发错误,引起编程者和使用者的注意。如果没有系统的这个措施,那么有空指针错误的指令将会得到到一个有效但内容不正确的值,接下来的错误会越走越远,不可收拾。
0: kd> db 0 00000000`00000000 ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? ???????????????? 00000000`00000010 ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? ???????????????? 00000000`00000020 ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? ???????????????? 00000000`00000030 ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? ???????????????? 00000000`00000040 ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? ???????????????? 00000000`00000050 ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? ???????????????? 00000000`00000060 ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? ???????????????? 00000000`00000070 ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? ????????????????
6,905 total views, 1 views today
指令的意思是把寄存在rcx所在地址處加上偏移rdx後所在地址處的一個字節的值賦給dl。
這裡dl看起來應該是al才對??
No conaiplmts on this end, simply a good piece.