相关术语
SEH:结构化异常处理
VEH向量化异常处理
TopLevelEH顶层异常处理
每种处理方法都可以三种值,在不同处理方法下意义不同
EXCEPTION_EXECUTE_HANDLER
该异常被处理,从异常处下一条指令开始执行
EXCEPTION_CONTINUE_SEARCH
不处理该异常
EXCEPTION_CONTINUE_EXECUTIOIN
忽略异常,从异常处继续执行
如果当前进程正在被调试,调试器也可以返回值
DBG_CONTINUE
等同于EXCEPTION_CONTINUE_EXECUTION
DBG_EXCEPTION_NOT_HANDLED
等同于EXCEPTION_CONTINUE_SEARCH
异常处理器包含内核异常处理和R3异常处理
R3程序产生异常时,异常处理器处理顺序:
交给调试器
执行VEH
执行SEH
TopLevelEH
交给调试器
调试异常端口通知csrss.exe
第一次交给调试器
判断是否处理该异常
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| while(!bExit) { DWORD dwContinueStatus = DBG_EXCEPTION_NOT_HANDLED; DEBUG_EVENT debugEvent; WaitForDebugEvent(&debugEvent, INFINITE); switch ( debugEvent.dwDebugEventCode ) { case EXCEPTION_DEBUG_EVENT: { EXCEPTION_DEBUG_INFO* pExcpInfo = &debugEvent.u.Exception; if ( MessageBox(0,_T("处理该异常?"), _T("我是调试器"),MB_YESNO)==IDYES ) { dwContinueStatus = DBG_CONTINUE; } } break; } ContinueDebugEvent(debugEvent.dwProcessId, debugEvent.dwThreadId, dwContinueStatus); }
|
执行VEH
如果没有被调试,或者调试器不处理该异常(返回DBG_EXCEPTION_NOT_HANDLED),就会把异常交给VEH
VEH是个链表,每个VEH按顺序调用
VEH在SEH之前执行,不依赖某一线程,返回值:
EXCEPTION_CONTINUE_SEARCH 交给下一个VEH
EXCEPTION_CONTINUE_EXECUTION 认为已被处理,退出异常处理器在异常指令处继续执行
EXCEPTION_EXECUTE_HANDLED 无效,等同于EXCEPTION_CONTINUE_SEARCH
1 2 3 4 5 6 7 8 9 10
| LONG NTAPI FirstVectExcepHandler( PEXCEPTION_POINTERS pExcepInfo ) { if( ... ) { return EXCEPTION_CONTINUE_EXECUTION; } return EXCEPTION_CONTINUE_SEARCH; }
AddVectoredExceptionHandler( 1, &FirstVectExcepHandler );
|
执行SEH
当所有的VEH都不处理该异常,该异常就会让SEH处理,SEH只能处理自己线程的异常,基于线程栈的异常处理机制
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| LONG FirstSEHer( PEXCEPTION_POINTERS pExcepInfo ) { TCHAR* pTitle = _T("第一个SEH处理器"); _tprintf( _T("[EH.Exe] [SEH][1] in \n") ); LONG nRet = ShowSelectMessageBox(pTitle); _tprintf( _T("[EH.Exe] [SEH][1] out \n") ); return nRet; } LONG SecondSEHer( PEXCEPTION_POINTERS pExcepInfo ) { TCHAR* pTitle = _T("第二个SEH处理器"); _tprintf( _T("[EH.Exe] [SEH][2] in \n") ); LONG nRet = ShowSelectMessageBox(pTitle); _tprintf( _T("[EH.Exe] [SEH][2] out \n") );; return nRet; } void ExcepFunction() { __try { __try { __try { _tprintf( _T("[EH.Exe] *[CALL] int 3\n") ); __asm int 3; } __finally { printf( "[EH.Exe] *[SEH][0] finally call...\n" ); } } __except( FirstSEHer(GetExceptionInformation()) ) { _tprintf( _T("[EH.Exe] [SEH][1] 被俺处理了~(只有返回EXCEPTION_EXECUTE_HANDLER才会走到这里)\n")); } } __except( SecondSEHer(GetExceptionInformation()) ) { _tprintf( _T("[EH.Exe] [SEH][2] 被俺处理了(只有返回EXCEPTION_EXECUTE_HANDLER才会走到这里)\n")); } }
|
执行TopLevelEH
利用SEH实现,但是可以处理所有线程抛出的异常。如果正在被调试,则顶层异常会被忽略。
返回值:
EXCEPTION_CONTINUE_SEARCH
查注册表,如果存在调试器,则抛给调试器
注册表路径:KLM\software\microsoft\windows nt\currentvsrsion\aedebug。如果Auto==1,Debugger!=NULL
EXCEPTION_EXECUTE_HANDLER
杀死该进程
EXCEPTION_CONTINUE_EXECUTION
和SEH一样
1 2 3 4 5 6 7 8 9 10
| LONG NTAPI TopLevelExcepFilter( PEXCEPTION_POINTERS pExcepInfo ) { TCHAR* pTitle = _T("*顶级* 异常处理器"); _tprintf( _T("[EH.Exe] [TOP] in \n") ); LONG nRet = ShowSelectMessageBox(pTitle); _tprintf( _T("[EH.Exe] [TOP] out \n") );; return nRet; }
SetUnhandledExceptionFilter( &TopLevelExcepFilter );
|
再次交给调试器
返回值
上面的异常处理机制都没有处理该异常,则调用csrss.exe,弹出一个对话框
参考资料
[1] [原创]白话windows之四 异常处理机制(VEH、SEH、TopLevelEH…)