Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to know if a different exception is hidden behind a 80000003 breakpoint (WER dialog)

My application, an executable, is crashing on a remote machine. I don't have access to that machine, so I requested a dump, generated through Task Manager. Using WinDbg, on executing the command !analyze -v, I can see the following text among many others

EXCEPTION_RECORD:  (.exr -1)
ExceptionAddress: 0000000000000000
ExceptionCode: 80000003 (Break instruction exception)
ExceptionFlags: 00000000
NumberParameters: 0

How can I know if it is responsible for the crash? If it is not, how do I identify the real cause?

like image 955
Rahul Singh Avatar asked Feb 07 '23 16:02

Rahul Singh


1 Answers

Is the INT3 breakpoint the root cause?

TLDR: if !findstack kernel32!WerpReportFault yields a result, then it's probably not the root cause.

Long version:

When your application crashes due to an unhandled exception, the OS will pick it up with a feature called Windows Error Reporting. This results in a few technical things:

  1. the exception dispatcher in ntdll starts a new thread.
  2. in the new thread, a breakpoint is triggered
  3. the exception dispatcher also calls the unhandled exception handler
  4. if there's no such handler by your application, it will forward the handling to the Windows Error Reporting (in kernel32) which shows the dialog

If you take a crash dump at that time, you'll see the following:

  1. A breakpoint exception as mentioned in your question

    0:002> .exr -1
    ExceptionAddress: 775f000c (ntdll!DbgBreakPoint)
       ExceptionCode: 80000003 (Break instruction exception)
      ExceptionFlags: 00000000
    NumberParameters: 1
       Parameter[0]: 00000000
    
  2. A thread that has nothing inside but a breakpoint

    0:002> k
    ChildEBP RetAddr  
    02e2ff58 7767f926 ntdll!DbgBreakPoint
    02e2ff88 75b3338a ntdll!DbgUiRemoteBreakin+0x3c
    02e2ff94 77619f72 kernel32!BaseThreadInitThunk+0xe
    02e2ffd4 77619f45 ntdll!__RtlUserThreadStart+0x70
    02e2ffec 00000000 ntdll!_RtlUserThreadStart+0x1b
    
  3. A call stack with the related actions mentioned before

    0:001> k
    ChildEBP RetAddr  
    01aff904 770715f7 ntdll!NtWaitForMultipleObjects+0x15
    01aff9a0 75b319f8 KERNELBASE!WaitForMultipleObjectsEx+0x100
    01aff9e8 75b34200    kernel32!WaitForMultipleObjectsExImplementation+0xe0
    01affa04 75b580a4 kernel32!WaitForMultipleObjects+0x18
    01affa70 75b57f63 kernel32!WerpReportFaultInternal+0x186
    01affa84 75b57858 kernel32!WerpReportFault+0x70
    01affa94 75b577d7 kernel32!BasepReportFault+0x20
    01affb20 776574ff kernel32!UnhandledExceptionFilter+0x1af
    01affb28 776573dc ntdll!__RtlUserThreadStart+0x62
    01affb3c 77657281 ntdll!_EH4_CallFilterFunc+0x12
    01affb64 7763b499 ntdll!_except_handler4+0x8e
    01affb88 7763b46b ntdll!ExecuteHandler2+0x26
    01affbac 7763b40e ntdll!ExecuteHandler+0x24
    01affc38 775f0133 ntdll!RtlDispatchException+0x127
    01affc38 6f8c20ce ntdll!KiUserExceptionDispatcher+0xf
    

To identify a WER breakpoint, you can check for these three conditions. For the latter, you can use the !findstack command, since it may happen on any thread.

0:001> !findstack kernel32!WerpReportFault
Thread 001, 2 frame(s) match
        * 04 01affa70 75b57f63 kernel32!WerpReportFaultInternal+0x186
        * 05 01affa84 75b57858 kernel32!WerpReportFault+0x70

I hope that the method name does not change.

How to identify the root cause?

This works for x86 (32 bit) due to the way how the stack is created. It does not work well on x64 (64 bit), since the kb command is not reliable. On x64, arguments get passed in registers instead of the stack but the kb command only works with the stack.

That said, the exception pointer is passed to WerpReportFault() as the second argument. You can use that exception pointer to create a new dump with that exception as the primary exception like this:

.dump /ma /xp <exception pointer> c:\path\to\newdump.dmp

Next, close the source dump, open the new dump and analyze it again, e.g. with the following 4 commands as a starting point:

.symfix
.reload
.exr -1
!analyze -v
like image 190
Thomas Weller Avatar answered Mar 04 '23 08:03

Thomas Weller