Windows异常的分发处理流程
根据异常来源,一般分硬件异常和软件异常,它们处理的流程大致一样,下面简单讲一下。
如果是硬件异常,CPU会根据中断类型号转而执行对应的中断处理程序。CPU会在IDT中查找对应的函数来处理,各个异常处理函数不仅仅处理异常还需要将异常信息封装,以便对后续处理,KiTrapXX例程在完成针对本异常的特别动作后,通常会调用CommonDispatchException函数,它会在栈中分配一个EXCEPTION_RECORD结构,并把异常信息存储到该结构中。在准备好这个结构后,它会调用内核中的KiDispatchExcption函数来分发异常。
如果是软甲异常,是通过直接或间接调用内核服务KiRaiseException而产生的。函数内部会把Context上下背景文复制到当前线程的内核栈,接下来调用KiDispatchExcption函数来进行分发。
综上所述,不管什么异常最后都会调用内核中的KiDispatchExcption函数进行分发,也就是说Windows用统一的方式来管理。异常封装完成后,系统会调用nt!KiDispatchException来处理异常,所以分析KiDispatchException函数就可以了解异常是如何被处理的。
首先来看看KiDisPatchException函数的函数原型
void KiDispatchException (
IN PEXCEPTION_RECORD ExceptionRecord,
IN PKEXCEPTION_FRAME ExceptionFrame,
IN PKTRAP_FRAME TrapFrame,
IN KPROCESSOR_MODE PreviousMode,
IN BOOLEAN FirstChance
)
ExceptionRecord也就是前面提的描述异常的结构,TrapFrame指向的结构用来描述发生异常时候的上下文,PreviousMode来说明异常来自Kernel还是User,最后的FirstChance用来表示异常是不是第一次被处理,实际上这些结构的集合就形成了一个虚拟的、完整的“异常”结构,再去进行下面的处理。下面先来看看KiDispatchException 的分发示意图:

