位置:ntdll.dll
3环调用了RtlCallVectoredExceptionHandlers
0环中没有调用
作用:
全称:Vectored Exception Handler
描述:全局异常链表,不同的线程共用一个
编译并运行以下代码
#include <stdio.h> #include <windows.h> 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 <stdio.h> #include <windows.h> /* //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; }
运行结果: