首页 > 编程知识 正文

Windows异常学习笔记三 VEH,三宽教育学习笔记

时间:2023-05-04 04:06:42 阅读:194328 作者:3776

Windows异常学习笔记(三)—— VEH&SEH 要点回顾分析 KiUserExceptionDispatcher分析 _RtlDispatchException_RtlCallVectoredExceptionHandlers VEH(向量化异常处理)实验:自定义VEH总结:VEH异常处理流程 SEH(结构化异常处理)分析 RtlDispatchException实验:构造自定义SEH总结:SEH异常处理流程

要点回顾 当用户异常产生后,内核函数KiDispatchException并不是像处理内核异常那样在0环直接进行处理 ,而是修正3环EIP为KiUserExceptionDispatcher函数后就结束了当线程再次回到3环时,将会从KiUserExceptionDispatcher函数开始执行 分析 KiUserExceptionDispatcher

位置:ntdll.dll

分析 _RtlDispatchException

3环调用了RtlCallVectoredExceptionHandlers
0环中没有调用

_RtlCallVectoredExceptionHandlers

作用

查找VEH链表(全局链表),如果有则调用查找SEH链表(局部链表,在堆栈中),如果有则调用 VEH(向量化异常处理)

全称:Vectored Exception Handler
描述:全局异常链表,不同的线程共用一个

实验:自定义VEH

编译并运行以下代码

#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, edxxor ecx, ecxmov eax, 0x10idiv ecx//EDX:EAX 除以 ECX}//4. 产生异常,从这里继续printf("代码从这里继续执行n");return 0;}

执行结果

总结:VEH异常处理流程 CPU捕获异常信息通过KiDispatchException进行分发(EIP=KiUserExceptionDispatcher)KiUserExceptionDispatcher调用RtlDispatchExceptionRtlDispatchException查找VEH处理函数链表 并调用相关处理函数代码返回到KiUserExceptionDispatcher调用ZwContinue再次进入0环(ZwContinue调用NtContinue,主要作用就是恢复TRAP_FRAME 然后通过KiServiceExit返回到3环)线程再次返回3环后,从修正后的位置开始执行 SEH(结构化异常处理)

全称:Structured Exception Handling
描述:局部异常链表,线程相关,位于当前线程的堆栈当中,不同线程不同堆栈
注意

在0环时,FS指向KPCR,在3环时,FS指向TEB,这两个结构体的第一个成员都指向NT_TIB,NT_TIB第一个成员为ExceptionList,即异常处理链表在加入VEH时,只需调用系统提供的API即可,但想要构造SEH的话,必须手动在当前线程当中加入这样一个结构,在A线程中加入的SEH不会对B线程产生影响

思考:当将SEH放入堆栈当中之后,什么时候会进行调用?
答案:需要分析RtlDispatchException

分析 RtlDispatchException


EXCEPTION_DISPOSITION __cdecl MyExceptionHandler(struct _EXCEPTION_RECORD *ExceptionRecord,//存储异常信息:类型、产生位置void * EstablisherFrame,//MyException结构体地址struct _CONTEXT *ContextRecord,//结构体,异常发生时各种寄存器的值,堆栈位置等void * Dispatchercontext) 实验:构造自定义SEH

编译并运行以下代码

#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, eaxlea ecx, myExceptionmov FS:[0], ecx}//原来的异常链表中也许有值,因此需要挂上myException.prev = (MyException*)temp;myException.handler = (DWORD)&MyExceptionHandler;//构造除0异常__asm{xor edx, edxxor ecx, ecxmov eax, 0x10idiv ecx//EDX:EAX 除以 ECX}//处理完成,摘掉异常__asm{mov eax, tempmov FS:[0], eax}printf("函数执行完毕n");}int main(){TestException();return 0;}

运行结果

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

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。