从图中我们可以看到,KiDispatchException会先调用KeContextFromKframes函数,目的是根据TrapFrame参数指向的KTRAP_FRAME结构产生一个CONTEXT结构,以供向调试器和异常处理器函数报告异常时使用。右边是内核的异常,左边边是用户的异常。
内核异常处理分发流程:
但PreviousMode为0时,就会进入Kernel的异常分发,系统会维护一个KiDebugRoutine的函数,当内核的调试器启动时,它就帮我们把异常送往了内核调试器,而在未启动时,它只是一个“存根”函数(stub),返回一个False。这一步也就是图中的debug
当第一次debug返回False后会接着调用RtlDispatchException,试图寻找已经注册的结构化异常处理器(SEH),函数的原型:BOOLEAN RtlDispatchException(PEXCEPTION_RECORD ExceptionRecord,PCONTEXT ContextRecord)。如果没有处理的话就会进行第二轮调试,重复上面的debug内容,如果依然是没有启用调试器的话就那么就会把这个异常当作UnhandleException,也就是我们常说的未处理异常,在kernel下未处理异常可是个大问题,毕竟这可是操作系统最最重要的也最最完善的内核,这样的未处理异常一般都不是小问题,为了防止异常引发更大的问题,这时候系统就会调用KeBugCheckEx中止系统运行显示蓝屏,并将导致异常的地址打印在屏幕上。
具体步骤如下:
用户模式异常处理分发流程:
当PreviousMode==1时就进入了用户态的异常分发,相较于Kernel来说,user的异常处理还包括了我们自己在编写程序的过程中用到的try catch,下面就具体来看看。
首先还是检查是否有调试器,具体的措施和Kernel相仿,不过找的函数是内核的DbgForwardException,这个函数涉及到了用户态的调试。简单点说就是用户态的调试器是不是要接手这个异常,如果成了就交给它处理,如果没有的话那就会通过KeUserExceptionDispatcher来找到KiUserExceptionDispatcher函数,要注意,此时已经返回到了用户态,且异常的相关信息(比如KTRAP_FRAME)已经被放入了用户态的栈上。之后会调用了RtlDispatchException(注意,该函数依然名字和作用都与Kernel的几乎相同,但是它是位于NTDLL的,而Kernel的则是位于NTOSKRNL)来遍历异常处理器的链表,但这次的链表又了“保底措施”,在链表的最末尾是UnhandledExceptionFilter(未处理异常过滤函数),一旦走到了这里,那就会出现“应用程序错误”的对话框并强制结束程序(之后会写这个函数的详细分析),异常也就算是处理完成了。
既然有了UnhandledExceptionFilter那岂不是所有的异常都会最终被直接处理了,那第二轮又是怎么回事?实际上如果在非调试状态下确实如此,用户态的异常如果在非调试状态下的话仅仅只有一轮的分发,而只有在调试状态下才会进行第二轮,再次判断调试器是否要接手异常。
具体处理步骤:
Windows异常的分发处理流程的更多相关文章
- Windows内核读书笔记——Windows异常分发处理机制
本篇读书笔记主要参考自<深入解析Windows操作系统>和<软件调试>这两本书. IDT是处理异常,实现操作系统与CPU的交互的关口. 系统在初始化阶段会去填写这个结构. ID ...
- Windows异常分发函数---KiUserExceptionDispatcher
简介 KiUserExceptionDispatcher 是SEH分发器的用户模式的负责函数.当一个异常发生的时候,该异常将生成一个异常事件,内核检查该异常是否是由于执行用户模式代码导致的.如果是这样 ...
- Windows异常分发
当有异常发生时,CPU会通过IDT表找到异常处理函数,即内核中的KiTrapXX系列函数,然后转去执行.但是,KiTrapXX函数通常只是对异常做简单的表征和描述,为了支持调试和软件自己定义的异常处理 ...
- Android事件分发机制三:事件分发工作流程
前言 很高兴遇见你~ 本文是事件分发系列的第三篇. 在前两篇文章中,Android事件分发机制一:事件是如何到达activity的? 分析了事件分发的真正起点:viewRootImpl,Activit ...
- Android Tv 中的按键事件 KeyEvent 分发处理流程
这次打算来梳理一下 Android Tv 中的按键点击事件 KeyEvent 的分发处理流程.一谈到点击事件机制,网上资料已经非常齐全了,像什么分发.拦截.处理三大流程啊:或者 dispatchTou ...
- 反调试——Windows异常-SEH
反调试--Windows异常-SEH 概念: SEH:Structured Exception Handling SEH是Windows默认的异常处理机制 如何使用 在代码中使用 __try__e ...
- Windows异常
一.什么是异常 异常指的是在程序运行过程中发生的异常事件,通常是由外部问题(如硬件错误.输入错误)所导致的.简单来说异常就是对于非预期状况的处理,当我们在运行某个程序时出现了异常状况,就会进入异常处理 ...
- Java框架之SpringMVC 05-拦截器-异常映射-Spring工作流程
SpringMVC 拦截器 Spring MVC也可以使用拦截器对请求进行拦截处理,可以自定义拦截器来实现特定的功能,自定义的拦截器可以实现HandlerInterceptor接口中的三个方法,也可以 ...
- iOS企业版APP分发上线流程和注意事项
0.准备 1]$299/year的企业级开发账号. 2]制作分发证书和描述文件,并下载安装到本机. 3]Xcode编译通过,真机测试通过的源码. 1.打包前配置 1]Xcode 打开项目,common ...
随机推荐
- TZOJ5697: 数据结构实验:归并排序
#include<stdio.h> #include<stdlib.h> void merge(int a[], int start,int mid,int end) { )) ...
- 『Go基础』第7节 变量
1. 什么是变量? 我们应该怎么去理解变量? 在这里我要举一个例子: 大家应该都知道王者荣耀这个游戏. 当我们在玩王者荣耀的时候, 我们操控的英雄的血量是不断变化的, 这个血量是存在内存中的. 那么这 ...
- Oracle 11g Java驱动包ojdbc6.jar安装到maven库,并查看jar具体版本号
ojdbc6.jar下载 Oracle官方宣布的Oracle数据库11g的驱动jar包是ojdbc6.jar ojdbc6.jar下载地址:https://www.oracle.com/technet ...
- 【洛谷 P2483】 【模板】k短路([SDOI2010]魔法猪学院)(A*)
题目链接 优先队列bfs第一次出队就是最短路,那么显然第k次出队就是k短路 ?????????????????????????????? 书上写的 但是直接优先队列bfs会T,所以用A*优化就行,估价 ...
- 【洛谷 P3966】 [TJOI2013]单词(AC自动机,差分)
把单词连起来,中间插入间隔符,同 #include <cstdio> #include <queue> #include <cstring> using names ...
- 【转载】C#中ToArray方法将List集合转换为对应的数组
在C#的List集合操作中,可以使用List集合自带的ToArray方法来将List集合转换为对应的Array数组元素.ToArray方法的签名为T[] ToArray(),存在于命名空间System ...
- AJAX 初识
AJAX全称为 Asynchronous Javasript And XML,是在浏览器端进行网络编程(发送请求,接收响应)的技术方案.AJAX 也就是浏览器提供的一套API,可以供 Javascri ...
- centos7开启80端口及其他端口
首先centos7的防火墙由iptables改为了firewalld 1. 执行命令:firewall-cmd --zone=public --add-port=80/tcp --permanent ...
- Android笔记(六十三) android中的动画——逐帧动画( frame-by-frame animation)
就好像演电影一样,播放实现准备好的图片,来实现动画效果. 逐帧动画需要用到AnimationDrawable类,该类主要用于创建一个逐帧动画,然后我们把这个动画设置为view的背景即可. androi ...
- sqlite3入门之sqlite3_get_table,sqlite3_free_table
sqlite3_get_table sqlite3_get_table函数原型: int sqlite3_get_table( sqlite3 *db, /* An open database */ ...