Windows异常学习笔记(三)—— VEH&SEH

  • 要点回顾
    • 分析 KiUserExceptionDispatcher
    • 分析 _RtlDispatchException
    • _RtlCallVectoredExceptionHandlers
  • VEH(向量化异常处理)
    • 实验:自定义VEH
    • 总结:VEH异常处理流程
  • SEH(结构化异常处理)
    • 分析 RtlDispatchException
    • 实验:构造自定义SEH
    • 总结:SEH异常处理流程

要点回顾

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

分析 KiUserExceptionDispatcher

位置:ntdll.dll

分析 _RtlDispatchException

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

_RtlCallVectoredExceptionHandlers

作用

  1. 查找VEH链表(全局链表),如果有则调用
  2. 查找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异常处理流程

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

SEH(结构化异常处理)

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

  1. 在0环时,FS指向KPCR,在3环时,FS指向TEB,这两个结构体的第一个成员都指向NT_TIB,NT_TIB第一个成员为ExceptionList,即异常处理链表
  2. 在加入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异常处理流程

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

Windows异常学习笔记(三)—— VEHSEH相关推荐

  1. Windows异常学习笔记(五)—— 未处理异常

    Windows异常学习笔记(五)-- 未处理异常 要点回顾 最后一道防线 实验一:理解最后一道防线 实验二:新线程的最后一道防线 总结 UnhandledExceptionFilter 实验三:理解U ...

  2. Windows异常学习笔记(四)—— 编译器扩展SEH

    Windows异常学习笔记(四)-- 编译器扩展SEH 要点回顾 编译器支持的SEH 过滤表达式 实验一:理解_try_except 实验二:_try_except 嵌套 拓展SEH结构体 scope ...

  3. Windows异常学习笔记(一)—— CPU异常记录模拟异常记录

    Windows异常学习笔记(一)-- CPU异常记录 基础知识 异常的分类 CPU异常 分析中断处理函数 _KiTrap00 分析 CommonDispatchException 总结 软件模拟异常 ...

  4. Windows异常学习笔记(二)—— 内核异常处理流程用户异常的分发

    Windows异常学习笔记(二)-- 内核异常处理流程&用户异常分发 用户层与内核层异常 内核异常 分析 KiDispatchException 分析 RtlDispatchException ...

  5. Windows系统调用学习笔记(三)—— 保存现场

    Windows系统调用学习笔记(三)-- 保存现场 要点回顾 基本概念 Trap Frame 结构 线程相关的结构体 ETHREAD KTHREAD CPU相关的结构体 KPCR _NT_TIB KP ...

  6. Windows APC学习笔记(二)—— 挂入过程执行过程

    Windows APC学习笔记(二)-- 挂入过程&执行过程 基础知识 挂入过程 KeInitializeApc ApcStateIndex KiInsertQueueApc Alertabl ...

  7. python3常用模块_Python学习笔记三(常用模块)

    Python 学习笔记三 (常用模块) 1.os模块 os模块包装了不同操作系统的通用接口,使用户在不同操作系统下,可以使用相同的函数接口,返回相同结构的结果. os.name:返回当前操作系统名称( ...

  8. K8S 学习笔记三 核心技术 Helm nfs prometheus grafana 高可用集群部署 容器部署流程

    K8S 学习笔记三 核心技术 2.13 Helm 2.13.1 Helm 引入 2.13.2 使用 Helm 可以解决哪些问题 2.13.3 Helm 概述 2.13.4 Helm 的 3 个重要概念 ...

  9. Windows APC学习笔记(一)—— APC的本质备用APC队列

    Windows APC学习笔记(一)-- APC的本质&备用APC队列 基础知识 APC的本质 APC队列 APC结构 分析 KiServiceExit 总结 备用APC队列 挂靠环境下Apc ...

  10. Windows系统调用学习笔记(四)—— 系统服务表SSDT

    Windows系统调用学习笔记(四)-- 系统服务表&SSDT 要点回顾 系统服务表 实验:分析 KiSystemService 与 KiFastCallEntry 共同代码 SSDT 实验: ...

最新文章

  1. jQuery面试题-区别mouseover和mouseenter的不同之处(看了也许对你有好处)
  2. 腾讯在线人数统计_PHP + REDIS 实践:统计在线人数的几种方案分析
  3. 天勤数据结构:树与二叉树(图解二叉树的三种遍历方式执行流程,超详细)
  4. python里的shell是什么_Python与shell的3种交互方式介绍
  5. 浅谈编程-----非计算机专业以及非培训班的一些感悟
  6. python复制文件shutil_Python常用模块——文件复制模块shutil
  7. WIN7下怎么安装iis教程
  8. 卷帘快门和全局快门的区别
  9. 酒店如何实现上网认证的呢
  10. 谷歌浏览器chrome翻译插件完美解决开发者模式插件问题
  11. 分水岭算法 c语言实现,分水岭算法的应用
  12. iOS 第三方框架-Masonry的使用
  13. lil9341_使用Python评估Lil John的“拒绝接受什么”
  14. 网络上游戏制作相关学习站点的网址! 1
  15. OSChina 儿童节乱弹 —— 六一不能让童工加班!
  16. JavaScript中Date的setMonth()顺延问题及解决方法
  17. pandas使用goupby函数和nunique函数计算每个分组对应的多个变量的独特值的个数( unique values of each group in dataframe)
  18. Web小轩:第一次做淘宝主页
  19. 腾讯云服务器的FTP账号密码如何查看?
  20. 【深度学习在智能机器人中的应用】论文合集推荐丨CMU新型机器人算法可操纵所有日常家具

热门文章

  1. 招聘网站职位分析数据可视化系统(Hadoop课设)
  2. Android 安装包没有签名文件问题
  3. 基于变量推理的知识图路径推理分析
  4. GROW GM65 条码二维码扫描识别模块 兼容大部分条码和二维码
  5. 2017腾讯校招机试题
  6. 2022年北京购房攻略一 (常识篇)
  7. win7服务器建网站教程,win7搭建Web服务器教程
  8. 难倒高手了,c语言枚举end的作用是什么?
  9. 手把手教你如何自学计算机,绝对的干货满满!!!
  10. pytorch log