首页 > VMP > VMP-异常处理SEH4结构
2016四月18

VMP-异常处理SEH4结构

[隐藏]

1.TIB(线程信息块)

0:000> dt ntdll!_TEB
   +0x000 NtTib            : _NT_TIB
typedef struct _NT_TIB {
    struct _EXCEPTION_REGISTRATION_RECORD *ExceptionList;
    PVOID StackBase;
    PVOID StackLimit;
    PVOID SubSystemTib;
    union {
        PVOID FiberData;
        DWORD Version;
    };
    PVOID ArbitraryUserPointer;
    struct _NT_TIB *Self;
} NT_TIB;
typedef NT_TIB *PNT_TIB;

ExceptionList,正好位于TEB的偏移0处,总是由[FS:0]指向的,这个结构是用来注册我们的_except_handler()即:异常处理程序

EXCEPTION_DISPOSITION __cdecl _except_handler (
    _In_ struct _EXCEPTION_RECORD *_ExceptionRecord,
    _In_ void * _EstablisherFrame,
    _Inout_ struct _CONTEXT *_ContextRecord,
    _Inout_ void * _DispatcherContext
    );

_EXCEPTION_REGISTRATION_RECORD的结构如下:

typedef
EXCEPTION_DISPOSITION
(*PEXCEPTION_ROUTINE) (
    IN struct _EXCEPTION_RECORD *ExceptionRecord,
    IN PVOID EstablisherFrame,
    IN OUT struct _CONTEXT *ContextRecord,
    IN OUT PVOID DispatcherContext
    );
typedef struct _EXCEPTION_REGISTRATION_RECORD {
    struct _EXCEPTION_REGISTRATION_RECORD *Next;// 下一个,从而形成链
    PEXCEPTION_ROUTINE Handler;
} EXCEPTION_REGISTRATION_RECORD;

PEXCEPTION_ROUTINE指向的就是一个_except_handler.

构建及调用SEH链的代码如下:

EXCEPTION_DISPOSITION HGYSEH(
					   IN struct _EXCEPTION_RECORD *ExceptionRecord,
					   IN PVOID EstablisherFrame,
					   IN OUT struct _CONTEXT *ContextRecord,
					   IN OUT PVOID DispatcherContext
					   )
{
	return ExceptionContinueSearch;
}

