异常的处理流程
异常记录,异常分发,异常处理
异常的分类
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函数的地址 |