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 ...
随机推荐
- delphi indy Idhttp error:1409442E:SSL routines:SSL3_READ_BYTES:tlsv1 alert protocol version
在使用 indy 中的 idhttp 组件访问 https 网站时,出现如下错误: error:1409442E:SSL routines:SSL3_READ_BYTES:tlsv1 alert pr ...
- node-red File读取好保存
File节点是操作文件的节点 file文件的保存 拖拽 注入节点inject file节点(writes msg.payload to a file)和 debug节点到工作区,并连线 设置file ...
- 测试不得不知的python编程小技能-----升级版基础语法和优秀的编码习惯
编程和学习python,最后快速上手.能写小工具,写自动化用例这类要求对鹅厂的测试人员来说都是一些基础的必备素质,但是一个优秀的测试,也是有着一颗开发完美测试工具的心的.但是罗马不是一天构建成,特别是 ...
- c#Queue队列的使用
消息队列 队列(System.Collections.Queue)代表了一个先进先出的对象集合.当您需要对各项进行先进先出的访问时,则使用队列.当您在列表中添加一项,称为入队,当您从列表中移除一项时, ...
- NEST 根据id查询
想要在NEST里根据id查询 GET /employee/employee/1 可使用Get方法 public IGetResponse<employee> GetDoc() { var ...
- 可分离滤波器设计高斯滤波 CUDA程序优化, 实验记录
环境:RTX2060 ,1920X1080p ,循环10次, kernal_size=8 一 .测试前128个线程拷贝到dst数据的性能 ,只测试行卷积, block=(128+2r)X1 1. 使 ...
- Tortoise SVN常见图标含义及图标无法正常解决方法!
转自:https://blog.csdn.net/xh16319/article/details/10582455 绿色的勾:图标表示这是一个最新取出的工作副本,他的Subversion状态是norm ...
- 使nginx支持pathinfo模式
在将fastadmin部署到虚拟机中时,遇到如下问题:当访问登录页面时,页面进行不断的循环跳转重定向.解决方法是将nginx配置为支持pathinfo的模式 以下是nginx中的配置内容: locat ...
- [LeetCode] 5. 最长回文子串 ☆☆☆(最长子串、动态规划)
最长回文子串 (动态规划法.中心扩展算法) https://leetcode-cn.com/problems/longest-palindromic-substring/solution/xiang- ...
- 【JUC】5.线程池—Executor
创建线程池可以分为三种方式: 1. 通过ThreadPoolExecutor的构造方法,创建ThreadPoolExecutor的对象,即一个线程池对象: 此构造方法,一共7个参数,5个必须参数,2个 ...