5.SEH(结构化异常处理)

当用户异常产生后,内核函数KiDispatchException并不是像处理内核异常那样在0环直接进行处理,而是修正3环EIP为KiUserExceptionDispatcher函数后就结束了。

这样,当线程再次回到3环时,将会从KiUserExceptionDispatcher函数开始执行。

KiUserExceptionDispatcher会调用RtIDispatchException函数来查找并调用异常处理函数,查找的顺序:

  1. 先查局链表: VEH
  2. 如果VEH没找到,再查局部链表: SEH

5.SEH(结构化异常处理)

3环fs[0]->TEB.+ 0x0 _NT_TIB
0环fs[0]->KPCR.+ 0x0 _NT_TIB
无论是3环还是0环它的第一个都是_EXCEPTION_REGISTRATION_RECORD 这个结构,这个结构最少要有两个成员,可拓展后面再说。

//最原始的 SEH链表结构
typedef struct _EXCEPTION_REGISTRATION_RECORD 
{ 
	struct _EXCEPTION_REGISTRATION_RECORD* Next;	//下一个节点,-1就是没有下一个节点了
	PEXCEPTION_ROUTINE Handler; //指向下一个异常处理函数
} EXCEPTION_REGISTRATION_RECORD;

SEH与VEH不同,VEH所有线程都能用的与线程无关,SEH哪个线程想用这个异常处理函数,就必须往自己的堆栈里压入_EXCEPTION_REGISTRATION_RECORD这种结构(你压入当前进程的A线程对B线程没有影响的),然后让fs[0]指向新构建的结构体,再给Handler提供异常处理函数。

5.SEH(结构化异常处理)

获取当前堆栈界限与起始位置,再回来
5.SEH(结构化异常处理)

这一块代码都是检测SEH链是否处于当将线程的堆栈中。
5.SEH(结构化异常处理)

调用处理异常函数
5.SEH(结构化异常处理)

测试代码

//最原始的 SEH链表结构(这个结构怎么写都行)
struct _EXCEPTION
{
	struct _EXCEPTION* Next;
	DWORD Handler;
};

EXCEPTION_DISPOSITION _cdecl MyEexception_handler
(
	struct _EXCEPTION_RECORD *ExceptionRecord,	//异常结构体
	PVOID EstablisherFrame,						//SEH结构体地址
	struct _CONTEXT *ContextRecord,				//存储异常发生时的各种寄存器的值 栈位置等
	PVOID DispatcherContext
)
{
	MessageBox(NULL,L"SEH异常处理函数执行了...",L"SEH异常",NULL);
	if (ExceptionRecord->ExceptionCode == 0xC0000094)
	{
		ContextRecord->Eip = ContextRecord->Eip + 2;

		ContextRecord->Ecx = 100;

		return ExceptionContinueExecution;
	}

	return ExceptionContinueSearch;
}


int main()
{
	DWORD temp;
	_EXCEPTION Exception;//必须在当前线程堆栈的堆栈中
	
	//fs[0]-> Exception
	_asm
	{
		mov eax, fs:[0]
		mov temp,eax
		lea ecx,Exception
		mov fs:[0],ecx
	}
	//为SEH成员赋值
	Exception.Next = (_EXCEPTION*)temp;
	Exception.Handler = (DWORD)&MyEexception_handler;

	//创建异常
	int val = 0;
	_asm
	{
		xor edx,edx
		xor ecx,ecx
		mov eax,1
		idiv ecx	//edx = eax /ecx

		mov val,ecx
	}
	
	//摘除刚插入的SEH
	_asm
	{
		mov eax, temp
		mov fs:[0],eax
	}

	printf("val = %d",val);

	getchar();
}

总结: SEH异常的处理流程

  1. FS:[0]指向SEH链表的第一个成员
  2. SEH的异常处理函数必须在当前线程的堆栈中
  3. 只有当VEH中的异常处理函数不存在或者不处理才会到SEH链表中查找