Bugcheck 0×3B is forced on x64 Windows platforms when an exception happens during a system service and unwind leads to a transition from a kernel to a user mode. Let’s see this in a complete memory dump:

An exception happened while executing a system service routine.
Arg1: 00000000c0000005, Exception code that caused the bugcheck
Arg2: fffff80001048a1d, Address of the exception record for the exception that caused the bugcheck
Arg3: fffffade643f6870, Address of the context record for the exception that caused the bugcheck
Arg4: 0000000000000000, zero.

CONTEXT: fffffade643f6870 -- (.cxr 0xfffffade643f6870)
rax=005300450053005c rbx=0000000000000048 rcx=0000000000000020
rdx=fffffa8007c9da20 rsi=0000000000000048 rdi=fffffade643f71d0
rip=fffff80001048a1d rsp=fffffade643f7088 rbp=0000000000000000
 r8=0000000000000048 r9=0000000000000002 r10=00490046002d0054
r11=0000000000000000 r12=fffffadf19744010 r13=fffffade643f7a78
r14=0000000000000800 r15=fffffadf1da71ee8
iopl=0 nv up ei pl nz na pe nc
cs=0010 ss=0018 ds=002b es=002b fs=0053 gs=002b efl=00010202
fffff800`01048a1d 488941e0 mov qword ptr [rcx-20h],rax ds:002b:00000000`00000000=????????????????

0: kd> kL
Child-SP RetAddr Call Site
fffffade`643f5eb8 fffff800`0104e834 nt!KeBugCheckEx
fffffade`643f5ec0 fffff800`0104e2fb nt!KiBugCheckDispatch+0x74
fffffade`643f6040 fffff800`0105c09d nt!KiSystemServiceHandler+0x7b
fffffade`643f6080 fffff800`01031561 nt!RtlpExecuteHandlerForException+0xd
fffffade`643f60b0 fffff800`010174fa nt!RtlDispatchException+0x2c0
fffffade`643f6770 fffff800`0104e92f nt!KiDispatchException+0xd9
fffffade`643f6d70 fffff800`0104d7e1 nt!KiExceptionExit
fffffade`643f6ef0 fffff800`01048a1d nt!KiPageFault+0x1e1
fffffade`643f7088 fffff800`01025977 nt!memmove+0xbd
fffffade`643f7090 fffffadf`101f858d nt!RtlAppendUnicodeStringToString+0x67
fffffade`643f70c0 fffffadf`101f8a1d driver+0x558d
fffffade`643f7a20 fffff800`012c3b21 driver+0x5a1d
fffffade`643f7a70 fffff800`012c3bd6 nt!IopXxxControlFile+0xa6b
fffffade`643f7b90 fffff800`0104e5fd nt!NtDeviceIoControlFile+0x56
fffffade`643f7c00 00000000`77ef12ca nt!KiSystemServiceCopyEnd+0×3
00000000`00e6ba08 00000000`77d67963 ntdll!ZwDeviceIoControlFile+0xa
00000000`00e6ba10 00000000`6340239f kernel32!DeviceIoControl+0×237
00000000`00e6bbf0 00000000`0000000e application!DllUnregisterServer+0×40f

On x64 Windows platforms KiSystemServiceCopyEnd has the similar purpose as KiFastSystemCallRet on x86 platforms.

We see that the chain of exception handlers spans protection boundary where KiSystemServiceCopyEnd has KiSystemServiceHandler as its exception handler:

0: kd> !exchain
100 stack frames, scanning for handlers...
Frame 0x03: nt!RtlpExecuteHandlerForException+0xd (fffff800`0105c09d)
  ehandler nt!RtlpExceptionHandler (fffff800`0105c060)
Frame 0x05: nt!KiDispatchException+0xd9 (fffff800`010174fa)
  ehandler nt!_C_specific_handler (fffff800`010356e0)
Frame 0x0a: driver+0x558d (fffffadf`101f858d)
  ehandler driver+0x1242 (fffffadf`101f4242)
Frame 0x0c: nt!IopXxxControlFile+0xa6b (fffff800`012c3b21)
  ehandler nt!_C_specific_handler (fffff800`010356e0)
Frame 0×0e: nt!KiSystemServiceCopyEnd+0×3 (fffff800`0104e5fd)
  ehandler nt!KiSystemServiceHandler (fffff800`0104e280)

Frame 0×10: kernel32!DeviceIoControl+0×237 (00000000`77d67963)
  ehandler kernel32!_C_specific_handler (00000000`77d92200)

If we disassemble KiSystemServiceHandler we get this code with bugcheck 3B branch:

kd> uf nt!KiSystemServiceHandler
fffff800`01040ddc cmp     byte ptr [rax+153h],0
fffff800`01040de3 je      nt!KiSystemServiceHandler+0×7b (fffff800`01040dfb)

fffff800`01040de5 xor     r10,r10
fffff800`01040de8 mov     r9,r8
fffff800`01040deb mov     r8,qword ptr [rcx+10h]
fffff800`01040def mov     edx,dword ptr [rcx]
fffff800`01040df1 mov     ecx,3Bh
fffff800`01040df6 call    nt!KiBugCheckDispatch (fffff800`01041300)

fffff800`01040dfb mov     eax,1
fffff800`01040e00 add     rsp,38h
fffff800`01040e04 ret

Here we see that the code checks if the previous mode for a thread was UserMode and if this is the case it bugchecks the system because transitioning back to  user space in exception unwind would have had disastrous consequences. The system wants to save a controlled crash dump for later problem analysis:

kd> dt _KTHREAD
   +0x000 Header           : _DISPATCHER_HEADER
   +0x018 MutantListHead   : _LIST_ENTRY
   +0x028 InitialStack     : Ptr64 Void
   +0x030 StackLimit       : Ptr64 Void
   +0x038 KernelStack      : Ptr64 Void
   +0×153 PreviousMode     : Char

Note that _KTHREAD.PreviousMode should not be confused with _KTRAP_FRAME.PreviousMode. The latter has KernelMode value if an exception happened while CPU was in kernel mode but the former structure field shows the previous CPU mode of a thread, for example, it has UserMode value if a user space thread called a system service.

  +0x000 P1Home : Uint8B
  +0x008 P2Home : Uint8B
  +0x010 P3Home : Uint8B
  +0x018 P4Home : Uint8B
  +0x020 P5 : Uint8B
  +0×028 PreviousMode : Char
  +0×029 PreviousIrql : UChar
  +0×02a FaultIndicator : UChar

I put all of this on a colored sequence UML diagram:


- Dmitry Vostokov @ DumpAnalysis.org -

One Response to “Bugchecks: SYSTEM_SERVICE_EXCEPTION”

  1. Crash Dump Analysis » Blog Archive » Reflecting on 2008 (Part 1) Says:

    […] minidump analyze windbg analyze c++ dereferencing null debug windows crash dump analysis system_service_exception kernel32!pnlsuserinfo warning: frame ip not in any known module. following frames may be wrong. […]

Leave a Reply

You must be logged in to post a comment.