3环调用了RtlCallVectoredExceptionHandlers
0环中没有调用
作用:
全称:Vectored Exception Handler
描述:全局异常链表,不同的线程共用一个
编译并运行以下代码
#include
#include
typedef PVOID (NTAPI *FnAddVectoredExceptionHandler)(ULONG, _EXCEPTION_POINTERS *);
FnAddVectoredExceptionHandler MyAddVectoredExceptionHandler;
// VEH异常处理只能返回2个值
// EXCEPTION_CONTINUE_EXECUTION 已处理
// EXCEPTION_CONTINUE_SEARCH 未处理
LONG NTAPI VectExcepHandler( PEXCEPTION_POINTERS pExcepInfo)
{
// pExcepInfo->ContextRecord 保存进入异常处理前的线程信息
// pExcepInfo->ExceptionRecord 保存异常信息
if( pExcepInfo->ExceptionRecord->ExceptionCode == 0xC0000094 )
{
::MessageBoxA(NULL, "VEH除0异常触发了", "VEH异常", MB_OK);
//修改完EIP之后并不是异常处理结束后直接返回,而是通过ZwContinue进行修正
pExcepInfo->ContextRecord->Eip = pExcepInfo->ContextRecord->Eip+2;
//pExcepInfo->ContextRecord->Ecx = 1;
return EXCEPTION_CONTINUE_EXECUTION;
}
return EXCEPTION_CONTINUE_SEARCH;
}
int main()
{
//1. 动态获取AddVectoredExceptionHandler函数地址
HMODULE hMyModule = GetModuleHandle("kernel32.dll");
MyAddVectoredExceptionHandler = (FnAddVectoredExceptionHandler)GetProcAddress(hMyModule, "AddVectoredExceptionHandler");
//2. 参数1表示插入到VEH头部,0表示插入到VEH尾部
MyAddVectoredExceptionHandler(0, (_EXCEPTION_POINTERS *)&VectExcepHandler);
//3. 构造除0异常
__asm
{
xor edx, edx
xor ecx, ecx
mov eax, 0x10
idiv ecx //EDX:EAX 除以 ECX
}
//4. 产生异常,从这里继续
printf("代码从这里继续执行\n");
return 0;
}
全称:Structured Exception Handling
描述:局部异常链表,线程相关,位于当前线程的堆栈当中,不同线程不同堆栈
注意:
思考:当将SEH放入堆栈当中之后,什么时候会进行调用?
答案:需要分析RtlDispatchException
EXCEPTION_DISPOSITION __cdecl MyExceptionHandler(
struct _EXCEPTION_RECORD *ExceptionRecord, //存储异常信息:类型、产生位置
void * EstablisherFrame, //MyException结构体地址
struct _CONTEXT *ContextRecord, //结构体,异常发生时各种寄存器的值,堆栈位置等
void * Dispatchercontext)
编译并运行以下代码:
#include
#include
/*
//0环异常处理时讲过这个结构体
typedef struct _EXCEPTION_REGISTRATION_RECORD
{
struct _EXCEPTION_REGISTRATION_RECORD *Next;
PEXCEPtiON_ROUTINE Handler;
}
*/
//定义时结构体名字可以不同,但必须遵守这个格式
struct MyException
{
struct MyException *prev;
DWORD handler;
};
EXCEPTION_DISPOSITION __cdecl MyExceptionHandler(
struct _EXCEPTION_RECORD *ExceptionRecord, //存储异常信息:类型、产生位置
void * EstablisherFrame, //MyException结构体地址
struct _CONTEXT *ContextRecord, //结构体,异常发生时各种寄存器的值,堆栈位置等
void * Dispatchercontext)
{
if( ExceptionRecord->ExceptionCode == 0xC0000094 )
{
MessageBoxA(NULL, "SEH除0异常触发了", "SEH异常", MB_OK);
ContextRecord->Eip = ContextRecord->Eip+2;
//pExcepInfo->ContextRecord->Ecx = 1;
return ExceptionContinueExecution;
}
return ExceptionContinueSearch;
}
void TestException()
{
DWORD temp;
//插入异常,必须在当前线程的堆栈当中
//若定义成全局变量则无效
MyException myException;
__asm
{
mov eax, FS:[0]
mov temp, eax
lea ecx, myException
mov FS:[0], ecx
}
//原来的异常链表中也许有值,因此需要挂上
myException.prev = (MyException*)temp;
myException.handler = (DWORD)&MyExceptionHandler;
//构造除0异常
__asm
{
xor edx, edx
xor ecx, ecx
mov eax, 0x10
idiv ecx //EDX:EAX 除以 ECX
}
//处理完成,摘掉异常
__asm
{
mov eax, temp
mov FS:[0], eax
}
printf("函数执行完毕\n");
}
int main()
{
TestException();
return 0;
}