当出现ntdll!KiUserExceptionDispatcher时,如何用windbg 定位正确堆栈
2015-07-16 11:59
507 查看
某些情况下,当程序崩溃时异常没有被程序捕获,就会出现ntdll!KiUserExceptionDispatcher这种情况,这时就需要通过其他方式获取产生异常时的正确堆栈
下面为KiUserExceptionDispatcher 函数和一些相关函数写的伪代码。这个函数在NTDLL.DLL中,它是异常处理执行的起点
6b68e5d4 00000000 6b68e5ec 6b68e63c 6b68e5ec ntdll!KiUserExceptionDispatcher+0xf中的6b68e5ec 和6b68e63c ,
用.exr分析异常类型,如下所示,可知类型为com异常
接着用.cxr恢复上下文到寄存器
再用kv命令则可以看到出现异常时候的正确堆栈
参考https://support.microsoft.com/en-gb/kb/313109
下面为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; }由此可知,KiUserExceptionDispatcher 函数第一个参数为异常类型,第二个参数为产生异常时的上下文记录,对应dump中的地址分别为
6b68e5d4 00000000 6b68e5ec 6b68e63c 6b68e5ec ntdll!KiUserExceptionDispatcher+0xf中的6b68e5ec 和6b68e63c ,
用.exr分析异常类型,如下所示,可知类型为com异常
接着用.cxr恢复上下文到寄存器
再用kv命令则可以看到出现异常时候的正确堆栈
参考https://support.microsoft.com/en-gb/kb/313109
相关文章推荐
- Dom
- System.Web Namespce
- 简单shiro扩展实现NOT、AND、OR权限验证
- 网络图片查看器
- 模仿jquery框架源码
- 使用ajax实现城市下拉框
- Spring 之注解事务 @Transactional
- http://www.cnblogs.com/wangfupeng1988/p/4001284.html
- 本地环境PHP5.5版本帝国备份王备份报错的解决方法
- 123
- 在Ubuntu上安装MySQLdb(mysql-python)
- C#职责链模式实例详解
- Django框架下在视图中使用模版的方法
- Linux系统上对Mysql数据库导入和导出
- zoj 1109 Language of FatMouse(字典树)
- 黑马程序员--Java基础
- jquery css3动态背景用户登录界面特效
- jstl jsp long to date
- SQL Server 2012大数据导入Oracle的解决方案
- css常用代码