逆向分析MSVCR90D.dll!_except_handler4_common函数

引言:_except_handler4_common执行_except_handler4转发而来的异常处理。

102DCA80 _EXCEPTION_DISPOSITION __cdecl _except_handler4_common( 102DCA80 unsigned int *CookiePointer, 102DCA80 void (__fastcall *CookieCheckFunction)(unsigned int), 102DCA80 _EXCEPTION_RECORD *ExceptionRecord, 102DCA80 _EXCEPTION_REGISTRATION_RECORD *EstablisherFrame, 102DCA80 _CONTEXT *ContextRecord, 102DCA80 void *DispatcherContext 102DCA80 ) 102DCA80 102DCA80 __except_handler4_common proc near ; CODE XREF: __except_handler4+1Fp 102DCA80 ; DATA XREF: .text:off_10308788o 102DCA80 102DCA80 FilterFunc = dword ptr -30h 102DCA80 ScopeTable = dword ptr -2Ch 102DCA80 TryLevel = dword ptr -28h 102DCA80 Revalidate = byte ptr -21h 102DCA80 RegistrationNode= dword ptr -20h 102DCA80 ScopeTableRecord= dword ptr -1Ch 102DCA80 FramePointer = dword ptr -18h 102DCA80 EnclosingLevel = dword ptr -14h 102DCA80 FilterResult = dword ptr -10h 102DCA80 Disposition = dword ptr -0Ch 102DCA80 ExceptionPointers= _EXCEPTION_POINTERS ptr -8 102DCA80 CookiePointer = dword ptr 8 102DCA80 CookieCheckFunction= dword ptr 0Ch 102DCA80 ExceptionRecord = dword ptr 10h 102DCA80 EstablisherFrame= dword ptr 14h 102DCA80 ContextRecord = dword ptr 18h 102DCA80 DispatcherContext= dword ptr 1Ch 102DCA80 102DCA80 mov edi, edi 102DCA82 push ebp 102DCA83 mov ebp, esp 102DCA85 sub esp, 30h 102DCA88 mov [ebp+Revalidate], 0 102DCA8C mov [ebp+Disposition], 1 ; 初始化返回值:ExceptionContinueSearch 102DCA93 mov eax, [ebp+EstablisherFrame] 102DCA96 sub eax, 8 ;[ebp-18]:ESP <---- 让eax指向这里 102DCA96 ;[ebp-14]:PEXCEPTION_POINTERS xpointers; 102DCA96 ; struct _EXCEPTION_REGISTRATION{ 102DCA96 ;[ebp-10]:struct _EXCEPTION_REGISTRATION *prev; 102DCA96 ;[ebp-0C]:void (*handler)(PEXCEPTION_RECORD,PEXCEPTION_REGISTRATION,PCONTEXT,PEXCEPTION_RECORD); 102DCA96 ;[ebp-08]:struct scopetable_entry *scopetable; 102DCA96 ;[ebp-04]:int trylevel; 102DCA96 ;[ebp-00]:int _ebp; 102DCA96 ; }; 102DCA99 mov [ebp+RegistrationNode], eax 102DCA9C mov ecx, [ebp+RegistrationNode] 102DCA9F add ecx, 18h 102DCAA2 mov [ebp+FramePointer], ecx ; 保存_ebp 102DCAA5 mov edx, [ebp+RegistrationNode] 102DCAA8 mov eax, [ebp+CookiePointer] 102DCAAB mov ecx, [edx+10h] ; 获取scopetable 102DCAAE xor ecx, [eax] ; 修复scopetable,scopetable ^=___security_cookie; 102DCAB0 mov [ebp+ScopeTable], ecx 102DCAB3 mov edx, [ebp+FramePointer] 102DCAB6 push edx ; FramePointer 102DCAB7 mov eax, [ebp+ScopeTable] 102DCABA push eax ; ScopeTable 102DCABB mov ecx, [ebp+CookieCheckFunction] 102DCABE push ecx ; CookieCheckFunction 102DCABF call ValidateLocalCookies ; 验证安全码:GSCookie和EHCookie 102DCAC4 add esp, 0Ch 102DCAC7 mov edx, [ebp+ExceptionRecord] 102DCACA mov eax, [edx+4] ; eax=ExceptionRecord->ExceptionFlags 102DCACD and eax, 66h ; 66h的作用? 6 = EXCEPTION_UNWIND_CONTEXT 102DCAD0 jnz loc_102DCBF6 ; 不等于0,跳走执行局部展开并退出 102DCAD6 mov ecx, [ebp+ExceptionRecord] 102DCAD9 mov [ebp+ExceptionPointers.ExceptionRecord], ecx 102DCADC mov edx, [ebp+ContextRecord] 102DCADF mov [ebp+ExceptionPointers.ContextRecord], edx 102DCAE2 mov eax, [ebp+RegistrationNode] 102DCAE5 lea ecx, [ebp+ExceptionPointers] 102DCAE8 mov [eax+4], ecx ; RegistrationNode->ExceptionPointers=ExceptionPointers 102DCAEB mov edx, [ebp+RegistrationNode] 102DCAEE mov eax, [edx+14h] 102DCAF1 mov [ebp+TryLevel], eax ; 获取当前__try的位置,TryLevel=RegistrationNode->TryLevel 102DCAF4 jmp short loc_102DCAFC ; 开始循环执行,查找过滤表达式等于.. 102DCAF6 ; --------------------------------------------------------------------------- 102DCAF6 102DCAF6 loc_102DCAF6: ; CODE XREF: __except_handler4_common:loc_102DCBEFj 102DCAF6 mov ecx, [ebp+EnclosingLevel] 102DCAF9 mov [ebp+TryLevel], ecx 102DCAFC 102DCAFC loc_102DCAFC: ; CODE XREF: __except_handler4_common+74j 102DCAFC cmp [ebp+TryLevel], 0FFFFFFFEh ; if(TryLevel==0xFFFFFFFE) goto loc_102DCBF4 102DCB00 jz loc_102DCBF4 ; 当前异常帧中所有嵌套的__try语句遍历完毕,跳走! 102DCB00 ; 注:一个函数仅有一个异常帧,即便有多个__try语句(包括嵌套)也只产生一个异常帧 102DCB06 mov edx, [ebp+TryLevel] 102DCB09 imul edx, 0Ch ; edx=sizeof(_EH4_SCOPETABLE_RECORD)*TryLevel 102DCB0C mov eax, [ebp+ScopeTable] 102DCB0F lea ecx, [eax+edx+10h] 102DCB13 mov [ebp+ScopeTableRecord], ecx ; 获取当前__try的结构,ScopeTableRecord=ScopeTable->ScopeRecord[TryLevel] 102DCB16 mov edx, [ebp+ScopeTableRecord] 102DCB19 mov eax, [edx+4] 102DCB1C mov [ebp+FilterFunc], eax ; 获取当前__try的过滤表达式,FilterFunc=ScopeTableRecord->FilterFunc 102DCB1F mov ecx, [ebp+ScopeTableRecord] 102DCB22 mov edx, [ecx] 102DCB24 mov [ebp+EnclosingLevel], edx ; 获取上一层__try的位置:EnclosingLevel=ScopeTableRecord->EnclosingLevel 102DCB27 cmp [ebp+FilterFunc], 0 102DCB2B jz loc_102DCBEF ; 若当前__try的过滤表达式不存在,则向上一层__try搜索 102DCB31 mov edx, [ebp+FramePointer] ; 传入过滤表达式所在的ebp 102DCB34 mov ecx, [ebp+FilterFunc] ; 传入过滤表达式所在的地址 102DCB37 call @_EH4_CallFilterFunc@8 ; 调用__try/__except的过滤表达式 102DCB3C mov [ebp+FilterResult], eax 102DCB3F mov [ebp+Revalidate], 1 102DCB43 cmp [ebp+FilterResult], 0 ; 检查过滤表达式的返回值(excpt.h) 102DCB47 jge short loc_102DCB5A ; if(FilterResult >= EXCEPTION_CONTINUE_SEARCH) goto loc_102DCB5A 102DCB49 mov [ebp+Disposition], 0 102DCB50 jmp loc_102DCBF4 ; 若过滤表达式返回EXCEPTION_CONTINUE_EXECUTION 102DCB50 ; return ExceptionContinueExecution; 102DCB55 ; --------------------------------------------------------------------------- 102DCB55 jmp loc_102DCBEF 102DCB5A ; --------------------------------------------------------------------------- 102DCB5A 102DCB5A loc_102DCB5A: ; CODE XREF: __except_handler4_common+C7j 102DCB5A cmp [ebp+FilterResult], 0 102DCB5E jle loc_102DCBEF ; 若过滤表达式返回EXCEPTION_CONTINUE_SEARCH 102DCB5E ; 跳走,继续向上一层__try搜索 102DCB64 mov eax, [ebp+ExceptionRecord] ; 过滤表达式等于EXCEPTION_EXECUTE_HANDLER的情况 102DCB67 cmp dword ptr [eax], 0E06D7363h 102DCB6D jnz short loc_102DCB98 ; if(ExceptionRecord->ExceptionCode!=0E06D7363h) goto loc_102DCB98 102DCB6F cmp ds:__pDestructExceptionObject, 0 102DCB76 jz short loc_102DCB98 102DCB78 push offset __pDestructExceptionObject ; pTarget 102DCB7D call __IsNonwritableInCurrentImage 102DCB82 add esp, 4 102DCB85 test eax, eax 102DCB87 jz short loc_102DCB98 102DCB89 push 1 ; fThrowNotAllowed 102DCB8B mov ecx, [ebp+ExceptionRecord] 102DCB8E push ecx ; pExcept 102DCB8F call ds:__pDestructExceptionObject 102DCB95 add esp, 8 102DCB98 102DCB98 loc_102DCB98: ; CODE XREF: __except_handler4_common+EDj 102DCB98 ; __except_handler4_common+F6j ... 102DCB98 mov ecx, [ebp+RegistrationNode] 102DCB9B add ecx, 8 ; ecx=EstablisherFrame 102DCB9E call @_EH4_GlobalUnwind@4 ; 进行全局展开 102DCBA3 mov edx, [ebp+RegistrationNode] 102DCBA6 mov eax, [edx+14h] ; 获取最初引发异常的__try块 RegistrationNode->TryLevel 102DCBA9 cmp eax, [ebp+TryLevel] ; 是否是EXCEPTION_EXECUTE_HANDLER所在的__try块 102DCBAC jz short loc_102DCBC4 ; if(TryLevel == RegistrationNode->TryLevel)goto loc_102DCBC4 102DCBAE mov ecx, [ebp+CookiePointer] ; CookiePointer是安全码的地址 102DCBB1 push ecx 102DCBB2 mov edx, [ebp+FramePointer] ; FramePointer是安全码地址上下文的_ebp 102DCBB5 push edx 102DCBB6 mov ecx, [ebp+RegistrationNode] 102DCBB9 add ecx, 8 102DCBBC mov edx, [ebp+TryLevel] 102DCBBF call @_EH4_LocalUnwind@16 ; 进行局部展开 102DCBC4 102DCBC4 loc_102DCBC4: ; CODE XREF: __except_handler4_common+12Cj 102DCBC4 mov eax, [ebp+RegistrationNode] 102DCBC7 mov ecx, [ebp+EnclosingLevel] 102DCBCA mov [eax+14h], ecx ; 设置当前__try块为RegistrationNode->TryLevel=EnclosingLevel 102DCBCD mov edx, [ebp+FramePointer] 102DCBD0 push edx ; FramePointer 102DCBD1 mov eax, [ebp+ScopeTable] 102DCBD4 push eax ; ScopeTable 102DCBD5 mov ecx, [ebp+CookieCheckFunction] 102DCBD8 push ecx ; CookieCheckFunction 102DCBD9 call ValidateLocalCookies ; 验证安全码:GSCookie和EHCookie 102DCBDE add esp, 0Ch 102DCBE1 mov edx, [ebp+FramePointer] 102DCBE4 mov eax, [ebp+ScopeTableRecord] 102DCBE7 mov ecx, [eax+8] ; ecx=ScopeTableRecord->HandlerAddress 102DCBEA call @_EH4_TransferToHandler@8 ; 执行标识为EXCEPTION_EXECUTE_HANDLER的__except块中的代码 102DCBEA ; 这个执行不会返回 102DCBEF 102DCBEF loc_102DCBEF: ; CODE XREF: __except_handler4_common+ABj 102DCBEF ; __except_handler4_common+D5j ... 102DCBEF jmp loc_102DCAF6 ; 向上遍历__try语句 102DCBF4 ; --------------------------------------------------------------------------- 102DCBF4 102DCBF4 loc_102DCBF4: ; CODE XREF: __except_handler4_common+80j 102DCBF4 ; __except_handler4_common+D0j 102DCBF4 jmp short loc_102DCC1B 102DCBF6 ; --------------------------------------------------------------------------- 102DCBF6 102DCBF6 loc_102DCBF6: ; CODE XREF: __except_handler4_common+50j 102DCBF6 mov ecx, [ebp+RegistrationNode] 102DCBF9 cmp dword ptr [ecx+14h], 0FFFFFFFEh 102DCBFD jz short loc_102DCC1B ; if(RegistrationNode->TryLevel==0FFFFFFFEh) goto loc_102DCC1B 102DCBFF mov edx, [ebp+CookiePointer] 102DCC02 push edx 102DCC03 mov eax, [ebp+FramePointer] 102DCC06 push eax 102DCC07 mov ecx, [ebp+RegistrationNode] 102DCC0A add ecx, 8 102DCC0D mov edx, 0FFFFFFFEh 102DCC12 call @_EH4_LocalUnwind@16 ; 执行局部展开 102DCC17 mov [ebp+Revalidate], 1 102DCC1B 102DCC1B loc_102DCC1B: ; CODE XREF: __except_handler4_common:loc_102DCBF4j 102DCC1B ; __except_handler4_common+17Dj 102DCC1B movzx ecx, [ebp+Revalidate] 102DCC1F test ecx, ecx 102DCC21 jz short loc_102DCC37 102DCC23 mov edx, [ebp+FramePointer] 102DCC26 push edx ; FramePointer 102DCC27 mov eax, [ebp+ScopeTable] 102DCC2A push eax ; ScopeTable 102DCC2B mov ecx, [ebp+CookieCheckFunction] 102DCC2E push ecx ; CookieCheckFunction 102DCC2F call ValidateLocalCookies ; 验证安全码:GSCookie和EHCookie 102DCC34 add esp, 0Ch 102DCC37 102DCC37 loc_102DCC37: ; CODE XREF: __except_handler4_common+1A1j 102DCC37 mov eax, [ebp+Disposition] 102DCC3A mov esp, ebp 102DCC3C pop ebp 102DCC3D retn 102DCC3D __except_handler4_common endp ;

