前言
在上一篇介绍了CPU异常记录的过程,本篇介绍软件模拟异常的记录过程。并比对两者之间的区别。
分析软件模拟异常
本次用一个小实验,分析软件模拟异常的流程
测试代码
编译并运行如下代码(环境:Windows XP,IDE:VC++6.0)
1 |
|
查看反汇编
在”throw 1”处下断点,运行程序,进入反汇编查看。
可以看到,它调用了函数_CxxThrowException
_CxxThrowException
接下来步入_CxxThrowException
发现_CxxThrowException又调用了RaiseException函数,这是一个Kernel32.dll中的导出函数
RaiseException
RaiseException函数,又调用了RtlRaiseException函数,这是一个Ntdll.dll中的函数
RtlRaiseException
RtlRaiseException会先调用ZwRaiseException,然后通过系统服务调用机制,调用内核函数NtRaiseException,进入内核
NtRaiseException
NtRaiseException又调用了另一个内核函数KiRaiseException
KiRaiseException
KiRaiseException最终调用了用于异常分发的函数KiDispatchException
小结
根据软件模拟异常的执行流程,可以看出最终也会调用KiDispatchException函数,和CPU异常是一样的。所以可以认为,进入异常分发的步骤后,CPU异常与软件模拟异常就没有明显的区别了。接下来,将会对部分函数进行分析,了解软件模拟异常是如何填充和构建ExceptionRecord结构体的。
ExceptionRecord结构体填充
学习完CPU异常记录了解到,异常记录的核心步骤,是对_EXCEPTION_RECORD结构体的构建和初始化。这里先回顾一下该结构。
其中最重要的是ExceptionCode与ExceptionAddress两个字段的赋值。接下来,将会重新分析软件模拟异常执行流程中的一些函数,观察赋值的细节。
ExceptionAddress
再来看这个RaiseException函数,这是_CxxThrowException调用的一个3环函数,可以看到,该函数主要就是初始化ExceptionRecord结构体,其中ExceptionAddress填入的并不是发生异常处的地址,而是RaiseException函数的地址。
ExceptionCode
ExceptionCode是状态异常码,其实它已在RaiseException函数的参数中出现,所以我们得单步到_CxxThrowException调用RaiseException前传递参数的位置。
通过观察反汇编,可以看到,传给RaiseException的第一个参数值(ExceptionCode)为0xE06D7363,与Windows提供的异常状态码的值并不相符。原因是在软件模拟异常的情况下,ExceptionCode的值是根据不同的编译环境而设定的,调用RaiseException函数的CxxThrowException也是如此。例如Visual C++程序抛出的异常,会通过CxxThrowException调用RaiseException函数,ExceptionCode的值固定为0xE06D7363,但是在别的编译环境下(例如.NET程序)会通过其它函数调用RaiseException函数,ExceptionCode的值则为0xE0434F4D。
KiRaiseException
这里为啥还要重提一下这个函数呢。该函数在调用前还做了一件比较关键的事,将_EXCEPTION_RECORD.ExceptinCode的最高位清零,用于区分CPU异常。
总结
CPU异常与软件模拟异常,最终都要调用KiDispatchException,在对异常记录这部分的流程有所不同。其中ExceptionCode与ExceptionAddress两个字段尤为关键。
参考资料
参考书籍:
- 《软件调试 卷2:Windows平台调试》p243~p244 —— 张银奎
参考教程:
- 海哥中级预习班课程
参考链接:
- https://blog.csdn.net/qq_41988448/article/details/104989318 (CSDN-lyzddf学习笔记,他的笔记止步于此,之后的文章就不会有他笔记的引用了)
- https://blog.csdn.net/qq_38474570/article/details/104346316 (CSDN-鬼手56学习笔记)
- https://blog.csdn.net/weixin_42052102/article/details/83501391 (CSDN-My classmates学习笔记)