文章目录
前奏
当API函数3环进0环时,第一件事就是保存现场,保存到_Trap_Frame
异常的分类
CPU产生的异常
错误首先肯定被CPU先发现,然后CPU就会执行相应的错误处理程序
软件模拟产生的异常
throw 1
异常产生
CPU异常的产生
CPU指令检测到异常(例:除0)------>查IDT
表,执行中断处理函数--------->CommonDispatchException
------>KiDispatchException
在跳转CommonDispatchException
之前,还传了两个参数
ebp+68h也就是上图Trap结构体的Eip
0x0c0000094h也就是ExceptionCode
传了两个参数后调用CommonDispatchException,
CommonDispatchException函数分析
该函数构造一个_EXCEPTION_RECORD结构体,并赋值
CommonDispatchException函数的作用也就是把一些值赋值给一个_EXCEPTION_RECORD
结构体
type struct _EXCEPTION_RECORD
{
DWORD ExceptionCode;//异常代码(异常类型)
DWORD ExceptionFlags;//异常状态
Struct _EXCEPTION_RECORD* ExceptionRecord;//下一个异常
PVOID ExceptionAddress; //附加发生地址(异常发生地址)
DWORD NumberParameters; //附加参数个数
ULONG_PTR ExceptionInformation
[EXCEPTION_MAXIMUM_PARAMETERS];//附加参数指针
}
结构体作用就是用来记录异常信息
ExceptionFlags
(给后面的处理程序所用,辨别异常状态)
Struct _EXCEPTION_RECORD* ExceptionRecord
(通常为空,当发生嵌套异常(当异常处理程序里面又发生异常时)这个指针会指向下一个异常)
总结:
CPU异常执行的流程:
- CPU指令检测到异常
- 查IDT表,执行中断处理函数(往往并不真正处理异常,而是调用函数)
- 调用CommonDispatchException(构造_EXCEPTION_RECORD)
- KiDispatchException(分发异常:目的是找到异常处理函数)
软件模拟异常
模拟异常的产生:
CxxThrowException
------->(KERNEL32.DLL)RaiseException(DWORD dwException,DWORD dwExceptionFlags,DWORD nNumberOfArguments,const of ULONG_PTR *IPArguments)
--------->NTDLL.DLL!RtIRaiseException
()------->NT!NtRaiseException
---->NT!KiRaiseException
填充ExceptionRecord结构体
type struct _EXCEPTION_RECORD
{
DWORD ExceptionCode;//异常代码(异常类型)
DWORD ExceptionFlags;//异常状态
Struct _EXCEPTION_RECORD* ExceptionRecord;//下一个异常
PVOID ExceptionAddress; //附加发生地址(异常发生地址)
DWORD NumberParameters; //附加参数个数
ULONG_PTR ExceptionInformation
[EXCEPTION_MAXIMUM_PARAMETERS];//附加参数指针
}
软件模拟异常这个ExceptionCode
是固定的,值取决于编译环境,编译环境不同,ExceptionCode
也不同
这个ExceptionAddress
并不是抛出异常的位置,而是存了一个固定的值,这个值就是函数RaiseException
地址
(以上两点就是CPU产生的异常和软件模拟产生的异常之间的区别)
KiRaiseException函数分析
- EXCEPTION_RECORD.ExceptionCode最高位清零,用于区分CPU异常
- 调用
KiDispatchException
开始分发异常
总结:
CPU异常:
CPU指令检测到异常------>查IDT
表,执行中断处理函数--------->CommonDispatchException
(填充ExceptionRecord
结构体)------>KiDispatchException
模拟异常:throw关键词(依赖编译器)---->CxxThrowException
------->(KERNEL32.DLL)RaiseException
(DWORD dwException,DWORD dwExceptionFlags,DWORD nNumberOfArguments,const of ULONG_PTR *IPArguments
)(作用:填充ExceptionRecord结构体)--------->NTDLL.DLL!RtIRaiseException()
------->NT!NtRaiseException(ExceptionCode
最高位清零)---->NT!KiRaiseException
CPU异常和模拟异常类型不同,仅仅异常记录时不同,但是等到异常分发时,就没法区分了