相应的伪代码:
/** * *结构化异常处理函数的返回值类型 *typedef enum _EXCEPTION_DISPOSITION { * ExceptionContinueExecution, * ExceptionContinueSearch, * ExceptionNestedException, * ExceptionCollidedUnwind *} EXCEPTION_DISPOSITION; * * VC++扩展SEH的异常帧结构: * [ebp-18] ESP * [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; * }; * * 操作系统原始的SEH异常帧结构 * struct _EXCEPTION_REGISTRATION_RECORD{ * struct _EXCEPTION_REGISTRATION_RECORD *Next; * _except_handler Handler; * } * _except_handler的返回类型 * typedef enum _EXCEPTION_DISPOSITION { * ExceptionContinueExecution, * ExceptionContinueSearch, * ExceptionNestedException, * ExceptionCollidedUnwind * } EXCEPTION_DISPOSITION; * * SEH异常处理函数原型 * EXCEPTION_DISPOSITION __cdecl _except_handler ( * _In_ struct _EXCEPTION_RECORD *_ExceptionRecord, * _In_ void * _EstablisherFrame, * _Inout_ struct _CONTEXT *_ContextRecord, * _Inout_ void * _DispatcherContext * ); * * C/C++运行库使用的SCOPE TABLE结构 * struct _EH4_SCOPETABLE { * DWORD GSCookieOffset; * DWORD GSCookieXOROffset; * DWORD EHCookieOffset; * DWORD EHCookieXOROffset; * struct _EH4_SCOPETABLE_RECORD ScopeRecord; * }; * * C/C++运行库使用的SCOPE TABLE RECORD结构 * struct _EH4_SCOPETABLE_RECORD { * DWORD EnclosingLevel; //上一层__try块 * PVOID FilterFunc; //过滤表达式 * union * { * PVOID HandlerAddress; //__except块代码 * PVOID FinallyFunc; //__finally块代码 * }; * }; * * C/C++运行库使用的异常帧结构 * struct _EH4_EXCEPTION_REGISTRATION_RECORD { * DWORD SavedESP; //异常引发函数在安装SEH时保存ESP. * PEXCEPTION_POINTERS ExceptionPointers; //GetExceptionInformation返回值 * _EXCEPTION_REGISTRATION_RECORD SubRecord; //当前异常帧原始结构 * _EH4_SCOPETABLE * EncodedScopeTable; //当前异常帧的ScopeTable * DWORD TryLevel; //当前__try所在位置 * }; * * *参数说明: * *CookiePointer - 安全码的地址 *CookieCheckFunction - 安全码验证函数的地址 *ExceptionRecord - 异常记录信息 *EstablisherFrame - 异常帧信息 *ContextRecord - 线程上下文 *DispatcherContext - 未知,在全局展开时用于指定下一个异常帧 * **/ _EXCEPTION_DISPOSITION __cdecl _except_handler4_common(unsigned int *CookiePointer, void (__fastcall *CookieCheckFunction)(unsigned int), _EXCEPTION_RECORD *ExceptionRecord, _EXCEPTION_REGISTRATION *EstablisherFrame, _CONTEXT *ContextRecord, void *DispatcherContext ) { BOOL fRevalidate = FALSE; EXCEPTION_DISPOSITION exDisposition = ExceptionContinueSearch; _EH4_EXCEPTION_REGISTRATION_RECORD * pRegistrationNode = (PCHAR)EstablisherFrame - 8; PDWORD pFramePointer = &EstablisherFrame->_ebp; _EH4_SCOPETABLE * pScopeTable = NULL; _EH4_SCOPETABLE_RECORD * pScopeTableRecord = NULL; EXCEPTION_POINTERS epExceptionPointers; DWORD dwTryLevel,dwEnclosingLevel,dwFilterResult; LPVOID lpFilterFunc; //获取并修复ScopeTable. pScopeTable = pRegistrationNode->EncodedScopeTable ^ (*CookiePointer); //验证安全码:GSCookie和EHCookie ValidateLocalCookies(CookieCheckFunction,pScopeTable,pFramePointer); //全局展开时会通过回调_except_handler4_common的方式执行到这里,对当前的异常帧进行局部展开工作 if(ExceptionRecord->ExceptionFlags&0x66) { //当前__try块还存在,执行局部展开 if(pRegistrationNode->TryLevel != 0xFFFFFFFE) { //执行局部展开 _EH4_LocalUnwind(EstablisherFrame,0xFFFFFFFE,pFramePointer,CookiePointer); fRevalidate = TRUE; } //验证安全码:GSCookie和EHCookie if(fRevalidate) { ValidateLocalCookies(CookieCheckFunction,pScopeTable,pFramePointer); } //退出本函数 return exDisposition; } //构建GetExceptionInformation返回值 epExceptionPointers->ExceptionRecord = ExceptionRecord; epExceptionPointers->ContextRecord = ContextRecord; pRegistrationNode->ExceptionPointers = &epExceptionPointers; dwTryLevel = pRegistrationNode->TryLevel; //循环搜索__try块,直到找到__except过滤表达式等于EXCEPTION_EXECUTE_HANDLER的__try块 while(dwTryLevel != 0xFFFFFFFE) { //获取当前__try的Scope记录 pScopeTableRecord = (&pScopeTable->ScopeRecord) + dwTryLevel; //获取当前__try的过滤表达式 lpFilterFunc = pScopeTableRecord->FilterFunc; //获取上一层__try的记录位置 dwEnclosingLevel = pScopeTableRecord->EnclosingLevel; //判断当前__try语句是否过滤表达式,即有无__except语句 if(lpFilterFunc == NULL) { //不存在__except,向上一层__try搜索 dwTryLevel = dwEnclosingLevel; continue; } //传入过滤表达式所在的ebp及其地址,调用过滤表达式 dwFilterResult = _EH4_CallFilterFunc(lpFilterFunc,pFramePointer); fRevalidate = TRUE; //判断过滤表达式的返回值 switch(dwFilterResult) { case EXCEPTION_CONTINUE_SEARCH: // 0 break; case EXCEPTION_EXECUTE_HANDLER: // 1 //作用未知,待分析 if(ExceptionRecord->ExceptionCode==0E06D7363h && __pDestructExceptionObject) { if(__IsNonwritableInCurrentImage(__pDestructExceptionObject)) { __pDestructExceptionObject(ExceptionRecord,TRUE); } } //执行全局展开,内部调用Kernel32.dll!RtlUnwind _EH4_GlobalUnwind(EstablisherFrame); //引发异常的__try块是否是EXCEPTION_EXECUTE_HANDLER所在的__try块. if(pRegistrationNode->TryLevel != dwTryLevel) { //对当前__try块执行局部展开 _EH4_LocalUnwind(EstablisherFrame,dwTryLevel,pFramePointer,CookiePointer); } //设置当前异常帧的__try位置为EXCEPTION_EXECUTE_HANDLER的上一层__try. pRegistrationNode->TryLevel = dwEnclosingLevel; //验证安全码:GSCookie和EHCookie ValidateLocalCookies(CookieCheckFunction,pScopeTable,pFramePointer); //执行__except(EXCEPTION_EXECUTE_HANDLER)块中的代码,不再返回 _EH4_TransferToHandler(pScopeTableRecord->HandlerAddress,pFramePointer); break; case EXCEPTION_CONTINUE_EXECUTION: // -1 exDisposition = ExceptionContinueExecution; //验证安全码:GSCookie和EHCookie if(fRevalidate) { ValidateLocalCookies(CookieCheckFunction,pScopeTable,pFramePointer); } //退出本函数 return exDisposition; } //向上一层__try搜索 dwTryLevel = dwEnclosingLevel; } //验证安全码:GSCookie和EHCookie if(fRevalidate) { ValidateLocalCookies(CookieCheckFunction,pScopeTable,pFramePointer); } //退出本函数 return exDisposition; }

 

其中 ValidateLocalCookies分析如下:

102DCC50 void __cdecl ValidateLocalCookies( 102DCC50 void (__fastcall *CookieCheckFunction)(unsigned int), 102DCC50 _EH4_SCOPETABLE *ScopeTable, 102DCC50 char *FramePointer 102DCC50 ) 102DCC50 ValidateLocalCookies proc near ; CODE XREF: __except_handler4_common+3Fp 102DCC50 ; __except_handler4_common+159p ... 102DCC50 102DCC50 GSCookie = dword ptr -8 102DCC50 EHCookie = dword ptr -4 102DCC50 CookieCheckFunction= dword ptr 8 102DCC50 ScopeTable = dword ptr 0Ch 102DCC50 FramePointer = dword ptr 10h 102DCC50 102DCC50 mov edi, edi 102DCC52 push ebp 102DCC53 mov ebp, esp 102DCC55 sub esp, 8 102DCC58 mov eax, [ebp+ScopeTable] 102DCC5B cmp dword ptr [eax], 0FFFFFFFEh 102DCC5E jz short loc_102DCC83 ; 判断GSCookie是否存在 102DCC60 mov ecx, [ebp+ScopeTable] 102DCC63 mov edx, [ecx] ; 提取GSCookie的偏移:ScopeTable->GSCookieOffset 102DCC65 mov eax, [ebp+FramePointer] ; 提取GSCookie偏移所在的EBP 102DCC68 mov ecx, [eax+edx] ; [GSCookie的偏移+EBP]得到GSCookie的值 102DCC6B mov [ebp+GSCookie], ecx 102DCC6E mov edx, [ebp+ScopeTable] 102DCC71 mov eax, [ebp+FramePointer] 102DCC74 add eax, [edx+4] ; 提取GSCookie异或码:[ScopeTable->GSCookieXOROffset+EBP] 102DCC77 xor eax, [ebp+GSCookie] ; 异或!得到真正的GSCookie. 102DCC7A mov [ebp+GSCookie], eax ; 保存 102DCC7D mov ecx, [ebp+GSCookie] ; ecx传递参数 102DCC80 call [ebp+CookieCheckFunction] ; 验证GSCookie是否与全局变量___security_cookie相符 102DCC83 102DCC83 loc_102DCC83: ; CODE XREF: ValidateLocalCookies+Ej 102DCC83 mov ecx, [ebp+ScopeTable] 102DCC86 mov edx, [ecx+8] ; 提取EHCookie的偏移:ScopeTable->EHCookieOffset 102DCC89 mov eax, [ebp+FramePointer] ; 提取EHCookie偏移所在的EBP 102DCC8C mov ecx, [eax+edx] ; [EHCookie的偏移+EBP]得到EHCookie的值 102DCC8F mov [ebp+EHCookie], ecx 102DCC92 mov edx, [ebp+ScopeTable] 102DCC95 mov eax, [ebp+FramePointer] 102DCC98 add eax, [edx+0Ch] ; 提取EHCookie异或码:[ScopeTable->EHCookieXOROffset+EBP] 102DCC9B xor eax, [ebp+EHCookie] ; 异或!得到真正的EHCookie. 102DCC9E mov [ebp+EHCookie], eax 102DCCA1 mov ecx, [ebp+EHCookie] ; ecx传递参数 102DCCA4 call [ebp+CookieCheckFunction] ; 验证EHCookie是否与全局变量___security_cookie相符 102DCCA7 mov esp, ebp 102DCCA9 pop ebp 102DCCAA retn 102DCCAA ValidateLocalCookies endp /** * * C/C++运行库使用的SCOPE TABLE结构 * struct _EH4_SCOPETABLE { * DWORD GSCookieOffset; * DWORD GSCookieXOROffset; * DWORD EHCookieOffset; * DWORD EHCookieXOROffset; * struct _EH4_SCOPETABLE_RECORD ScopeRecord; * }; * *C/C++运行库使用的SCOPE TABLE RECORD结构 * struct _EH4_SCOPETABLE_RECORD { * DWORD EnclosingLevel; //上一层__try块 * PVOID FilterFunc; //过滤表达式 * union * { * PVOID HandlerAddress; //__except块代码 * PVOID FinallyFunc; //__finally块代码 * }; * }; * * **/ void __cdecl ValidateLocalCookies( void (__fastcall *CookieCheckFunction)(unsigned int), _EH4_SCOPETABLE *ScopeTable, char *EbpPointer ) { DWORD dwGSCookie,dwEHCookie; if(ScopeTable->GSCookieOffset != 0xFFFFFFFE) { dwGSCookie = *(EbpPointer + ScopeTable->GSCookieOffset); dwGSCookie ^= *(EbpPointer + ScopeTable->GSCookieXOROffset); //验证GSCookie是否与全局变量___security_cookie相符(查阅:vc/crt/src/gs_support.c) CookieCheckFunction(dwGSCookie); } dwEHCookie = *(EbpPointer + ScopeTable->EHCookieOffset); dwEHCookie ^= *(EbpPointer + ScopeTable->EHCookieXOROffset); //验证EHCookie是否与全局变量___security_cookie相符 CookieCheckFunction(dwEHCookie); }

 

其中__IsNonwritableInCurrentImage在vc/crt/src/pesect.c中定义,用于判断指定内存地址所在的节是否可写:

/*** *pesect.c - PE image header routines * * Copyright (c) Microsoft Corporation. All rights reserved. * *Purpose: * Defines routines that query info from a PE image header. Because * one of these queries the current PE image, via the linker-defined * variable __ImageBase, this object must be a static-link component * of any C Runtime library. * *******************************************************************************/ #include <windows.h> #if defined (_WIN64) && defined (_M_IA64) #pragma section(".base", long, read) __declspec(allocate(".base")) extern IMAGE_DOS_HEADER __ImageBase; #else /* defined (_WIN64) && defined (_M_IA64) */ extern IMAGE_DOS_HEADER __ImageBase; #endif /* defined (_WIN64) && defined (_M_IA64) */ #pragma optimize("t", on) // optimize for speed, not space /*** *BOOL _ValidateImageBase * *Purpose: * Check if a PE image is located at a potential image base address. * *Entry: * pImageBase - pointer to potential PE image in memory * *Return: * TRUE PE image validated at pImageBase * FALSE PE image not found * *******************************************************************************/ BOOL __cdecl _ValidateImageBase( PBYTE pImageBase ) { PIMAGE_DOS_HEADER pDOSHeader; PIMAGE_NT_HEADERS pNTHeader; PIMAGE_OPTIONAL_HEADER pOptHeader; pDOSHeader = (PIMAGE_DOS_HEADER)pImageBase; if (pDOSHeader->e_magic != IMAGE_DOS_SIGNATURE) { return FALSE; } pNTHeader = (PIMAGE_NT_HEADERS)((PBYTE)pDOSHeader + pDOSHeader->e_lfanew); if (pNTHeader->Signature != IMAGE_NT_SIGNATURE) { return FALSE; } pOptHeader = (PIMAGE_OPTIONAL_HEADER)&pNTHeader->OptionalHeader; if (pOptHeader->Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC) { return FALSE; } return TRUE; } /*** *PIMAGE_SECTION_HEADER _FindPESection * *Purpose: * Given an RVA (Relative Virtual Address, the offset from the Image Base * for a PE image), determine which PE section, if any, includes that RVA. * *Entry: * pImageBase - pointer to PE image in memory * rva - RVA whose enclosing section is to be found * *Return: * NULL RVA is not part by any section in the PE image * non-NULL Pointer to IMAGE_SECTION_HEADER describing the section holding * the RVA * *******************************************************************************/ PIMAGE_SECTION_HEADER __cdecl _FindPESection( PBYTE pImageBase, DWORD_PTR rva ) { PIMAGE_NT_HEADERS pNTHeader; PIMAGE_SECTION_HEADER pSection; unsigned int iSection; pNTHeader = (PIMAGE_NT_HEADERS) (pImageBase + ((PIMAGE_DOS_HEADER)pImageBase)->e_lfanew); // // Find the section holding the desired address. We make no assumptions // here about the sort order of the section descriptors (though they // always appear to be sorted by ascending section RVA). // for (iSection = 0, pSection = IMAGE_FIRST_SECTION(pNTHeader); iSection < pNTHeader->FileHeader.NumberOfSections; ++iSection, ++pSection) { if (rva >= pSection->VirtualAddress && rva < pSection->VirtualAddress + pSection->Misc.VirtualSize) { // // Section found // return pSection; } } // // Section not found // return NULL; } /*** *BOOL _IsNonwritableInCurrentImage * *Purpose: * Check if an address is located within the current PE image (the one * starting at __ImageBase), that it is in a proper section of the image, * and that section is not marked writable. This routine must be * statically linked, not imported from the CRT DLL, so the correct * __ImageBase is found. * *Entry: * pTarget - address to check * *Return: * 0 Address is either not in current image, not in a section, or * in a writable section. * non-0 Address is in a non-writable section of the current image. * *******************************************************************************/ BOOL __cdecl _IsNonwritableInCurrentImage( PBYTE pTarget ) { PBYTE pImageBase; DWORD_PTR rvaTarget; PIMAGE_SECTION_HEADER pSection; pImageBase = (PBYTE)&__ImageBase; __try { // // Make sure __ImageBase does address a PE image. This is likely an // unnecessary check, since we should be running from a normal image, // but it is fast, this routine is rarely called, and the normal call // is for security purposes. If we don't have a PE image, return // failure. // if (!_ValidateImageBase(pImageBase)) { return FALSE; } // // Convert the targetaddress to a Relative Virtual Address (RVA) within // the image, and find the corresponding PE section. Return failure if // the target address is not found within the current image. // rvaTarget = pTarget - pImageBase; pSection = _FindPESection(pImageBase, rvaTarget); if (pSection == NULL) { return FALSE; } // // Check the section characteristics to see if the target address is // located within a writable section, returning a failure if yes. // return (pSection->Characteristics & IMAGE_SCN_MEM_WRITE) == 0; } __except (GetExceptionCode() == STATUS_ACCESS_VIOLATION) { // // Just return failure if the PE image is corrupted in any way that // triggers an AV. // return FALSE; } }

 

从_except_handler4_common的分析中,我们可以看到它和_except_handler3的异常帧处理方式是不一样的。_except_handler3中的scopetable是未加密且结构简单,_except_handler4中的scopetable是加密过的且结构较复杂。

 

以下示例输出所有异常帧结构信息,其中scopetable做了相应的提取方式:

/** *文件: ShowSehFrame.cpp *描述: 输出当前所有已注册(包括C/C++运行库帮我们注册的异常帧)的异常帧信息 *编译: cl.exe ShowSehFrame.cpp *环境: Visual Studio 2008 C/C++编译器 * **/ #include <windows.h> #include <stdio.h> //C/C++运行库使用的SCOPE TABLE RECORD结构 typedef struct _EH4_SCOPETABLE_RECORD { DWORD EnclosingLevel; //上一层__try块 PVOID FilterFunc; //过滤表达式 union { PVOID HandlerAddress; //__except块代码 PVOID FinallyFunc; //__finally块代码 }; }EH4_SCOPETABLE_RECORD,*PEH4_SCOPETABLE_RECORD; //C/C++运行库使用的SCOPE TABLE结构 typedef struct _EH4_SCOPETABLE { DWORD GSCookieOffset; DWORD GSCookieXOROffset; DWORD EHCookieOffset; DWORD EHCookieXOROffset; struct _EH4_SCOPETABLE_RECORD ScopeRecord; }EH4_SCOPETABLE,*PEH4_SCOPETABLE; //SEH异常处理函数原型 typedef EXCEPTION_DISPOSITION (__cdecl *PEXCEPTION_ROUTINE)( struct _EXCEPTION_RECORD *_ExceptionRecord, void * _EstablisherFrame, struct _CONTEXT *_ContextRecord, void * _DispatcherContext ); //C/C++编译器扩展的SEH结构 typedef struct _EXCEPTION_REGISTRATION{ struct _EXCEPTION_REGISTRATION *Prev; PEXCEPTION_ROUTINE Handler; struct _EH4_SCOPETABLE *ScopeTable; int TryLevel; int _Ebp; }EXCEPTION_REGISTRATION,*PEXCEPTION_REGISTRATION; void ShowSehFrames() { DWORD oldProtect; PEXCEPTION_REGISTRATION pRegistration = NULL; __asm mov eax,fs:[0] __asm mov pRegistration,eax while((DWORD)pRegistration != 0xFFFFFFFF) { printf("/n"); PEH4_SCOPETABLE pScopeTable = NULL; PEH4_SCOPETABLE_RECORD pScopeRecord = NULL; //0x0040C000是__security_cookie存放位置,用于解密_except_handler4中的异常帧的ScopeTable VirtualProtect((LPVOID)0x0040C000,4,PAGE_READWRITE,&oldProtect); //还未到达最后一个SEH(最后一个SEH的处理方式中ScopeTable是未加密的) if((DWORD)pRegistration->Prev != 0xFFFFFFFF) { //__except_handler4中异常帧的ScopeTable pScopeTable = (PEH4_SCOPETABLE)(((DWORD)(pRegistration->ScopeTable))^(*((DWORD*)0x0040C000))); pScopeRecord = &pScopeTable->ScopeRecord; } else//__except_handler3中异常帧的ScopeTable pScopeRecord = (PEH4_SCOPETABLE_RECORD)(pRegistration->ScopeTable); printf("Registration:%08x,Prev:%08x,Handler:%08x,TryLevel:%08x/n", pRegistration, pRegistration->Prev, pRegistration->Handler, pRegistration->TryLevel); for(int i = 0; i <= pRegistration->TryLevel; i ++) { printf(" [%d] PrevTryLevel=%08x,FilterFunc=%08x,HandlerAddress=%08x/n", i, pScopeRecord->EnclosingLevel, pScopeRecord->FilterFunc, pScopeRecord->HandlerAddress); pScopeRecord ++; } pRegistration = pRegistration->Prev; } } void Funcition() { __try { __try { ShowSehFrames(); } __except(EXCEPTION_CONTINUE_SEARCH){} } __except(EXCEPTION_CONTINUE_SEARCH){} } int main() { __try { __try { __try { //输出所有异常帧信息,每个函数最多有一个异常帧,总共有4个: //1.Funcition //2.main //3.__tmainCRTStartup //4._BaseProcessStart Funcition(); } __except(EXCEPTION_CONTINUE_SEARCH){} } __except(EXCEPTION_CONTINUE_SEARCH){} } __except(EXCEPTION_CONTINUE_SEARCH){} }

运行结果:

逆向分析MSVCR90D.dll!_except_handler4_common函数_第1张图片

 

MSVCR90D.dll!_except_handler4_common的执行示意图:

逆向分析MSVCR90D.dll!_except_handler4_common函数_第2张图片

你可能感兴趣的:(exception,struct,image,Security,header,Pointers)