某些情况下,当程序崩溃时异常没有被程序捕获,就会出现ntdll!KiUserExceptionDispatcher这种情况,这时就需要通过其他方式获取产生异常时的正确堆栈
下面为KiUserExceptionDispatcher 函数和一些相关函数写的伪代码。这个函数在NTDLL.DLL中,它是异常处理执行的起点
- KiUserExceptionDispatcher( PEXCEPTION_RECORD pExcptRec, CONTEXT * pContext )
- {
- DWORD retValue;
- // Note: If the exception is handled, RtlDispatchException() never returns
- if ( RtlDispatchException( pExceptRec, pContext ) )
- retValue = NtContinue( pContext, 0 );
- else
- retValue = NtRaiseException( pExceptRec, pContext, 0 );
- EXCEPTION_RECORD excptRec2;
- excptRec2.ExceptionCode = retValue;
- excptRec2.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
- excptRec2.ExceptionRecord = pExcptRec;
- excptRec2.NumberParameters = 0;
- RtlRaiseException( &excptRec2 );
- }
- int RtlDispatchException( PEXCEPTION_RECORD pExcptRec, CONTEXT * pContext )
- {
- DWORD stackUserBase;
- DWORD stackUserTop;
- PEXCEPTION_REGISTRATION pRegistrationFrame;
- DWORD hLog;
- // Get stack boundaries from FS:[4] and FS:[8]
- RtlpGetStackLimits( &stackUserBase, &stackUserTop );
- pRegistrationFrame = RtlpGetRegistrationHead();
- while ( -1 != pRegistrationFrame )
- {
- PVOID justPastRegistrationFrame = &pRegistrationFrame + 8;
- if ( stackUserBase > justPastRegistrationFrame )
- {
- pExcptRec->ExceptionFlags |= EH_STACK_INVALID;
- return DISPOSITION_DISMISS; // 0
- }
- if ( stackUsertop < justPastRegistrationFrame )
- {
- pExcptRec->ExceptionFlags |= EH_STACK_INVALID;
- return DISPOSITION_DISMISS; // 0
- }
- if ( pRegistrationFrame & 3 ) // Make sure stack is DWORD aligned
- {
- pExcptRec->ExceptionFlags |= EH_STACK_INVALID;
- return DISPOSITION_DISMISS; // 0
- }
- if ( someProcessFlag )
- {
- // Doesn't seem to do a whole heck of a lot.
- hLog = RtlpLogExceptionHandler( pExcptRec, pContext, 0,
- pRegistrationFrame, 0x10 );
- }
- DWORD retValue, dispatcherContext;
- retValue= RtlpExecuteHandlerForException(pExcptRec, pRegistrationFrame,
- pContext, &dispatcherContext,
- pRegistrationFrame->handler );
- // Doesn't seem to do a whole heck of a lot.
- if ( someProcessFlag )
- RtlpLogLastExceptionDisposition( hLog, retValue );
- if ( 0 == pRegistrationFrame )
- {
- pExcptRec->ExceptionFlags &= ~EH_NESTED_CALL; // Turn off flag
- }
- EXCEPTION_RECORD excptRec2;
- DWORD yetAnotherValue = 0;
- if ( DISPOSITION_DISMISS == retValue )
- {
- if ( pExcptRec->ExceptionFlags & EH_NONCONTINUABLE )
- {
- excptRec2.ExceptionRecord = pExcptRec;
- excptRec2.ExceptionNumber = STATUS_NONCONTINUABLE_EXCEPTION;
- excptRec2.ExceptionFlags = EH_NONCONTINUABLE;
- excptRec2.NumberParameters = 0
- RtlRaiseException( &excptRec2 );
- }
- else
- return DISPOSITION_CONTINUE_SEARCH;
- }
- else if ( DISPOSITION_CONTINUE_SEARCH == retValue )
- {
- }
- else if ( DISPOSITION_NESTED_EXCEPTION == retValue )
- {
- pExcptRec->ExceptionFlags |= EH_EXIT_UNWIND;
- if ( dispatcherContext > yetAnotherValue )
- yetAnotherValue = dispatcherContext;
- }
- else // DISPOSITION_COLLIDED_UNWIND
- {
- excptRec2.ExceptionRecord = pExcptRec;
- excptRec2.ExceptionNumber = STATUS_INVALID_DISPOSITION;
- excptRec2.ExceptionFlags = EH_NONCONTINUABLE;
- excptRec2.NumberParameters = 0
- RtlRaiseException( &excptRec2 );
- }
- pRegistrationFrame = pRegistrationFrame->prev; // Go to previous frame
- }
- return DISPOSITION_DISMISS;
- }
- _RtlpExecuteHandlerForException: // Handles exception (first time through)
- MOV EDX,XXXXXXXX
- JMP ExecuteHandler
- RtlpExecutehandlerForUnwind: // Handles unwind (second time through)
- MOV EDX,XXXXXXXX
- int ExecuteHandler( PEXCEPTION_RECORD pExcptRec
- PEXCEPTION_REGISTRATION pExcptReg
- CONTEXT * pContext
- PVOID pDispatcherContext,
- FARPROC handler ) // Really a ptr to an _except_handler()
- // Set up an EXCEPTION_REGISTRATION, where EDX points to the
- // appropriate handler code shown below
- PUSH EDX
- PUSH FS:[0]
- MOV FS:[0],ESP
- // Invoke the exception callback function
- EAX = handler( pExcptRec, pExcptReg, pContext, pDispatcherContext );
- // Remove the minimal EXCEPTION_REGISTRATION frame
- MOV ESP,DWORD PTR FS:[00000000]
- POP DWORD PTR FS:[00000000]
- return EAX;
- }
- Exception handler used for _RtlpExecuteHandlerForException:
- {
- // If unwind flag set, return DISPOSITION_CONTINUE_SEARCH, else
- // assign pDispatcher context and return DISPOSITION_NESTED_EXCEPTION
- return pExcptRec->ExceptionFlags & EXCEPTION_UNWIND_CONTEXT
- ? DISPOSITION_CONTINUE_SEARCH
- : *pDispatcherContext = pRegistrationFrame->scopetable,
- DISPOSITION_NESTED_EXCEPTION;
- }
- Exception handler used for _RtlpExecuteHandlerForUnwind:
- {
- // If unwind flag set, return DISPOSITION_CONTINUE_SEARCH, else
- // assign pDispatcher context and return DISPOSITION_COLLIDED_UNWIND
- return pExcptRec->ExceptionFlags & EXCEPTION_UNWIND_CONTEXT
- ? DISPOSITION_CONTINUE_SEARCH
- : *pDispatcherContext = pRegistrationFrame->scopetable,
- DISPOSITION_COLLIDED_UNWIND;
- }
6b68e5d4 00000000 6b68e5ec 6b68e63c 6b68e5ec ntdll!KiUserExceptionDispatcher+0xf中的6b68e5ec 和6b68e63c ,
用.exr分析异常类型,如下所示,可知类型为com异常
接着用.cxr恢复上下文到寄存器
再用kv命令则可以看到出现异常时候的正确堆栈