int _tmain(int argc, _TCHAR* argv[])
{
	__asm
	{
		push HGYSEH				// 设置当前的_except_handler
		push DWORD PTR fs:[0]   // 设置_EXCEPTION_REGISTRATION_RECORD.next
		mov fs:[0],esp			// 设置到fs:[0]位


		mov eax, DWORD PTR fs:[0]
		call DWORD PTR[eax+4]	// 调用HGYSEH
	}

  

2.构建SEH

示例1:

void SEHTest()
{
	__try
	{
	}
	__except(EXCEPTION_EXECUTE_HANDLER)
	{
	}
}

反汇编如下:

  8 012213c0 55              push    ebp
    8 012213c1 8bec            mov     ebp,esp
    8 012213c3 6afe            push    0FFFFFFFEh
    8 012213c5 68686a2201      push    offset test!__rtc_tzz+0x104 (01226a68)
    8 012213ca 687d102201      push    offset test!ILT+120(__except_handler4) (0122107d)//1. 压入 __except_handler4,它是缺省的异常处理程序
    8 012213cf 64a100000000    mov     eax,dword ptr fs:[00000000h]//TEB取值到eax
    8 012213d5 50              push    eax//2.压入前一个TEB 值
    8 012213d6 81c438ffffff    add     esp,0FFFFFF38h
    8 012213dc 53              push    ebx
    8 012213dd 56              push    esi
    8 012213de 57              push    edi
    8 012213df 8dbd28ffffff    lea     edi,[ebp-0D8h]
    8 012213e5 b930000000      mov     ecx,30h
    8 012213ea b8cccccccc      mov     eax,0CCCCCCCCh
    8 012213ef f3ab            rep stos dword ptr es:[edi]
    8 012213f1 a100702201      mov     eax,dword ptr [test!__security_cookie (01227000)]
    8 012213f6 3145f8          xor     dword ptr [ebp-8],eax
    8 012213f9 33c5            xor     eax,ebp
    8 012213fb 50              push    eax
    8 012213fc 8d45f0          lea     eax,[ebp-10h]
    8 012213ff 64a300000000    mov     dword ptr fs:[00000000h],eax// 设置 FS:[0] 值
    8 01221405 8965e8          mov     dword ptr [ebp-18h],esp
    9 01221408 c745fc00000000  mov     dword ptr [ebp-4],0
   11 0122140f c745fcfeffffff  mov     dword ptr [ebp-4],0FFFFFFFEh
   11 01221416 eb10            jmp     test!SEHTest+0x68 (01221428)  Branch
   
   15 01221428 8b4df0          mov     ecx,dword ptr [ebp-10h]
   15 0122142b 64890d00000000  mov     dword ptr fs:[0],ecx//恢复 SEH 链处理
   15 01221432 59              pop     ecx
   15 01221433 5f              pop     edi
   15 01221434 5e              pop     esi
   15 01221435 5b              pop     ebx
   15 01221436 8be5            mov     esp,ebp
   15 01221438 5d              pop     ebp
   15 01221439 c3              ret

实际上VC++扩展了_EXCEPTION_REGISTRATION_RECORD,它的结构如下:

; exception registration record structure.

__EXCEPTIONREGISTRATIONRECORD struc
        prev_structure          dd      ?
        ExceptionHandler        dd      ?
        ExceptionFilter         dd      ?//scopetable
        FilterFrame             dd      ?
        PExceptionInfoPtrs      dd      ?
__EXCEPTIONREGISTRATIONRECORD ends

ExceptionFilter对应scopetable

用C描述为:(https://www.microsoft.com/msj/0197/exception/exception.aspx)

struct _EXCEPTION_REGISTRATION{
      struct _EXCEPTION_REGISTRATION *prev;
      void (*handler)(PEXCEPTION_RECORD,
                      PEXCEPTION_REGISTRATION,
                      PCONTEXT,
                      PEXCEPTION_RECORD);
      struct scopetable_entry *scopetable;
      int trylevel;
      int _ebp;
      PEXCEPTION_POINTERS xpointers;
 };

因为_except_handler4是缺省SEH,所以分析从它开始

012ec630          QQDemo!_except_handler4 (struct _EXCEPTION_RECORD *, struct _EXCEPTION_REGISTRATION_RECORD *, struct _CONTEXT *, void *)

-->
012ec783 e868000000      call    QQDemo!ValidateLocalCookies (012ec7f0)
-->
012ec7f0          QQDemo!ValidateLocalCookies (struct _EH4_SCOPETABLE *, char *)
-->
0:000> dt _EH4_SCOPETABLE
QQDemo!_EH4_SCOPETABLE
   +0x000 GSCookieOffset   : Uint4B
   +0x004 GSCookieXOROffset : Uint4B
   +0x008 EHCookieOffset   : Uint4B
   +0x00c EHCookieXOROffset : Uint4B
   +0x010 ScopeRecord      : [1] _EH4_SCOPETABLE_RECORD

用C描述为:

struct _EH4_SCOPETABLE {
 UINT GSCookieOffset;
 UINT GSCookieXOROffset;
 UINT EHCookieOffset;
 UINT EHCookieXOROffset;
 _EH4_SCOPETABLE_RECORD ScopeRecord[1];
};

再来看看trylevel

void SEHTest()
{
	__try /* 0-level */
	{
		__try  /* 1-level */
		{
			__try /* 2-level */
			{ 
			}
			__except(1) 
			{
			}
		}
		__except(1)
		{
		}
	} 
	__except(1)
	{
	}
}

反汇编如下:

	__try /* 0-level */
00CD36B8  mov         dword ptr [ebp-4],0 // 0层到[ebp-4]
	{
		__try  /* 1-level */
00CD36BF  mov         dword ptr [ebp-4],1 // 1层到[ebp-4]
		{
			__try /* 2-level */
00CD36C6  mov         dword ptr [ebp-4],2 // 2层到[ebp-4]
			{ 
			}
00CD36CD  mov         dword ptr [ebp-4],1 // 退到1层,执行except
00CD36D4  jmp         $LN16+0Ah (0CD36E6h) 
			__except(1) 
00CD36D6  mov         eax,1 
$LN17:
00CD36DB  ret              
$LN16:
00CD36DC  mov         esp,dword ptr [ebp-18h] 
			{
			}
00CD36DF  mov         dword ptr [ebp-4],1  // 退到1层,执行except
		}
00CD36E6  mov         dword ptr [ebp-4],0  // 退到0层,执行except
00CD36ED  jmp         $LN12+0Ah (0CD36FFh) 
		__except(1)
00CD36EF  mov         eax,1 
$LN13:
00CD36F4  ret              
$LN12:
00CD36F5  mov         esp,dword ptr [ebp-18h] 
		{
		}
00CD36F8  mov         dword ptr [ebp-4],0 // 退到0层,执行except
	} 
00CD36FF  mov         dword ptr [ebp-4],0FFFFFFFEh 
00CD3706  jmp         $LN8+0Ah (0CD3718h) 
	__except(1)
00CD3708  mov         eax,1 
$LN9:
00CD370D  ret              
$LN8:
00CD370E  mov         esp,dword ptr [ebp-18h] 
	{
	}
00CD3711  mov         dword ptr [ebp-4],0FFFFFFFEh // 退回所有层后,设回初始值0FFFFFFFEh
}
00CD3718  mov         ecx,dword ptr [ebp-10h] 
00CD371B  mov         dword ptr fs:[0],ecx 
00CD3722  pop         ecx  
00CD3723  pop         edi  
00CD3724  pop         esi  
00CD3725  pop         ebx  
00CD3726  mov         esp,ebp 
00CD3728  pop         ebp  
00CD3729  ret  

上面的代码嵌套了三层 __try{} 结构,那么最外层被称作 0-level,依次往里最里一层是 2-level



参考资料:http://www.mouseos.com/windows/SEH5.html

文章作者:hgy413
本文地址:https://hgy413.com/3257.html
版权所有 © 转载时必须以链接形式注明作者和原始出处!

本文目前尚无任何评论.

发表评论