Making sense out of a nonsensical call stack

Recently a colleague wrote an application which on purpose caused an access violation. He took a memory dump of the process when it access violated and checked the call stack. To his surprise he didn’t see a direct call stack which would point him to the exact location in his source file but the call stack showed as if it was ready for throwing the exception but not yet thrown. This post is not for analyzing why this happened but how can we make sense of such call stacks.

For reference this is how the callstack looks…

0:000> kc

WARNING: Frame IP not in any known module. Following frames may be wrong.

To get around this call stack its good to know that for every exception there is an exception context that get saved to memory, which in simple terms means this context record will point to the code that caused the exception. So in our case if we look at the parameters passed to first two functions at the top of the stack ZwRaiseException and KiUserExceptionDispatcher, they get a reference to the context record. By trial and error I’ve found that it’s the second parameter while the first one is the exception record

0:000> kb 2
ChildEBP RetAddr  Args to Child             
004eec0c 76fe014d 004eec20 004eec70 00000000 ntdll!ZwRaiseException+0x12
004eec0c 00392d2d 004eec20 004eec70 00000000 ntdll!KiUserExceptionDispatcher+0x29

This is what is stored inside exception record, contains useful information about the exception that happened. It shows us the exception address, exception code etc. But our guy of interest is the context record.

0:000> .exr 004eec20
ExceptionAddress: 00392d2d (CrashingApp!CCrashingAppDlg::OnBnClickedOk+0x0000002d)
   ExceptionCode: c0000005 (Access violation)
  ExceptionFlags: 00000000
NumberParameters: 2
   Parameter[0]: 00000001
   Parameter[1]: 00000000
Attempt to write to address 00000000

The key to retrieve the actual call stack is the context record: 004eec70. The command to set context record or context of execution is .cxr. This command is used as follows…

0:000> .cxr 004eec70
eax=00000000 ebx=00000000 ecx=004efa80 edx=00000000 esi=0065e748 edi=004ef1b8
eip=00392d2d esp=004ef0d4 ebp=004ef1b8 iopl=0         nv up ei pl nz na po nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010202
00392d2d c60063          mov     byte ptr [eax],63h         ds:002b:00000000=??

So what does a context contain. As the above output says, a context is identified by eip, esp, eax, ecx, edx etc. Smile In fact context means registers! When an exception happens all the values in the registers get’s saved and that is what we call as context record. This is because a program in execution always uses the registers for its execution, just change the register values to make the program to do something else. I won't post the structure internal details here since I'm not sure if that's permitted.

Once the above command completes the context is now changed to the actual exception context, take a look at the call stack now…

0:000> kc
  *** Stack trace for last set context - .thread/.cxr resets it


Bingo! right at the top we now have the culprit, the call stack now makes perfect sense.

Ok what happens if the function KiUserExceptionDispatcher is not always on the call stack, what happens if this exception caused another exception? In such scenarios I normally check the ‘thread’ stack for calls made to KiUserExceptionDispatcher/ZwRaiseException. I also check for well known exception codes like: c0000005. In this case the function addresses on this threads’ stack is as follows…

0x004eeb10    0x77047519    ntdll!_except_handler4+000000cc
0x004eeb28    0x76ffc540    ntdll! ?? ::FNODOBFM::`string'+00000b6e
0x004eeb38    0x7702b459    ntdll!ExecuteHandler2+00000026
0x004eeb50    0x7702b46d    ntdll!ExecuteHandler2+0000003a
0x004eeb5c    0x7702b42b    ntdll!ExecuteHandler+00000024
0x004eeb80    0x77033c67    ntdll!RtlCallVectoredContinueHandlers+00000012
0x004eeb94    0x77033c48    ntdll!RtlDispatchException+000001b5
0x004eec0c    0x76ff15de    ntdll!ZwRaiseException+00000012
0x004eec10    0x76fe014e    ntdll!KiUserExceptionDispatcher+0000002a

Now I know this is something interesting, so start exploring the values around the above function’s address: 0x004eec10. I see the following…

0:000> dds 0x004eec10
004eec10  76fe014e ntdll!KiUserExceptionDispatcher+0x2a
004eec14  004eec20   <--- exception record
004eec70   <--- context record
004eec1c  00000000
004eec20  c0000005   <----- the exception code
004eec24  00000000
004eec28  00000000

Again if we use .cxr on above context record we’ll end up having the correct call stack again. At any point of time if you would like to return back to original state as and when the dump was taken, use .cxr without any parameters.

Any questions, let me know.

Skip to main content