VEH / SEH

VEH全局链表:与线程无关

全局链表结构(每个是个EXCEOTION_REGISTRATION_RECORD)
VEH / SEH_第1张图片构造除零异常

__asm
{
	xor edx,edx
	xor ecx,ecx
	mov eax.0x10
	idiv ecx //edx:eax 除以 ecx
}

用一个函数将异常处理函数挂入VEH,异常处理函数如下

LONG NTAPI VecExcepHandler( PEXCEPTION_POINTERS pExcepInfo )
{
	::MessageBoxA(NULL,"VEH异常处理函数执行了","VEH异常",MB_OK);
	//异常过滤
    if( pExcepInfo->ExceptionRecord->ExceptionCode == 0xC0000094)
    {	//异常处理
		pExcepInfo->ContextRecord->Eip = pExcepInfo->ContextRecord->Eip+2;
		//pExcepInfo->ContextRecord->Ecx = 1;
		return 已处理
	}
	return 未处理
}

SEH局部链表:在堆栈中

windows原始结构

typedef struct _EXCEOTION_REGISTRATION_RECORD{
		struct _EXCEPTION_REGISTRATION_RECORD *Next;
		PEXCEPTION_ROUTINE Handler;
}EXCEOTION_REGISTRATION_RECORD;

编译器拓展结构,扩展了3个成员是因为一个函数里无论有多少try catch都只挂一个record

struct _EXCEOTION_REGISTRATION_RECORD{
		struct _EXCEPTION_REGISTRATION *prev;
		void (*handler)(PEXCEPTION_RECORD,
			PEXCEPTION_REGISTRATION,
			PCONTEXT,PEXCEPTION_RECORD);
		struct scopetable_entry *scopetable;
		int reylevel;
		int _ebp;
};

自己实现将异常处理函数挂入SEH

DWORD temp;
MyException myException;//自己定义的EXCEOTION_REGISTRATION_RECORD
//将原FS:[0]存入temp
//将FS:[0]指向新的EXCEOTION_REGISTRATION_RECORD
//挂入链表
__asm{
		mov eax,FS:[0]
		mov temp,eax
		lea ecx,myException
		mov FS:[0],ecx
}
myException.prev = (MyException*)temp;
myException.handle = (DWORD)&MyException_handler;

//创造异常
__asm
{
	xor edx,edx
	xor ecx,ecx
	mov eax.0x10
	idiv ecx //edx:eax 除以 ecx
}

//摘除异常
__asm{
		mov eax,temp
		mov FS:[0],eax
}

编译器实现将异常处理函数挂入SEH
过滤表达式有 常量 (1,0)/ 表达式(exceptioncode=0x…) / 函数(GetExceptionInfo()里有context等)
过滤表达式为函数,可能在函数里涉及加密,异常处理程序也会涉及

try					//挂入链表(对应上面的代码)
{

}
except(过滤表达式)	//异常过滤
{
	异常处理程序		//异常处理
}

多个try & scopetable,trylevel分析

Example

try{
}
except(){
}
try{
	try{
	}
	except(){
	}
}
except(){
}

●每个使用try的函数,不论其内部嵌套或反复使用多少个try,都只将一个EXCEOTION_REGISTRATION_RECORD挂入当前线程的SEH(对于递归函数,每一次调用都会创建一个EXCEOTION_REGISTRATION_RECORD并挂入),以下是初始化了扩展的record

push ebp //ebp
mov ebp,esp //提升堆栈
push 0xFF //-1,trylevel
push scopetable地址
push 异常处理函数地址
mov eax,FS:[0]
push eax  //prev
mov fs:[0] ,esp //指向新结构体,即挂入链表

●对于scopetable,有几个try就有几个成员

struct scopetable_entry
{
	DWORD previousTryLevel	//上一个try{}结构编号
	PDWRD lpfnFilter		//过滤函数的起始地址,except()
	PDWRD lpgnHandler		//异常处理程序的地址,except里的
}
scopetable[0].previousTryLevel = -1 //因为前面没try
scopetable[0].lpfnFilter = 过滤函数1 //异常过滤
scopetable[0].lpgnHandler = 异常处理函数1 //异常处理
scopetable[1].previousTryLevel = -1 
scopetable[1].lpfnFilter = 过滤函数2
scopetable[1].lpgnHandler = 异常处理函数2
scopetable[2].previousTryLevel = 1	//嵌套try
scopetable[2].lpfnFilter = 过滤函数3
scopetable[2].lpgnHandler = 异常处理函数3
如果嵌套里面再嵌套一个level就是2

Example

try{
	try{
	}
	except(){
	}
}
except(){
}
try{
	try{
	}
	except(){
	}
}
except(){
}

●trylevel用于标识当前代码执行在哪个try里,是随时变化的,进入try就改变值

例子的变化过程如下:
-1(try 外),0(第一个try),1(第2个),0(恢复,在第一个try),-1(退出了第一个try)
2(第三个),3(第四个),2,-1(-1就是不在任何try里)

如果是自己throw的知识KiDispatchException前不一样except_handler3在SEH里
VEH / SEH_第2张图片

try {
可能出错的代码
}
finally{
一定要执行的代码
}
finally用在try里没发生异常且提前退出,finally的PDWRD lpfnFilter为空,局部展开(一个函数的名称)调用finally
若出现异常,一层一层的往外找except处理,然后finally,全局展开这个函数走的
VEH / SEH_第3张图片

你可能感兴趣的:(VEH,SEH)