引言:_except_handler3是BaseProcessStart的异常处理函数。
7C839AF0 ; int __cdecl _except_handler3(EXCEPTION_RECORD *argExceptionRecord, 7C839AF0 _EXCEPTION_REGISTRATION *argEstablisherFrame, _CONTEXT *argContextRecord) 7C839AF0 7C839AF0 varXPointers = dword ptr -8 7C839AF0 var_4 = dword ptr -4 7C839AF0 argExceptionRecord= dword ptr 8 7C839AF0 argEstablisherFrame= dword ptr 0Ch 7C839AF0 argContextRecord= dword ptr 10h 7C839AF0 ; 7C839AF0 ; 7C839AF0 ; VC++扩展SEH 7C839AF0 ; [ebp-14];PEXCEPTION_POINTERS xpointers; 7C839AF0 ; ;struct _EXCEPTION_REGISTRATION{ 7C839AF0 ; [ebp-10]; struct _EXCEPTION_REGISTRATION *prev; 7C839AF0 ; [ebp-0C]; _except_handler handler; 7C839AF0 ; [ebp-08]; struct scopetable_entry *scopetable; 7C839AF0 ; [ebp-04]; int trylevel; 7C839AF0 ; [ebp-00]; int _ebp; 7C839AF0 ; ;}; 7C839AF0 ; argEstablisherFrame当前指向[ebp-10] 7C839AF0 ; 7C839AF0 ; 7C839AF0 ; _except_handler定义 7C839AF0 ; typedef EXCEPTION_DISPOSITION __cdecl (*_except_handler)( 7C839AF0 ; _In_ struct _EXCEPTION_RECORD *_ExceptionRecord, 7C839AF0 ; _In_ void * _EstablisherFrame, 7C839AF0 ; _Inout_ struct _CONTEXT *_ContextRecord, 7C839AF0 ; _Inout_ void * _DispatcherContext 7C839AF0 ; ); 7C839AF0 ; 7C839AF0 ; 7C839AF0 ; scopetable_entry定义 7C839AF0 ; struct scopetable_entry{ 7C839AF0 ; DWORD prevlevel; 7C839AF0 ; PVOID lpfnFilter; 7C839AF0 ; PVOID lpfnHandler; 7C839AF0 ; } 7C839AF0 7C839AF0 push ebp 7C839AF1 mov ebp, esp 7C839AF3 sub esp, 8 ; EXCEPTION_POINTERS varXPointers; 7C839AF6 push ebx 7C839AF7 push esi 7C839AF8 push edi 7C839AF9 push ebp 7C839AFA cld ; Clear Direction Flag 7C839AFB mov ebx, [ebp+argEstablisherFrame] 7C839AFE mov eax, [ebp+argExceptionRecord] 7C839B01 test dword ptr [eax+4], 6 ;if(argExceptionRecord->ExceptionFlags & 7C839B01 ; EXCEPTION_UNWIND_CONTEXT) 7C839B01 ; goto loc_7C839BB9 7C839B01 ;EXCEPTION_UNWIND_CONTEXT在exsup.inc中定义 7C839B08 jnz loc_7C839BB9 7C839B0E mov [ebp+varXPointers], eax;varXPointers->ExceptionRecord=argExceptionRecord 7C839B11 mov eax, [ebp+argContextRecord] 7C839B14 mov [ebp+var_4], eax ;varXPointers->ContextRecord=argContextRecord 7C839B17 lea eax, [ebp+varXPointers] 7C839B1A mov [ebx-4], eax ;(PEXCEPTION_POINTERS)((DWORD)argEstablisherFrame-4)=xpointers 7C839B1D mov esi, [ebx+0Ch] ;esi=argEstablisherFrame->trylevel 7C839B20 mov edi, [ebx+8] ;edi=argEstablisherFrame->scopetable 7C839B23 push ebx 7C839B24 call __ValidateEH3RN 7C839B29 add esp, 4 7C839B2C or eax, eax 7C839B2E jz short loc_7C839BAB 7C839B30 7C839B30 loc_7C839B30: ;CODE XREF: __except_handler3+B2j 7C839B30 cmp esi, 0FFFFFFFFh ;if(argEstablisherFrame->trylevel==0xFFFFFFFF) goto loc_7C839BB2 7C839B33 jz short loc_7C839BB2 ;当前异常帧中所有__try/__except(嵌套)遍历完毕,跳走! 7C839B33 ;注:一个函数仅有一个异常帧,__try/__except嵌套也只产生一个异常帧 7C839B35 lea ecx, [esi+esi*2] 7C839B38 mov eax, [edi+ecx*4+4] ;eax=argEstablisherFrame->scopetable[trylevel].lpfnFilter 7C839B3C or eax, eax 7C839B3E jz short loc_7C839B99 ;if(lpfnFilter == NULL) goto loc_7C839B99 7C839B40 push esi 7C839B41 push ebp ;保存当前ebp 7C839B42 lea ebp, [ebx+10h] ;切换ebp,为lpfnFilter调用做准备 7C839B45 xor ebx, ebx 7C839B47 xor ecx, ecx 7C839B49 xor edx, edx 7C839B4B xor esi, esi 7C839B4D xor edi, edi 7C839B4F call eax ;call lpfnFilter 7C839B51 pop ebp ;恢复当前ebp 7C839B52 pop esi 7C839B53 mov ebx, [ebp+argEstablisherFrame] 7C839B56 or eax, eax ;检查lpfnFilter返回值. 7C839B58 jz short loc_7C839B99 ;if(eax==EXCEPTION_CONTINUE_SEARCH) goto loc_7C839B99 7C839B5A js short loc_7C839BA4 ;if(eax==EXCEPTION_CONTINUE_EXECUTION) goto loc_7C839BA4 7C839B5C mov edi, [ebx+8] ;if(eax==EXCEPTION_EXECUTE_HANDLER) goto 7C839B5F 7C839B5F push ebx 7C839B60 call __global_unwind2 ;全局展开 7C839B65 add esp, 4 7C839B68 lea ebp, [ebx+10h] ;切换ebp,注意之前没有保存当前ebp. 7C839B6B push esi 7C839B6C push ebx 7C839B6D call __local_unwind2 ;局部展开 7C839B72 add esp, 8 7C839B75 lea ecx, [esi+esi*2] 7C839B78 push 1 7C839B7A mov eax, [edi+ecx*4+8] 7C839B7E call __NLG_Notify 7C839B83 mov eax, [edi+ecx*4] ;eax = =argEstablisherFrame->scopetable[trylevel].prelevel 7C839B86 mov [ebx+0Ch], eax ;argEstablisherFrame->trylevel=eax 7C839B89 mov eax, [edi+ecx*4+8] ;eax=argEstablisherFrame->scopetable[trylevel].lpfnHandler 7C839B8D xor ebx, ebx 7C839B8F xor ecx, ecx 7C839B91 xor edx, edx 7C839B93 xor esi, esi 7C839B95 xor edi, edi 7C839B97 call eax ;call lpfnHandler 不再返回! 7C839B99 7C839B99 loc_7C839B99: ;CODE XREF: __except_handler3+4Ej 7C839B99 ;__except_handler3+68j 7C839B99 mov edi, [ebx+8] ;lpfnFilter返回EXCEPTION_CONTINUE_SEARCH的情况下 7C839B99 ;edi=argEstablisherFrame->scopetable 7C839B9C lea ecx, [esi+esi*2] 7C839B9F mov esi, [edi+ecx*4];esi=argEstablisherFrame->scopetable[trylevel].prevlevel 7C839BA2 jmp short loc_7C839B30 7C839BA4 ; --------------------------------------------------------------------------- 7C839BA4 7C839BA4 loc_7C839BA4: ;CODE XREF: __except_handler3+6Aj 7C839BA4 mov eax, 0 ;eax=ExceptionContinueExecution 7C839BA9 jmp short loc_7C839BCE ; 退出 7C839BAB ; --------------------------------------------------------------------------- 7C839BAB 7C839BAB loc_7C839BAB: ;CODE XREF: __except_handler3+3Ej 7C839BAB mov eax, [ebp+argExceptionRecord] 7C839BAE or dword ptr [eax+4], 8 7C839BB2 7C839BB2 loc_7C839BB2: ;CODE XREF: __except_handler3+43j 7C839BB2 mov eax, 1 ;7C839BAB ~ 7C839BB7的分析 7C839BB2 ;if(argExceptionRecord->ExceptionFlags==EXCEPTION_STACK_INVALID){ 7C839BB2 ; eax = ExceptionContinueSearch 7C839BB2 ; goto loc_7C839BCE 7C839BB2 ;} 7C839BB7 jmp short loc_7C839BCE ; 退出 7C839BB9 ; --------------------------------------------------------------------------- 7C839BB9 7C839BB9 loc_7C839BB9: ; CODE XREF: __except_handler3+18j 7C839BB9 push ebp ; 保存当前ebp 7C839BBA lea ebp, [ebx+10h] ; 切换ebp 7C839BBD push 0FFFFFFFFh 7C839BBF push ebx 7C839BC0 call __local_unwind2 ; 局部展开 7C839BC5 add esp, 8 7C839BC8 pop ebp ; 恢复当前ebp 7C839BC9 mov eax, 1 ; eax = ExceptionContinueSearch 7C839BCE 7C839BCE loc_7C839BCE: ; CODE XREF: __except_handler3+B9j 7C839BCE ; __except_handler3+C7j 7C839BCE pop ebp 7C839BCF pop edi 7C839BD0 pop esi 7C839BD1 pop ebx 7C839BD2 mov esp, ebp 7C839BD4 pop ebp 7C839BD5 retn 7C839BD5 __except_handler3 endp
相应的伪代码:
// VC++扩展SEH的异常帧结构 // [ebp-14];PEXCEPTION_POINTERS xpointers; // ;struct _EXCEPTION_REGISTRATION{ // [ebp-10]; struct _EXCEPTION_REGISTRATION *prev; // [ebp-0C]; _except_handler handler; // [ebp-08]; struct scopetable_entry *scopetable; // [ebp-04]; int trylevel; // [ebp-00]; int _ebp; // ;}; // // typedef enum _EXCEPTION_DISPOSITION { // ExceptionContinueExecution, // ExceptionContinueSearch, // ExceptionNestedException, // ExceptionCollidedUnwind // } EXCEPTION_DISPOSITION; // // _except_handler定义 // typedef EXCEPTION_DISPOSITION __cdecl (*_except_handler)( // _In_ struct _EXCEPTION_RECORD *_ExceptionRecord, // _In_ void * _EstablisherFrame, // _Inout_ struct _CONTEXT *_ContextRecord, // _Inout_ void * _DispatcherContext // ); // // // scopetable_entry定义 // struct scopetable_entry{ // DWORD prevtrylevel; // PVOID lpfnFilter; // PVOID lpfnHandler; // } EXCEPTION_DISPOSITION __cdecl __except_handler3 ( _In_ struct _EXCEPTION_RECORD *argExceptionRecord, _In_ void * argEstablisherFrame, _Inout_ struct _CONTEXT *argContextRecord, _Inout_ void * argDispatcherContext ) { EXCEPTION_POINTERS varXPointers; DWORD dwTryLevel,dwRetFilter; //方向标志复位 __asm cld if(!(argExceptionRecord->ExceptionFlags & EXCEPTION_UNWIND_CONTEXT)) { varXPointers->ExceptionRecord = argExceptionRecord; varXPointers->ContextRecord = argContextRecord; //提供VC++扩展SEH的异常帧结构中的[ebp-14]值 //内联函数GetExceptionInformation将从[ebp-14]提取信息 (PEXCEPTION_POINTERS)((DWORD)argEstablisherFrame-4)= &varXPointers; //验证SEH异常帧 if(__ValidateEH3RN(argEstablisherFrame)) { //一个函数仅有一个异常帧,一个函数可以有多个__try/__except结构 //嵌套的__try/__except通过scopetable->prevtrylevel关联起来 //向上搜索当前异常帧中嵌套的__try/__except过滤函数和处理函数 dwTryLevel = argEstablisherFrame->trylevel; while(dwTryLevel != 0xFFFFFFFF) { //不存在过滤函数,继续向上一层__try/__except搜索 if(!argEstablisherFrame->scopetable[dwTryLevel].lpfnFilter) { dwTryLevel = argEstablisherFrame->scopetable[dwTryLevel].prevtrylevel; continue; } //保存当前ebp __asm push ebp //切换ebp回lpfnFilter所在位置 __asm lea ebp,&argEstablisherFrame->_ebp; //调用过滤函数 dwRetFilter = argEstablisherFrame->scopetable[dwTryLevel].lpfnFilter(); //恢复当前ebp __asm pop ebp //检查过滤函数的返回值 if(dwRetFilter == EXCEPTION_CONTINUE_SEARCH) { dwTryLevel = argEstablisherFrame->scopetable[dwTryLevel].prevtrylevel; continue; } else if(dwRetFilter == EXCEPTION_CONTINUE_EXECUTION) { //异常已经修复,重新执行引发异常的指令 return ExceptionContinueExecution; } //找到__except(EXCEPTION_EXECUTE_HANDLER) //全局展开 __global_unwind2(argEstablisherFrame); //切换ebp,注意:之前没有保存当前ebp __asm lea ebp,&argEstablisherFrame->_ebp; //对当前__try/__except进行局部展开 __local_unwind2(argEstablisherFrame,dwTryLevel); //作用未知! __NLG_Notify(1); //把异常帧的trylevel设置成__except(EXCEPTION_EXECUTE_HANDLER) //的上一个__try/__except argEstablisherFrame->trylevel = argEstablisherFrame->scopetable[dwTryLevel].prevtrylevel; //调用__except {}块,这个调用并不会返回 argEstablisherFrame->scopetable[dwTryLevel].lpfnHandler(); } //当前异常帧搜索结束,但仍然没有找到__except(EXCEPTION_EXECUTE_HANDLER) //向下一个异常帧搜索,也就是向__except_handler3的调用函数搜索异常帧 return ExceptionContinueSearch; } else { //异常帧的栈无效 //向下一个异常帧搜索,也就是向__except_handler3的调用函数搜索异常帧 if(argExceptionRecord->ExceptionFlags==EXCEPTION_STACK_INVALID) { return ExceptionContinueSearch; } } } else { //保存当前ebp __asm push ebp //切换ebp回引发异常的函数 __asm lea,&argEstablisherFrame->_ebp; //对引发异常的函数进行局部展开 __local_unwind2(argEstablisherFrame,0xFFFFFFFF); //恢复当前ebp __asm pop ebp return ExceptionContinueSearch; } }
示意图(也就是__try/__except的示意图):
遗留:还不太清楚__NLG_Notify的作用,哪位朋友可以提点一下,非常感谢!!附__NLG_Notify:
7C80E01B __NLG_Notify proc near ; CODE XREF: __local_unwind2+57p 7C80E01B ; __except_handler3+8Ep 7C80E01B push ebx 7C80E01C push ecx 7C80E01D mov ebx, offset __NLG_Destination 7C80E022 mov ecx, [ebp+8] 7C80E025 7C80E025 loc_7C80E025: ; CODE XREF: __NLG_Notify1+7j 7C80E025 mov [ebx+8], ecx 7C80E028 mov [ebx+4], eax ; eax=pEstablisherFrame->scopetable[trylevel].lpfnHandler 7C80E02B mov [ebx+0Ch], ebp 7C80E02E push ebp 7C80E02F push ecx 7C80E030 push eax 7C80E030 __NLG_Notify endp ; sp-analysis failed 7C80E030 7C80E031 7C80E031 ; =============== S U B R O U T I N E ======================================= 7C80E031 7C80E031 7C80E031 __NLG_Dispatch2 proc near 7C80E031 pop eax 7C80E032 pop ecx 7C80E033 pop ebp 7C80E034 pop ecx 7C80E035 pop ebx 7C80E036 retn 4 7C80E036 __NLG_Dispatch2 endp ; sp-analysis failed 7C80E036