前言
从本篇开始,进入异常专题,这部分内容就比较关键了,因为异常这种机制,大部分操作系统都有一套自己的规则,大部分漏洞利用手法也和异常有关,前面的内容如果是基础,那么异常就是核心了。之前曾在中断与异常这篇提到过异常,当时只是简要总结了一下异常与中断的差异,现在来从异常的本质开始学习。
异常执行流程
异常产生后,首先是要记录异常信息(异常的类型、异常发生的位置等),然后要寻找异常的处理函数,这部分称为异常的分发,最后找到异常处理函数并调用,这一步称为异常处理。
之后关于异常的文章,也将会按照这三个主线展开:异常记录,异常分发,异常处理。
异常的分类
异常主要分为两种:
- CPU产生的异常
- 软件模拟产生的异常
例一:在编程语言中,若CPU检测到除数为0,便会抛出异常(CPU产生的异常)
例二:一些高级的编程语言,可以自己抛出异常(软件模拟产生的异常)
异常记录
本篇以CPU异常为主,根据其执行流程,学习并了解异常执行的第一步,异常记录。
除0异常执行流程
以除0异常为例,它的执行流程如下所示。
中断处理函数做了什么事
先来看一张中断描述符表
查阅中断描述符表,得知除0异常,会调用0号中断处理函数。接下来进入IDA(打开ntoskrnl.exe),看看0号中断都做了什么。
按下ALT+T,然后直接搜索_IDT,找到IDT表反汇编,进入0号中断处理函数。
进入0号中断处理函数后,开头部分的代码,是不是非常眼熟,可以比对一下来看。
这部分代码的主要作用就是保存现场,和API函数进0环时的KiSystemService函数保存现场的方式一样,这部分可以参考此篇文章。
接着往下看
可以看到,直到0号中断处理函数结束都没有对异常进行处理,反而是经过跳转,调用了另一个函数CommonDispatchException。为何中断处理函数不直接把异常处理掉呢?因为微软在设计时,希望程序员自己能够对异常进行处理,因此在中断处理函数中并没有对异常进行处理。
中断处理函数调用了CommonDispatchException,步入该函数
该函数构造了一个_EXCEPTION_RECORD结构体,并赋值,接着调用了KiDispatchException函数。KiDispatchException函数通常用来分发异常,目的是找到异常的处理函数。
至此,异常记录部分结束。
_EXCEPTION_RECORD
通过中断处理函数的流程,可以看到,异常记录只做了一件事,就是初始化_EXCEPTION_RECORD结构体。所以这个结构体就显得格外重要了,先来看看它的结构。
图中标明了字段的含义,这里对部分字段进一步解释:
ExceptionCode:异常状态码,微软给Windows系统中的每一种状态都设置了状态码。这部分可以参考MSDN对状态码的描述。根据中断处理函数传递给CommonDispatchException的参数,可以得到状态码0xC0000094。查询状态码列表,可得该状态码表示的正是除零异常。
ExceptionFlags:异常状态,0表示CPU异常,1表示软件模拟异常,8表示堆栈异常(参考软件调试,卷2,p241)。
ExceptionRecord:通常为0,若出现内嵌异常(处理一个异常时发生另一个异常)时,它指向下一个异常。
ExceptionAddress:异常发生地址,该值通过_Trap_Frame(+0x68)处获得,发生异常时会调用中断处理函数,EIP会被临时存到TrapFrame,在中断处理函数时,会将该地址赋给参数,再传递给CommonDispatchException函数。
小结:ExceptionCode与ExceptionAddress是最为重要的两个字段,也务必记住两个字段取值的来源。
总结
本篇主要介绍了CPU异常执行流程中的第一步,异常记录,对于CPU产生的异常,它首先会调用相应异常的中断处理函数,接着调用CommonDispatchException构建并初始化_EXCEPTION_RECORD结构体,最后再调用KiDispatchException分发异常。
参考资料
参考课程:
- 海哥中级预习班课程
参考链接:
- https://blog.csdn.net/qq_41988448/article/details/104989318 (CSDN-lzyddf学习笔记)
- https://blog.csdn.net/qq_38474570/article/details/104346316 (CSDN-鬼手56学习笔记)
- https://blog.csdn.net/weixin_42052102/article/details/83501391 (CSDN-My classmates学习笔记)
- https://en.wikipedia.org/wiki/Interrupt_descriptor_table (维基百科-IDT)
- https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/596a1078-e883-4972-9bbc-49e60bebca55?redirectedfrom=MSDN (MSDN-NTSTATUS Values)