引言:RtlUnwind是Kernel32.dll!_except_handler3中的全局展开函数。
7C957A40 ; int __stdcall RtlUnwind(PVOID TargetFrame, PVOID TargetIp, 7C957A40 PEXCEPTION_RECORD ExceptionRecord, PVOID ReturnValue) 7C957A40 7C957A40 varExceptionRecord= EXCEPTION_RECORD ptr -37Ch 7C957A40 varExcptRecordTemp= EXCEPTION_RECORD ptr -32Ch 7C957A40 varDispatcherContext= dword ptr -2DCh 7C957A40 StackBottom = dword ptr -2D8h 7C957A40 StackTop = dword ptr -2D4h 7C957A40 varContext = CONTEXT ptr -2D0h 7C957A40 varSecurityCookie= dword ptr -4 7C957A40 TargetFrame = dword ptr 8 7C957A40 TargetIp = dword ptr 0Ch 7C957A40 ExceptionRecord = dword ptr 10h 7C957A40 ReturnValue = dword ptr 14h 7C957A40 7C957A40 ; FUNCTION CHUNK AT .text:7C96EAFF SIZE 000000C5 BYTES 7C957A40 7C957A40 mov edi, edi 7C957A42 push ebp 7C957A43 mov ebp, esp 7C957A45 sub esp, 37Ch 7C957A4B mov eax, ___security_cookie; XP SP2固定值:0BB40h 7C957A50 push esi 7C957A51 mov esi, [ebp+ExceptionRecord] 7C957A54 mov [ebp+varSecurityCookie], eax 7C957A57 push edi 7C957A58 lea eax, [ebp+StackTop] 7C957A5E push eax ; StackTop 7C957A5F lea eax, [ebp+StackBottom] 7C957A65 push eax ; StackBottom 7C957A66 call _RtlpGetStackLimits@8 ; 获取当前线程堆栈的界限,分别存放在StackTop、StackBottom 7C957A6B xor edi, edi ; edi清零 7C957A6D cmp esi, edi 7C957A6F jnz short loc_7C957A9C ; if(ExceptionRecord!=NULL) goto loc_7C957A9C 7C957A71 mov eax, [ebp+4] ; 获取RtlUnwind的返回地址 7C957A74 lea esi, [ebp+varExceptionRecord] 7C957A7A mov [ebp+varExceptionRecord.ExceptionCode], 0C0000027h ; STATUS_UNWIND(ntstatus.h) 7C957A84 mov [ebp+varExceptionRecord.ExceptionFlags], edi 7C957A8A mov [ebp+varExceptionRecord.ExceptionRecord], edi 7C957A90 mov [ebp+varExceptionRecord.ExceptionAddress], eax ; RtlUnwind的返回地址 7C957A96 mov [ebp+varExceptionRecord.NumberParameters], edi 7C957A9C 7C957A9C loc_7C957A9C: ; CODE XREF: RtlUnwind(x,x,x,x)+2Fj 7C957A9C cmp [ebp+TargetFrame], edi 7C957A9C ; [loc_7C957A9C ~ loc_7C957AA9)的分析: 7C957A9C ; 7C957A9C ; //设置当前异常SEH帧的ExceptionFlags标识,为全局展开做准备 7C957A9C ; if(TargetFrame==NULL) 7C957A9C ; varExceptionRecord.ExceptionFlags|=EXCEPTION_UNWIND_CONTEXT 7C957A9C ; else 7C957A9C ; varExceptionRecord.ExceptionFlags|=EXCEPTION_UNWINDING(exsup.inc) 7C957A9F jz loc_7C957B77 7C957AA5 or dword ptr [esi+4], 2 ; EXCEPTION_UNWINDING(exsup.inc) 7C957AA9 7C957AA9 loc_7C957AA9: ; CODE XREF: RtlUnwind(x,x,x,x)+13Bj 7C957AA9 push ebx 7C957AAA lea eax, [ebp+varContext] 7C957AB0 push eax 7C957AB1 mov [ebp+varContext.ContextFlags], 10007h 7C957AB1 ; CONTEXT_i486|CONTEXT_CONTROL|CONTEXT_INTEGER|CONTEXT_SEGMENTS(WinNT.h) 7C957ABB call _RtlpCaptureContext@4 7C957ABB ; 填充varContext,注意填充后: 7C957ABB ; varContext->Eip=[ebp+4],即:RtlUnwind的返回地址 7C957ABB ; varContext->Ebp=[ebp+0],即:RtlUnwind调用者的ebp 7C957ABB ; varContext->Esp= ebp+8 ,即:&TargetFrame 7C957AC0 mov eax, [ebp+ReturnValue] 7C957AC3 add [ebp+varContext._Esp], 10h ; _Esp等于没有压栈调用RtlUnwind之前的esp值 7C957ACA mov [ebp+varContext._Eax], eax 7C957AD0 call _RtlpGetRegistrationHead@0 ; 从FS:[0]获取首个SEH异常帧(链表形式) 7C957AD5 mov ebx, eax 7C957AD7 cmp ebx, 0FFFFFFFFh 7C957ADA jz loc_7C96EB9A ; //FS:[0]已不存在任何SEH异常帧!RtlUnwind退出! 7C957ADA ; if(FS:[0]==0xFFFFFFFF) 7C957ADA ; { 7C957ADA ; //TargetFrame还存在的话,抛出异常并退出! 7C957ADA ; if(TargetFrame!=0xFFFFFFFF) 7C957ADA ; return ZwRaiseException(&varExceptionRecord,&varContext,0); 7C957ADA ; 7C957ADA ; //退出! 7C957ADA ; return ZwContinue(&varContext,0); 7C957ADA ; } 7C957AE0 xor edi, edi ; edi=0 7C957AE2 inc edi ; edi=1 7C957AE3 7C957AE3 loc_7C957AE3: ; CODE XREF: RtlUnwind(x,x,x,x)+122j 7C957AE3 cmp ebx, [ebp+TargetFrame] 7C957AE6 jz short loc_7C957B67 ; 判断当前FS:[0]异常帧是否为TargetFrame? 7C957AE8 cmp [ebp+TargetFrame], 0 7C957AEC jz short loc_7C957AF7 7C957AEE cmp [ebp+TargetFrame], ebx 7C957AF1 jb loc_7C96EAFF ; [loc_7C957AE3 ~ loc_7C957AF7)代码分析: 7C957AF1 ; 7C957AF1 ; if(FS:[0]==TargetFrame) 7C957AF1 ; { 7C957AF1 ; ZwContinue(&varContext,0) 7C957AF1 ; } 7C957AF1 ; else if(TargetFrame && TargetFrame < FS:[0]) 7C957AF1 ; { 7C957AF1 ; //如果存在某个异常帧在堆栈上的位置比异常链表的头部还低,说明出了错! 7C957AF1 ; //EXCEPTION_NONCONTINUABLE标识当前进程不能再继续进行,必须终止! 7C957AF1 ; varExcptRecordTemp.NumberParameters = 0; 7C957AF1 ; varExcptRecordTemp.ExceptionCode = STATUS_INVALID_UNWIND_TARGET; 7C957AF1 ; varExcptRecordTemp.ExceptionFlags = EXCEPTION_NONCONTINUABLE; 7C957AF1 ; varExcptRecordTemp.ExceptionRecord = &varExceptionRecord; 7C957AF1 ; RtlRaiseException(&varExcptRecordTemp); 7C957AF1 ; } 7C957AF7 7C957AF7 loc_7C957AF7: ; CODE XREF: RtlUnwind(x,x,x,x)+ACj 7C957AF7 ; RtlUnwind(x,x,x,x)+135j ... 7C957AF7 cmp ebx, [ebp+StackBottom] 7C957AFD jb loc_7C96EB6A ; FS:[0]低于栈底!跳走,产生一个异常并处理下一个SEH帧. 7C957B03 lea eax, [ebx+8] 7C957B06 cmp eax, [ebp+StackTop] ; 判断这个FS:[0]是否都在栈的范围内 7C957B0C ja loc_7C96EB6A ; FS:[0]有部分已超出栈顶!跳走,产生一个异常并处理下一个SEH帧. 7C957B12 test bl, 3 7C957B15 jnz loc_7C96EB6A ; FS:[0]指针值非4的倍数!跳走,产生一个异常并处理下一个SEH帧 7C957B1B mov eax, [ebx+4] 7C957B1E cmp eax, [ebp+StackBottom] 7C957B24 jb short loc_7C957B32 ; FS:[0]->handler不在堆栈范围内!跳走loc_7C957B32,执行handler 7C957B26 cmp eax, [ebp+StackTop] 7C957B2C jb loc_7C96EB6A ; FS:[0]->handler也在堆栈范围内!跳走,产生一个异常并处理下一个SEH帧 7C957B32 7C957B32 loc_7C957B32: ; CODE XREF: RtlUnwind(x,x,x,x)+E4j 7C957B32 push eax ; FS:[0]->handler,实际上还是_except_handler3. 7C957B33 lea eax, [ebp+varDispatcherContext] 7C957B39 push eax ; DispatcherContext 7C957B3A lea eax, [ebp+varContext] 7C957B40 push eax ; &varContext 7C957B41 push ebx ; FS:[0] 7C957B42 push esi ; &varExceptionRecord 7C957B42 ; 注意:varExceptionRecord.ExceptionFlags=EXCEPTION_UNWINDING或EXCEPTION_UNWIND_CONTEXT 7C957B43 call _RtlpExecuteHandlerForUnwind@20 ; 7C957B43 ; 执行FS:[0]->handler,进行当前SEH帧的局部展开工作(参阅:_except_handler3). 7C957B43 ; 其返回值类型如下: 7C957B43 ; typedef enum _EXCEPTION_DISPOSITION { 7C957B43 ; ExceptionContinueExecution, 7C957B43 ; ExceptionContinueSearch, 7C957B43 ; ExceptionNestedException, 7C957B43 ; ExceptionCollidedUnwind 7C957B43 ; } EXCEPTION_DISPOSITION; 7C957B48 dec eax 7C957B49 jnz loc_7C96EB2D ; if(eax!=ExceptionContinueSearch) 7C957B49 ; 执行当前SEH帧的局部展开过程发生异常(参阅:__local_unwind2) 7C957B49 ; goto loc_7C96EB2D 7C957B49 ; if(eax==ExceptionContinueSearch) goto loc_7C957B4F 7C957B4F 7C957B4F loc_7C957B4F: ; CODE XREF: RtlUnwind(x,x,x,x)+1711Aj 7C957B4F ; RtlUnwind(x,x,x,x)+17125j 7C957B4F mov eax, ebx 7C957B51 mov ebx, [ebx] ; ebx=FS:[0]->prev 7C957B53 push eax ; EstablisherFrame 7C957B54 call _RtlpUnlinkHandler@4 ; 设置FS:[0]为其下一个SEH. 7C957B59 7C957B59 loc_7C957B59: ; CODE XREF: RtlUnwind(x,x,x,x)+17153j 7C957B59 cmp ebx, 0FFFFFFFFh 7C957B5C jz loc_7C96EB98 ; 判断FS:[0]是否处理完毕,若处理完毕跳走退出! 7C957B62 jmp loc_7C957AE3 ; 循环处理FS:[0]下一个SEH 7C957B67 ; --------------------------------------------------------------------------- 7C957B67 7C957B67 loc_7C957B67: ; CODE XREF: RtlUnwind(x,x,x,x)+A6j 7C957B67 push 0 ; int 7C957B69 lea eax, [ebp+varContext] 7C957B6F push eax ; ContextRecord 7C957B70 call _ZwContinue@8 ; ZwContinue(&varContext,0) 7C957B75 jmp short loc_7C957AF7 7C957B77 ; --------------------------------------------------------------------------- 7C957B77 7C957B77 loc_7C957B77: ; CODE XREF: RtlUnwind(x,x,x,x)+5Fj 7C957B77 or dword ptr [esi+4], 6 ; varExceptionRecord.ExceptionFlags|=EXCEPTION_UNWIND_CONTEXT 7C957B7B jmp loc_7C957AA9 7C957B7B _RtlUnwind@16 endp 7C96EB2D loc_7C96EB2D: ; CODE XREF: RtlUnwind(x,x,x,x)+109j 7C96EB2D dec eax 7C96EB2E dec eax 7C96EB2F jz short loc_7C96EB5F ; 7C96EB2F ; if(eax==ExceptionCollidedUnwind) goto loc_7C96EB5F 7C96EB2F ; if(eax!=ExceptionCollidedUnwind) 7C96EB2F ; 展开发生冲突异常 7C96EB2F ; goto 7C96EB31 7C96EB31 and [ebp+varExcptRecordTemp.NumberParameters], 0 7C96EB38 lea eax, [ebp+varExcptRecordTemp] 7C96EB3E push eax 7C96EB3F mov [ebp+varExcptRecordTemp.ExceptionCode], 0C0000026h ; STATUS_INVALID_DISPOSITION(ntstatus.h) 7C96EB49 mov [ebp+varExcptRecordTemp.ExceptionFlags], edi ; edi=EXCEPTION_NONCONTINUABLE(WinNT.h) 7C96EB4F mov [ebp+varExcptRecordTemp.ExceptionRecord], esi 7C96EB55 call _RtlRaiseException@4 ; 全局展开发生冲突,引发新的异常! 7C96EB5A jmp loc_7C957B4F 7C96EB5F ; --------------------------------------------------------------------------- 7C96EB5F 7C96EB5F loc_7C96EB5F: ; CODE XREF: RtlUnwind(x,x,x,x)+170EFj 7C96EB5F mov ebx, [ebp+varDispatcherContext] 7C96EB65 jmp loc_7C957B4F 7C96EB6A ; --------------------------------------------------------------------------- 7C96EB6A loc_7C96EB6A: ; CODE XREF: RtlUnwind(x,x,x,x)+BDj 7C96EB6A ; RtlUnwind(x,x,x,x)+CCj ... 7C96EB6A and [ebp+varExcptRecordTemp.NumberParameters], 0 7C96EB71 lea eax, [ebp+varExcptRecordTemp] 7C96EB77 push eax 7C96EB78 mov [ebp+varExcptRecordTemp.ExceptionCode], 0C0000028h 7C96EB82 mov [ebp+varExcptRecordTemp.ExceptionFlags], edi 7C96EB88 mov [ebp+varExcptRecordTemp.ExceptionRecord], esi 7C96EB8E call _RtlRaiseException@4 ; RtlRaiseException(x) 7C96EB93 jmp loc_7C957B59 7C96EB98 ; --------------------------------------------------------------------------- 7C96EB98 7C96EB98 loc_7C96EB98: ; CODE XREF: RtlUnwind(x,x,x,x)+11Cj 7C96EB98 xor edi, edi 7C96EB9A 7C96EB9A loc_7C96EB9A: ; CODE XREF: RtlUnwind(x,x,x,x)+9Aj 7C96EB9A cmp [ebp+TargetFrame], 0FFFFFFFFh 7C96EB9E pop ebx 7C96EB9F lea eax, [ebp+varContext] 7C96EBA5 push edi ; edi=0 7C96EBA6 push eax ; eax=&varContext 7C96EBA7 jnz short loc_7C96EBB0 ; //TargetFrame还存在的话,抛出异常并退出! 7C96EBA7 ; if(TargetFrame!=0xFFFFFFFF) goto loc_7C96EBB0 7C96EBA9 call _ZwContinue@8 ; ZwContinue(&varContext,0) 7C96EBAE jmp short loc_7C96EBB6 ; 退出RtlUnwind 7C96EBB0 ; --------------------------------------------------------------------------- 7C96EBB0 7C96EBB0 loc_7C96EBB0: ; CODE XREF: RtlUnwind(x,x,x,x)+17167j 7C96EBB0 push esi ; esi=&varExceptionRecord 7C96EBB1 call _ZwRaiseException@12 ; ZwRaiseException(&varExceptionRecord,&varContext,0) 7C96EBB6 7C96EBB6 loc_7C96EBB6: ; CODE XREF: RtlUnwind(x,x,x,x)+1716Ej 7C96EBB6 mov ecx, [ebp+varSecurityCookie] ; 提取原先保存好的安全码 7C96EBB9 pop edi 7C96EBBA pop esi 7C96EBBB call @__security_check_cookie@4 ; 安全性检查 7C96EBC0 leave 7C96EBC1 retn 10h 7C96EBC1 ; END OF FUNCTION CHUNK FOR _RtlUnwind@16
相应的伪代码:
/** * 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; * } * * RtlUnwind函数原型(Winternl.h) * void WINAPI RtlUnwind( * __in_opt PVOID TargetFrame, * __in_opt PVOID TargetIp, * __in_opt PEXCEPTION_RECORD ExceptionRecord, * __in PVOID ReturnValue * ); * * _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 * ); * **/ int __stdcall RtlUnwind(PVOID TargetFrame, PVOID TargetIp, PEXCEPTION_RECORD ExceptionRecord, PVOID ReturnValue) { EXCEPTION_REGISTRATION *pEstablisherFrame; EXCEPTION_RECORD excptRecord,excptRecordTemp; PVOID *pDispatcherContext; DWORD dwStackBottom,dwStackTop,dwSecurityCookie; CONTEXT ctxRecord; EXCEPTION_DISPOSITION eReturnValue; //提取安全码,XP SP2下固定值:0BB40h dwSecurityCookie = ___security_cookie; //获取当前线程堆栈的界限 _RtlpGetStackLimits(&dwStackBottom,&dwStackTop); //正常情况为NULL if(ExceptionRecord == NULL) { excptRecord.ExceptionCode = STATUS_UNWIND; excptRecord.ExceptionFlags = 0; excptRecord.ExceptionRecord = 0; excptRecord.ExceptionAddress= (PCHAR)&TargetFrame - 4; //RtlUnwind的返回地址 excptRecord.NumberParameters= 0; } //设置当前异常SEH帧的ExceptionFlags标识,为全局展开做准 if(TargetFrame) excptRecord.ExceptionFlags |= EXCEPTION_UNWINDING; else excptRecord.ExceptionFlags |= EXCEPTION_UNWIND_CONTEXT; //获取线程上下文环境信息,包括通用寄存器、段寄存器、浮点寄存器. //其中设置了ctxRecord._Eip为RtlUnwind的返回地址 ctxRecord.ContextFlags = CONTEXT_i486|CONTEXT_CONTROL|CONTEXT_INTEGER|CONTEXT_SEGMENTS; _RtlpCaptureContext(&ctxRecord); ctxRecord._Esp += 0x10; //_Esp等于还没压栈调用RtlUnwind之前调用者的esp值 ctxRecord._Eax = ReturnValue; //从FS:[0]获取首个SEH异常帧(链表形式) _RtlpGetRegistrationHead(&pEstablisherFrame); //FS:[0]已不存在任何SEH异常帧! if(pEstablisherFrame==0xFFFFFFFF) { //若TargetFrame存在的话,就不正常 if(TargetFrame != 0xFFFFFFFF) { //引发一个异常 return _ZwRaiseException(&excptRecord,&ctxRecord,0); } return _ZwContinue(&ctxRecord,0); } do { if(pEstablisherFrame == TargetFrame) { //_ZwContinue恢复一个线程的执行,相当于退出本函数 //执行ctxRecord._Eip指向的指令,这里即RtlUnwind的返回地址! _ZwContinue(&ctxRecord,0); } else if(TargetFrame && TargetFrame < pEstablisherFrame) { //如果存在某个异常帧在堆栈上的位置比异常链表的头部还低,说明出了错! //EXCEPTION_NONCONTINUABLE标识当前进程不能再继续进行,必须终止! excptRecordTemp.NumberParameters = 0; excptRecordTemp.ExceptionCode = STATUS_INVALID_UNWIND_TARGET; excptRecordTemp.ExceptionFlags = EXCEPTION_NONCONTINUABLE; excptRecordTemp.ExceptionRecord = &excptRecord; _RtlRaiseException(&excptRecordTemp); } //验证SEH异常帧是否在正确的栈范围 //验证SEH异常帧地址是否4字节对齐 //验证异常处理函数不应在栈的范围 if((pEstablisherFrame < dwStackBottom)|| (((PCHAR)pEstablisherFrame + sizeof(_EXCEPTION_REGISTRATION_RECORD)) > dwStackTop)|| (pEstablisherFrame & 0x3) || ((pEstablisherFrame->handler >= dwStackBottom)&&(pEstablisherFrame->handler < dwStackTop))) { excptRecordTemp.NumberParameters = 0; excptRecordTemp.ExceptionCode = STATUS_BAD_STACK; excptRecordTemp.ExceptionFlags = EXCEPTION_NONCONTINUABLE; excptRecordTemp.ExceptionRecord = &excptRecord; _RtlRaiseException(&excptRecordTemp); continue; } //执行展开操作,内部回调pEstablisherFrame->handler,也即_except_handler3函数. //进行当前SEH帧的局部展开工作(参阅:_except_handler3) eReturnValue = _RtlpExecuteHandlerForUnwind(&excptRecord,pEstablisherFrame, &ctxRecord,&pDispatcherContext,pEstablisherFrame->handler); if(eReturnValue != ExceptionContinueSearch) { //执行当前SEH帧的局部展开过程发生异常(参阅:__local_unwind2) if(eReturnValue == ExceptionCollidedUnwind) pEstablisherFrame = pDispatcherContext; // 未知涵义! else { excptRecordTemp.NumberParameters = 0; excptRecordTemp.ExceptionCode = STATUS_INVALID_DISPOSITION; excptRecordTemp.ExceptionFlags = EXCEPTION_NONCONTINUABLE; excptRecordTemp.ExceptionRecord = &excptRecord; _RtlRaiseException(&excptRecordTemp); } } //设置FS:[0],使之指向pEstablisherFrame的下一个SEH帧 _RtlpUnlinkHandler(pEstablisherFrame); pEstablisherFrame = pEstablisherFrame->prev; } while(pEstablisherFrame!=0xFFFFFFFF); //若TargetFrame还存在的话,抛出异常并退出! if(TargetFrame != 0xFFFFFFFF) { //引发一个异常 return _ZwRaiseException(&excptRecord,&ctxRecord,0); } return _ZwContinue(&ctxRecord,0); }
几个子函数的简要分析:
1、_RtlpGetStackLimits获取当前线程堆栈的界限
7C92390C ; int __stdcall RtlpGetStackLimits(int StackBottom, int StackTop) 7C92390C _RtlpGetStackLimits@8 proc near ; CODE XREF: RtlDispatchException(x,x)+2Ap 7C92390C ; RtlUnwind(x,x,x,x)+26p 7C92390C 7C92390C StackBottom = dword ptr 4 7C92390C StackTop = dword ptr 8 7C92390C 7C92390C mov eax, large fs:8 7C923912 mov ecx, [esp+StackBottom] 7C923916 mov [ecx], eax 7C923918 mov eax, large fs:4 7C92391E mov ecx, [esp+StackTop] 7C923922 mov [ecx], eax 7C923924 retn 8 7C923924 _RtlpGetStackLimits@8 endp
2、_RtlpCaptureContext获取特定Context的信息
7C92387B ; __stdcall RtlpCaptureContext(CONTEXT *ContextRecord) 7C92387B _RtlpCaptureContext@4: ; CODE XREF: RtlUnwind(x,x,x,x)+7Bp 7C92387B push ebx 7C92387C mov ebx, [esp+4+ContextRecord] 7C923880 mov dword ptr [ebx+0B0h], 0 ; ContextRecord->Eax=0 7C92388A mov dword ptr [ebx+0ACh], 0 ; ContextRecord->Ecx=0 7C923894 mov dword ptr [ebx+0A8h], 0 ; ContextRecord->Edx=0 7C92389E mov dword ptr [ebx+0A4h], 0 ; ContextRecord->Ebx=0 7C9238A8 mov dword ptr [ebx+0A0h], 0 ; ContextRecord->Esi=0 7C9238B2 mov dword ptr [ebx+9Ch] , 0 ; ContextRecord->Edi=0 7C9238BC 7C9238BC loc_7C9238BC: ; CODE XREF: RtlCaptureContext(x)+2Cj 7C9238BC mov word ptr [ebx+0BCh], cs ; ContextRecord->SegCs=cs 7C9238C2 mov word ptr [ebx+98h] , ds ; ContextRecord->SegDs=ds 7C9238C8 mov word ptr [ebx+94h] , es ; ContextRecord->SegEs=es 7C9238CE mov word ptr [ebx+90h] , fs ; ContextRecord->SegFs=fs 7C9238D4 mov word ptr [ebx+8Ch] , gs ; ContextRecord->SegGs=gs 7C9238DA mov word ptr [ebx+0C8h], ss ; ContextRecord->SegSs=ss 7C9238E0 pushf 7C9238E1 pop dword ptr [ebx+0C0h] ; ContextRecord->EFlags=flags 7C9238E7 mov eax, [ebp+4] ; eax=RtlUnwind的返回地址 7C9238EA mov [ebx+0B8h], eax ; ContextRecord->Eip=eax=[ebp+4] 7C9238F0 mov eax, [ebp+0] 7C9238F3 mov [ebx+0B4h], eax ; ContextRecord->Ebp=[ebp+0] 7C9238F9 lea eax, [ebp+8] 7C9238FC mov [ebx+0C4h], eax ; ContextRecord->Esp=ebp+8 7C923902 pop ebx 7C923903 retn 4 7C923903 _RtlCaptureContext@4 endp
3、_RtlpGetRegistrationHead从FS:[0]获取首个SEH异常帧
7C92392D ; int __stdcall RtlpGetRegistrationHead() 7C92392D _RtlpGetRegistrationHead@0 proc near; CODE XREF: RtlDispatchException(x,x)+2Fp 7C92392D ; RtlUnwind(x,x,x,x)+90p 7C92392D mov eax, large fs:0 7C923933 retn 7C923933 _RtlpGetRegistrationHead@0 endp
4、_RtlpExecuteHandlerForUnwind针对特定SEH帧执行局部展开操作
7C923760 ; int __stdcall RtlpExecuteHandlerForUnwind( 7C923760 struct EXCEPTION_RECORD *ExceptionRecord, 7C923760 struct EXCEPTION_REGISTRATION *EstablisherFrame, 7C923760 struct _CONTEXT *Context, void *DispatcherContext, 7C923760 void *EstablisherFrameHandler) 7C923760 ; CODE XREF: RtlUnwind(x,x,x,x)+103p 7C923760 7C923760 ExceptionRecord = dword ptr 4 7C923760 EstablisherFrame= dword ptr 8 7C923760 Context = dword ptr 0Ch 7C923760 DispatcherContext= dword ptr 10h 7C923760 EstablisherFrameHandler= dword ptr 14h 7C923760 7C923760 mov edx, offset sub_7C923804 ;用于RtlpExecuteHandlerForUnwind的异常处理函数 7C923765 lea ecx, [ecx] 7C923765 _RtlpExecuteHandlerForUnwind@20 endp; sp-analysis failed 7C923765 7C923767 7C923767 ; =============== S U B R O U T I N E ======================================= 7C923767 7C923767 7C923767 ; int __stdcall ExecuteHandler( 7C923767 struct EXCEPTION_RECORD *ExceptionRecord, 7C923767 struct EXCEPTION_REGISTRATION *EstablisherFrame, 7C923767 struct _CONTEXT *Context, void *DispatcherContext, 7C923767 void *EstablisherFrameHandler) 7C923767 7C923767 ExceptionRecord = dword ptr 4 7C923767 EstablisherFrame= dword ptr 8 7C923767 Context = dword ptr 0Ch 7C923767 DispatcherContext= dword ptr 10h 7C923767 EstablisherFrameHandler= dword ptr 14h 7C923767 7C923767 push ebx 7C923768 push esi 7C923769 push edi 7C92376A xor eax, eax 7C92376C xor ebx, ebx 7C92376E xor esi, esi 7C923770 xor edi, edi 7C923772 push [esp+0Ch+EstablisherFrameHandler] ; EstablisherFrameHandler 7C923776 push [esp+10h+DispatcherContext] ; DispatcherContext 7C92377A push [esp+14h+Context] ; Context 7C92377E push [esp+18h+EstablisherFrame] ; EstablisherFrame 7C923782 push [esp+1Ch+ExceptionRecord] ; ExceptionRecord 7C923786 call ExecuteHandler2@20 7C92378B pop edi 7C92378C pop esi 7C92378D pop ebx 7C92378E retn 14h 7C92378E ExecuteHandler@20 endp 7C923799 ; int __stdcall ExecuteHandler2( 7C923799 struct EXCEPTION_RECORD *ExceptionRecord, 7C923799 struct EXCEPTION_REGISTRATION *EstablisherFrame, 7C923799 struct _CONTEXT *Context, 7C923799 void *DispatcherContext, 7C923799 void *EstablisherFrameHandler) 7C923799 ExecuteHandler2@20 proc near ; CODE XREF: ExecuteHandler@20+1Fp 7C923799 7C923799 ExceptionRecord = dword ptr 8 7C923799 EstablisherFrame= dword ptr 0Ch 7C923799 Context = dword ptr 10h 7C923799 DispatcherContext= dword ptr 14h 7C923799 EstablisherFrameHandler= dword ptr 18h 7C923799 7C923799 push ebp 7C92379A mov ebp, esp 7C92379C push [ebp+EstablisherFrame] 7C92379F push edx ;handler,查阅7C923760处代码 7C9237A0 push large dword ptr fs:0 7C9237A7 mov large fs:0, esp ;安装SEH异常处理结构 7C9237AE push [ebp+DispatcherContext] 7C9237B1 push [ebp+Context] 7C9237B4 push [ebp+EstablisherFrame] 7C9237B7 push [ebp+ExceptionRecord] 7C9237BA mov ecx, [ebp+EstablisherFrameHandler] 7C9237BD call ecx 7C9237BF mov esp, large fs:0 7C9237C6 pop large dword ptr fs:0 7C9237CD mov esp, ebp 7C9237CF pop ebp 7C9237D0 retn 14h 7C9237D0 ExecuteHandler2@20 endp 7C923804 ; int __stdcall sub_7C923804( 7C923804 _EXCEPTION_RECORD *ExceptionRecord, 7C923804 struct _EXCEPTION_REGISTRATION *EstablisherFrame, 7C923804 struct _CONTEXT *ContextRecord, 7C923804 void *DispatcherContext) 7C923804 sub_7C923804 proc near ; DATA XREF: RtlpExecuteHandlerForUnwind(x,x,x,x,x)o 7C923804 7C923804 ExceptionRecord = dword ptr 4 7C923804 EstablisherFrame= dword ptr 8 7C923804 ContextRecord = dword ptr 0Ch 7C923804 DispatcherContext= dword ptr 10h 7C923804 7C923804 mov ecx, [esp+ExceptionRecord] 7C923808 test dword ptr [ecx+4], 6 7C92380F mov eax, 1 7C923814 jz short locret_7C923828 7C923816 mov ecx, [esp+EstablisherFrame] 7C92381A mov edx, [esp+DispatcherContext] 7C92381E mov eax, [ecx+8] 7C923821 mov [edx], eax 7C923823 mov eax, 3 7C923828 7C923828 locret_7C923828: ; CODE XREF: sub_7C923804+10j 7C923828 retn 10h 7C923828 sub_7C923804 endp
5、_RtlpUnlinkHandler设置FS:[0]为其下一个SEH
7C923830 ; int __stdcall RtlpUnlinkHandler(struct _EXCEPTION_REGISTRATION *EstablisherFrame) 7C923830 _RtlpUnlinkHandler@4 proc near ; CODE XREF: RtlUnwind(x,x,x,x)+114p 7C923830 7C923830 EstablisherFrame= dword ptr 4 7C923830 7C923830 mov ecx, [esp+EstablisherFrame] 7C923834 mov ecx, [ecx] ; ecx=EstablisherFrame->prev 7C923836 mov large fs:0, ecx 7C92383D retn 4 7C92383D _RtlpUnlinkHandler@4 endp
6、_ZwContinue恢复一个线程的执行,执行地址由ContextRecord._Eip指定.(其调用系统服务ZwContinue)
7C92D619 ; int __stdcall ZwContinue(CONTEXT *ContextRecord, int) 7C92D619 public _ZwContinue@8 7C92D619 _ZwContinue@8 proc near ; CODE XREF: KiUserApcDispatcher(x,x,x,x,x)+Ap 7C92D619 ; KiUserExceptionDispatcher(x,x)+17p ... 7C92D619 7C92D619 ContextRecord = dword ptr 4 7C92D619 arg_4 = dword ptr 8 7C92D619 7C92D619 mov eax, 20h ; NtContinue功能号 7C92D61E mov edx, 7FFE0300h 7C92D623 call dword ptr [edx] 7C92D625 retn 8 7C92D625 _ZwContinue@8 endp
全局展开示意图: