异常的处理流程
异常记录,异常分发,异常处理
异常的分类
1)CPU检测到的异常(例:除零)
2)软件模拟产生的异常(例:try catch)
1)发生在内核空间的内核异常
2)发生在用户空间的用户异常
一、CPU检测到的异常的记录和分发(可用ida打开ntoskrnl.exe分析)
- CPU检测到异常(例:除零)
- 查IDT表,执行中断处理函数
- CommonDispatchException把异常相关的信息写入EXCEPTION_RECORD结构体,并未处理异常,可理解为异常的记录
- KiDispatchException分发异常,寻找异常的处理函数,可理解为异常的初步分发
type struct _EXCEPTION_RECORD{
DWORD ExceptionCode //异常代码,就像一个ID
DWORD ExceptionFlags//异常状态,可用来区分是CPU异常还是软件模拟异常
struct _EXCEPTION_RECORD* ExceptionRecord//下一个异常,嵌套异常时会使用
PVOID ExceptionAddress//异常发生地址
DWORD NumberParameters//附加参数个数,一般不关注
ULONG_PTR ExceptionInformation [EXCEPTION_MAXIMUM_PARAMETERS]//附加参数指针,一般不关注
}
二、软件模拟产生的异常的记录和分发
- throw了异常
- CxxThrowException(vc6里的,不同语言该函数可能不同)
- KERNEL32.DLL的RaiseException,作用同CommonDispatchException
- NTDLL.DLL!RtlRaiseException
- NT!NtRaiseException
- NT!KiRaiseException
- KiDispatchException同上
一些值得注意的点
- 两种异常的共同点为最后都调用了KiDispachException
CPU产生的异常 | 软件模拟的异常 | |
---|---|---|
异常的记录 | RaiseException | CommonDispatchException |
异常的初步分发 | KiDispatchException | KiDispatchException |
- 两种异常在填充EXCEPTION_RECORD结构体时的不同点
CPU产生的异常 | 软件模拟的异常 | |
---|---|---|
ExceptionCode | 固定 | 不固定 |
ExceptionAddress | 存了真实的地址 | 存了RaiseException函数的地址 |