VEH全局链表:与线程无关
全局链表结构(每个是个EXCEOTION_REGISTRATION_RECORD)
构造除零异常
__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里
try {
可能出错的代码
}
finally{
一定要执行的代码
}
finally用在try里没发生异常且提前退出,finally的PDWRD lpfnFilter为空,局部展开(一个函数的名称)调用finally
若出现异常,一层一层的往外找except处理,然后finally,全局展开这个函数走的