SEH和VEH

SEH(Structured Exception Handling,结构化异常处理)是window操作系统默认的异常处理机制,逆向分析中,SEH除了基本的异常处理功能外,还大量用于反调试程序。

1、SEH的相关数据结构

1、TIB结构

TIB(Thread Information Block,线程信息块)是保存线程基本信息的数据结构。在用户模式下,它位于TEB(Thread Environment Block,线程环境块)的头部,而TEB是操作系统为了保存每个线程的私有数据创建的,每个线程都有自己的TEB。TIB定义:

1
2
3
4
5
6
7
8
9
10
11
12
13
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;//指向TIB结构自身
} NT_TIB;
typedef NT_TIB *PNT_TIB;

2、_EXCEPTION_REGISTRATION_RECORD结构

TEB偏移量为0的_EXCEPTION_REGISTRATION_RECORD主要用于描述线程异常处理过程的地址,多个该结构体的链表描述了多个线程异常处理过程的嵌套层次关系,定义如下:

1
2
3
4
5
6
struct EXCEPTION_REGISTRATION_RECORD
typedef struct _EXCEPTION_REGISTRATION_RECORD
{
PEXCEPTION_REGISTRATION_RECORD Next;//指向下一个结构的指针
PEXCEPTION_DISPOSITION Handler;//当前异常处理回调函数的地址
} EXCEPTION_REGISTRATION_RECORD, *PEXCEPTION_REGISTRATION_RECORD;

twKlvV.png

3、EXCEPTION_DISPOSITION结构

由系统调用,是一个回调函数,第一个参数是一个指向EXCEPTION_RECORD结构体的指针

1
2
3
4
5
6
EXCEPTION_DISPOSITION __cdecl _except_handler (
EXCEPTION_RECORD *pRecord,
EXCEPTION_REGISTRATION_RECORD *pFrame,
CONTEXT *pContext,
PVOID pValue
);

4、EXCEPTION_RECORD结构

异常处理函数的第三个参数是指向CONTEXT结构体的指针,CONTEXT结构体用来备份CPU的值。

1
2
3
4
5
6
7
8
typedef struct _EXCEPTION_RECORD {
DWORD ExceptionCode; //异常代码
DWORD ExceptionFlags;
struct _EXCEPTION_RECORD *ExceptionRecord;
PVOID ExceptionAddress; //异常发生地址
DWORD NumberParameters;
ULONG_PTR ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];
} EXCEPTION_RECORD;

异常发生的时候,执行异常代码的线程就会发生中断,转而运行SEH,此时操作系统会把线程CONTEXT结构体的指针传递给异常处理函数的相应参数。里面有个eip成员,在异常处理函数中将参数传递过来的CONTEXT.eip设置为其他地址,然后返回处理函数。这样之前暂停的线程会执行新的EIP地址处的代码。

2、VEH

向量化异常处理的基本概念和SEH相同,也是注册一个回调函数,当发生异常时会被系统的异常处理过程调用。

1
2
3
4
5
6
7
8
9
WINBASEAPI PVOID WINAPI AddVectoreExceptionHandler (
ULONG FirstHandler;
PVECTORED_EXCEPTION_HANDLER VectoreHandler//回调函数地址
);

//回调函数原型
LONG CALLBACK VectoredHandler (
PEXCEPTION_POINTERS ExceptionInfo
);

VEH回调函数也形成一个链表。若参数FirstHandler的值为0,则回调函数位于VEH链表的尾部;若参数FirstHandler为非零值,则置于VEH链表的头部。
VEH回调函数所在的模块被卸载之后,系统不能自动将回调函数从VEH链表上移除,需要程序在退出前自己完成卸载工作。

1
2
3
ULONG RemoveVectoreExceptionHandler (
POVID VectoreHandlerHandle
);

VectoreHandlerHandle为AddVectoreExceptionHandler的返回值。

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
#include "stdafx.h"

#define _WIN32_WINNT 0x502
#include <windows.h>

char szTit[]="design : achillis XP+";
DWORD validADDR;

LONG WINAPI VectExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo)
{
PCONTEXT pContext=ExceptionInfo->ContextRecord;
pContext->Eax=(DWORD)&validADDR;
return EXCEPTION_CONTINUE_EXECUTION;
}


int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR CmdLine,int nCmdShow)
{
PVOID handle = AddVectoredExceptionHandler(TRUE, VectExceptionHandler);

__asm
{
xor eax,eax
mov [eax],5 //向0地址写入数据,引发内存访问异常
}

MessageBox(0,"We SUC recovering from Write Acess!",szTit,MB_ICONINFORMATION);
RemoveVectoredExceptionHandler(handle);
return 0;
}