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 ...
随机推荐
- Keil 5出现Error: L6218E: Undefined symbol解决方法
首先列出网上百度到比较好的blog: blog1:https://blog.csdn.net/super_demo/article/details/32131379 总结了代码中可能因为几种初级或者粗 ...
- leetcode整数反转
给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转. 示例 1: 输入: 123输出: 321 示例 2: 输入: -123输出: -321 示例 3: 输入: 120输出: 21 ...
- Relative Sort Array
Relative Sort Array Given two arrays arr1 and arr2, the elements of arr2 are distinct, and all eleme ...
- localhost-startStop-1启动失败
背景:在IDEA调试程序的时候,应用起不来,看日志是从main线程切换到localhost-startStop-1线程就开始卡住了 方法一 原因 这个问题和jvm上的熵池策略有关 解决 将$JAVA_ ...
- Python之TensorFlow的变量收集、自定义命令参数、矩阵运算、梯度下降-4
一.TensorFlow为什么要存在变量收集的过程,主要目的就是把训练过程中的数据,比如loss.权重.偏置等数据通过图形展示的方式呈现在开发者的眼前. 自定义参数:自定义参数,主要是通过Python ...
- MySQL-5.7.26解压版安装教程
1.下载地址:https://cdn.mysql.com//Downloads/MySQL-5.7/mysql-5.7.26-winx64.zip 2.在解压目录中添加 data文件夹 和 my.in ...
- C#获取汉字拼音和首字母
C#获取汉字拼音和首字母 引入NPinyin using NPinyin; 调用 /// <summary> /// 中文首字母大写 /// </summary> /// &l ...
- Python接口自动化基础---post请求
常见的post传递参数的类型有以下两种: 第一种:application/x-www-form-urlencoded,浏览器原生的form表单,格式如下:input1=xxx&input2=o ...
- C#中hashtable如何嵌套遍历
嵌套hashtable的遍历取值怎么做 hastable中嵌套了hashtable,想用递归的方式把所有hashtable中的key和value取出来 foreach (DictionaryEntry ...
- Jquery简单闭包
<html> <body> <script src="Js/Index.js"></script> <script type= ...