当出现ntdll!KiUserExceptionDispatcher时,如何用windbg 定位正确堆栈

某些情况下,当程序崩溃时异常没有被程序捕获,就会出现ntdll!KiUserExceptionDispatcher这种情况,这时就需要通过其他方式获取产生异常时的正确堆栈

当出现ntdll!KiUserExceptionDispatcher时,如何用windbg 定位正确堆栈_第1张图片

下面为KiUserExceptionDispatcher 函数和一些相关函数写的伪代码。这个函数在NTDLL.DLL中,它是异常处理执行的起点

[cpp]  view plain copy
  1. KiUserExceptionDispatcher( PEXCEPTION_RECORD pExcptRec, CONTEXT * pContext )  
  2.  {  
  3.      DWORD retValue;  
  4.    
  5.      // Note: If the exception is handled, RtlDispatchException() never returns  
  6.      if ( RtlDispatchException( pExceptRec, pContext ) )  
  7.          retValue = NtContinue( pContext, 0 );  
  8.      else  
  9.          retValue = NtRaiseException( pExceptRec, pContext, 0 );  
  10.    
  11.      EXCEPTION_RECORD excptRec2;  
  12.    
  13.      excptRec2.ExceptionCode = retValue;  
  14.      excptRec2.ExceptionFlags = EXCEPTION_NONCONTINUABLE;  
  15.      excptRec2.ExceptionRecord = pExcptRec;  
  16.      excptRec2.NumberParameters = 0;  
  17.    
  18.      RtlRaiseException( &excptRec2 );  
  19.  }  
  20.    
  21.  int RtlDispatchException( PEXCEPTION_RECORD pExcptRec, CONTEXT * pContext )  
  22.  {  
  23.      DWORD   stackUserBase;  
  24.      DWORD   stackUserTop;  
  25.      PEXCEPTION_REGISTRATION pRegistrationFrame;  
  26.      DWORD hLog;  
  27.    
  28.      // Get stack boundaries from FS:[4] and FS:[8]  
  29.      RtlpGetStackLimits( &stackUserBase, &stackUserTop );  
  30.    
  31.      pRegistrationFrame = RtlpGetRegistrationHead();  
  32.    
  33.      while ( -1 != pRegistrationFrame )  
  34.      {  
  35.          PVOID justPastRegistrationFrame = &pRegistrationFrame + 8;  
  36.          if ( stackUserBase > justPastRegistrationFrame )  
  37.          {  
  38.              pExcptRec->ExceptionFlags |= EH_STACK_INVALID;  
  39.              return DISPOSITION_DISMISS; // 0  
  40.          }  
  41.    
  42.          if ( stackUsertop < justPastRegistrationFrame )  
  43.          {  
  44.              pExcptRec->ExceptionFlags |= EH_STACK_INVALID;  
  45.              return DISPOSITION_DISMISS; // 0  
  46.          }  
  47.    
  48.          if ( pRegistrationFrame & 3 )   // Make sure stack is DWORD aligned  
  49.          {  
  50.              pExcptRec->ExceptionFlags |= EH_STACK_INVALID;  
  51.              return DISPOSITION_DISMISS; // 0  
  52.          }  
  53.    
  54.          if ( someProcessFlag )  
  55.          {  
  56.              // Doesn't seem to do a whole heck of a lot.  
  57.              hLog = RtlpLogExceptionHandler( pExcptRec, pContext, 0,  
  58.                                              pRegistrationFrame, 0x10 );  
  59.          }  
  60.    
  61.          DWORD retValue, dispatcherContext;  
  62.    
  63.          retValue= RtlpExecuteHandlerForException(pExcptRec, pRegistrationFrame,  
  64.                                                   pContext, &dispatcherContext,  
  65.                                                   pRegistrationFrame->handler );  
  66.    
  67.          // Doesn't seem to do a whole heck of a lot.  
  68.          if ( someProcessFlag )  
  69.              RtlpLogLastExceptionDisposition( hLog, retValue );  
  70.    
  71.          if ( 0 == pRegistrationFrame )  
  72.          {  
  73.              pExcptRec->ExceptionFlags &= ~EH_NESTED_CALL;   // Turn off flag  
  74.          }  
  75.    
  76.          EXCEPTION_RECORD excptRec2;  
  77.    
  78.          DWORD yetAnotherValue = 0;  
  79.    
  80.          if ( DISPOSITION_DISMISS == retValue )  
  81.          {  
  82.              if ( pExcptRec->ExceptionFlags & EH_NONCONTINUABLE )  
  83.              {  
  84.                  excptRec2.ExceptionRecord = pExcptRec;  
  85.                  excptRec2.ExceptionNumber = STATUS_NONCONTINUABLE_EXCEPTION;  
  86.                  excptRec2.ExceptionFlags = EH_NONCONTINUABLE;  
  87.                  excptRec2.NumberParameters = 0  
  88.                  RtlRaiseException( &excptRec2 );  
  89.              }  
  90.              else  
  91.                  return DISPOSITION_CONTINUE_SEARCH;  
  92.          }  
  93.          else if ( DISPOSITION_CONTINUE_SEARCH == retValue )  
  94.          {  
  95.          }  
  96.          else if ( DISPOSITION_NESTED_EXCEPTION == retValue )  
  97.          {  
  98.              pExcptRec->ExceptionFlags |= EH_EXIT_UNWIND;  
  99.              if ( dispatcherContext > yetAnotherValue )  
  100.                  yetAnotherValue = dispatcherContext;  
  101.          }  
  102.          else    // DISPOSITION_COLLIDED_UNWIND  
  103.          {  
  104.              excptRec2.ExceptionRecord = pExcptRec;  
  105.              excptRec2.ExceptionNumber = STATUS_INVALID_DISPOSITION;  
  106.              excptRec2.ExceptionFlags = EH_NONCONTINUABLE;  
  107.              excptRec2.NumberParameters = 0  
  108.              RtlRaiseException( &excptRec2 );  
  109.          }  
  110.    
  111.          pRegistrationFrame = pRegistrationFrame->prev;  // Go to previous frame  
  112.      }  
  113.    
  114.      return DISPOSITION_DISMISS;  
  115.  }  
  116.    
  117.    
  118.  _RtlpExecuteHandlerForException:    // Handles exception (first time through)  
  119.      MOV     EDX,XXXXXXXX  
  120.      JMP     ExecuteHandler  
  121.    
  122.    
  123.  RtlpExecutehandlerForUnwind:        // Handles unwind (second time through)  
  124.      MOV     EDX,XXXXXXXX  
  125.    
  126.    
  127.    
  128.  int ExecuteHandler( PEXCEPTION_RECORD pExcptRec  
  129.                      PEXCEPTION_REGISTRATION pExcptReg  
  130.                      CONTEXT * pContext  
  131.                      PVOID pDispatcherContext,  
  132.                      FARPROC handler ) // Really a ptr to an _except_handler()  
  133.    
  134.      // Set up an EXCEPTION_REGISTRATION, where EDX points to the  
  135.      // appropriate handler code shown below  
  136.      PUSH    EDX  
  137.      PUSH    FS:[0]  
  138.      MOV     FS:[0],ESP  
  139.    
  140.      // Invoke the exception callback function  
  141.      EAX = handler( pExcptRec, pExcptReg, pContext, pDispatcherContext );  
  142.    
  143.      // Remove the minimal EXCEPTION_REGISTRATION frame   
  144.      MOV     ESP,DWORD PTR FS:[00000000]  
  145.      POP     DWORD PTR FS:[00000000]  
  146.    
  147.      return EAX;  
  148.  }  
  149.    
  150.  Exception handler used for _RtlpExecuteHandlerForException:  
  151.  {  
  152.      // If unwind flag set, return DISPOSITION_CONTINUE_SEARCH, else  
  153.      // assign pDispatcher context and return DISPOSITION_NESTED_EXCEPTION  
  154.    
  155.      return pExcptRec->ExceptionFlags & EXCEPTION_UNWIND_CONTEXT  
  156.                  ? DISPOSITION_CONTINUE_SEARCH   
  157.                  : *pDispatcherContext = pRegistrationFrame->scopetable,  
  158.                    DISPOSITION_NESTED_EXCEPTION;  
  159.  }  
  160.    
  161.  Exception handler used for _RtlpExecuteHandlerForUnwind:  
  162.  {  
  163.      // If unwind flag set, return DISPOSITION_CONTINUE_SEARCH, else  
  164.      // assign pDispatcher context and return DISPOSITION_COLLIDED_UNWIND  
  165.    
  166.      return pExcptRec->ExceptionFlags & EXCEPTION_UNWIND_CONTEXT  
  167.                  ? DISPOSITION_CONTINUE_SEARCH   
  168.                  : *pDispatcherContext = pRegistrationFrame->scopetable,  
  169.                    DISPOSITION_COLLIDED_UNWIND;  
  170.  }  
由此可知,KiUserExceptionDispatcher 函数第一个参数为异常类型,第二个参数为产生异常时的上下文记录,对应dump中的地址分别为

6b68e5d4 00000000 6b68e5ec 6b68e63c 6b68e5ec ntdll!KiUserExceptionDispatcher+0xf中的6b68e5ec 和6b68e63c ,

用.exr分析异常类型,如下所示,可知类型为com异常

当出现ntdll!KiUserExceptionDispatcher时,如何用windbg 定位正确堆栈_第2张图片

接着用.cxr恢复上下文到寄存器


再用kv命令则可以看到出现异常时候的正确堆栈

当出现ntdll!KiUserExceptionDispatcher时,如何用windbg 定位正确堆栈_第3张图片

参考https://support.microsoft.com/en-gb/kb/313109

你可能感兴趣的:(windbg命令收集)