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

  • 用户层与内核层异常
  • 内核异常
    • 分析 KiDispatchException
    • 分析 RtlDispatchException
    • _EXCEPTION_REGISTRATION_RECORD
  • 用户异常的分发
    • 用户异常
    • 分析 KiDispatchException
    • 总结:用户异常处理流程

用户层与内核层异常

描述

  1. 异常可以发生在用户空间,也可以发生在内核空间
  2. 无论是CPU异常还是模拟异常,是用户层异常还是内核异常,都要通过 KiDispatchException 函数进行分发,理解这个函数是学好异常的关键

内核异常

分析 KiDispatchException

声明:

VOID KiDispatchException(ExceptionRecord,ExceptionFrame,TrapFrame,PreviousMode,FirstChance);

处理逻辑

  1. 调用 _KeContextFromKframes,由于操作系统不知道分发的异常到底是3环的异常还是0环的异常,如果是3环的异常,进0环前的环境会被备份到Trap_Frame中,如果要在中途回到3环的话,就需要将 Trap_frame 备份到 context,为返回3环做准备
  2. 判断先前模式,0是内核调用,1是用户层调用,此时能够知道要分发的异常来自哪里。
  3. 是否是第一次调用
  4. 是否有内核调试器
  5. 如果没有或者内核调试器不处理,调用RtlDispatchException,寻找异常处理函数
  6. 如果RtlDispatchException返回FALSE,也就是0
  7. 再次判断是否有内核调试器,有就调用,没有会直接蓝屏


分析 RtlDispatchException

作用

  1. 遍历异常链表,调用异常处理函数,如果异常被正确处理了,该函数返回
  2. 如果当前异常处理函数不能处理该异常,那么调用下一个,以此类推
  3. 如果到最好也没有人处理这个异常,返回0

反汇编


可以发现,RtlDispatchException 调用了 RtlpGetRegistrationHead,RtlpGetRegistrationHead的唯一作用就是获取fs寄存器的值给eax
当程序位于0环是,FS寄存器指向KPCR,而KPCR的第一个成员又指向_EXCEPTION_REGISTRATION_RECORD这样一个结构体

_EXCEPTION_REGISTRATION_RECORD

声明

typedef struct _EXCEPTION_REGISTRATION_RECORD {struct _EXCEPTION_REGISTRATION_RECORD *Next;PEXCEPTION_ROUTINE Handler;
} EXCEPTION_REGISTRATION_RECORD;

描述

  1. _EXCEPTION_REGISTRATION_RECORD位于当前线程的堆栈中
  2. Next指向下一个结构体,Handler指向异常处理函数,是一个链表结构
  3. 当调用RtlDispatchException时,按顺序执行异常处理函数,若其中一个异常处理函数返回结果为真,就不再继续向下执行
  4. 若执行完所有异常处理函数后,异常仍然没有被处理,那么就返回FALSE

用户异常的分发

描述

  1. 异常如果发生在内核层,处理起来比较简单,因为异常处理函数也在0环,不用切换堆栈,但是如果异常发生在3环,就意味着必须要切换堆栈,回到3环执行处理函数

  2. 切换堆栈的处理方式与用户APC的执行过程几乎是一样的,惟一的区别就是执行用户APC时返回3环后执行的函数是KiUserApcDispatcher,而异常处理时返回3环后执行的函数是KiUserExceptionDispatcher

  3. 理解用户APC的执行过程是理解3环异常处理的关键

用户异常

描述:当异常发生时,无论是CPU异常还是模拟异常,最终在0环都要通过一个函数进行分发处理,这个函数就是KiDispatchException

VOID KiDispatchException(ExceptionRecord,ExceptionFrame,TrapFrame,PreviousMode,FirstChance);

注意:需先掌握用户APC执行过程

分析 KiDispatchException

  1. Trap_frame被分到context为返回3环做准备,因为目前不确定是从0环进来还是从3环进来
  2. 判断先前模式,0是内核调用,1是用户层调用

    3. 从loc_42590B向下分析,是在为TRAP_FRAME结构体赋值,准备结束

总结:用户异常处理流程

  1. _KeContextFromKframes将Trap_frame被分到context为返回3环做准备
  2. 判断席安全模式,0是内核调用,1是用户层调用
  3. 是否都是第一次机会
  4. 是否有内核调试器
  5. 发送给3环调试
  6. 如果3环调试器没有处理这个异常,修正EIP为KiUserExceptionDispatcher
  7. KiUserExceptionDispatcher函数执行结束:CPU异常与模拟异常返回地点不同
    CPU异常:CPU检测到异常→查IDT执行处理函数→CommonDispatchException→KiDispatchException通过IRETD返回3环
    模拟异常:CxxThrowException→RaiseException→RtlRaiseException→NT!NtRaiseException→NT!KiRaiseException→KiDispatchException通过系统调用返回3环
    

Windows异常学习笔记(二)—— 内核异常处理流程用户异常的分发相关推荐

  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 APC学习笔记(二)—— 挂入过程执行过程

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

  5. Windows系统调用学习笔记(二)—— 3环进0环

    Windows系统调用学习笔记(二)-- 3环进0环 要点回顾 基本概念 _KUSER_SHARED_DATA 0x7FFE0300 实验:判断CPU是否支持快速调用 第一步:修改EAX=1 第二步: ...

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

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

  7. Windows消息机制学习笔记(三)—— 消息的接收与分发

    Windows消息机制学习笔记(三)-- 消息的接收与分发 要点回顾 消息循环 消息队列 消息的接收 GetMessage 实验1:理解GetMessage 第一步:编译并运行程序A 第二步:编译并运 ...

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

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

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

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

最新文章

  1. 博客已经迁移至 http://barretlee.com/entry/,时而同步分享到这里
  2. 开始报名丨CCF C³-05@亚马逊云科技:未来云计算之旅
  3. 公式编辑公式总是偏上怎么办?
  4. js ajax上传图片到服务器
  5. Android 监控网络状态
  6. html中post语句,html中post乱码的解决方法
  7. android 对话框 重复,如何在Android上重复使用AlertDialog for Yes / No?
  8. codevs 5958 无
  9. 自增主键为什么不是连续的?
  10. paip.invalid conversion from FormWdg* to SOCKET {aka unsigned int}
  11. 网易云音乐歌曲带时间轴歌词的提取
  12. servlet的九大内置对象和四大作用域
  13. 我们的青春已落幕,用 Python 分析韦德职业生涯数据
  14. 服务器右键文件夹不显示共享,右键不出现共享菜单 文件或文件夹不能共享怎么办?...
  15. PLUS模型教程2:数据前期准备和土地利用数量预测
  16. 集线器,交换机与路由器
  17. 1.3 guessing game
  18. 大数据中一些常用软件
  19. 已解决:出现了自己签名的证书。 错误: 证书通用名 “www.doctorcom.com” 与所要求的主机名 “raw.githubusercontent.com” 不符。
  20. 敏捷开发中如何写好用户故事?

热门文章

  1. Interview:算法岗位面试—上海某公司算法岗位(偏图像算法,互联网科技行业)技术面试考点之区块链的TPS等问题
  2. ModelFileType:XML、Hdf5、dat等不同模型文件后缀文件的简介、使用方法之详细攻略
  3. ML与math:机器学习与高等数学基础概念、代码实现、案例应用之详细攻略——进阶篇
  4. 成功解决Remix Mock compiler: Source not found
  5. 深度学习中常用的误差方法
  6. Using Preferences(Beginning Android)
  7. utf-8 字符串转为Unicode编码格式
  8. HaoheDI让ETL变得简单
  9. Laravel的console使用方法
  10. MySQL中用decimal的原因