我们主要围绕这个主线展开:
- 异常记录
- 异常分发
- 异常处理
异常的分类
- CPU产生的异常
- 软件模拟产生的常
这种属于CPU产生的异常
int main()
{
int a = 10;
int b = 0;
int val = a / b;
}
这种属于软件模拟的异常
void a()
{
throw 1;
}
int main()
{
a();
}
CPU异常产生过程
- CPU指令检测到异常
- 查IDT表,执行中断处理函数
- 调用CommonDispatchException(构建EXCEPTION_RECORD)
- KiDispatchException(分发异常:目的是找到异常的处理函数)
下面跟一下除0异常处理执行过程,ida中Alt+T搜索_IDT
CommonDispatchException这个函数就是构建一个_EXCEPTION_RECORD结构体并赋值
typedef struct _EXCEPTION_RECORD//记录异常信息
{
DWORD ExceptionCode; //异常码
DWORD ExceptionFlags; //异常标志 cpu 0 ,软件模拟 1,嵌套异常10h ...
struct _EXCEPTION_RECORD* ExceptionRecord; //下一个异常 一般为NULL 除非出现嵌套异常
PVOID ExceptionAddress; //发生异常的指令地址
DWORD NumberParameters; //参数个数
ULONG_PTR ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS]; //附加参数指针
};
软件模拟异常的过程
- CxxThrowException
- (KERNEL32.DLL)RaiseException(DWORD dwExceptionCode, DWORD dwExceptionFlags, DWORD nNumberOfArguments, const ULONG PTR "IpArguments)
- NTDLL.DLL! RtIRaiseException()
- NT!NtRaiseException
- NT!KiRaiseException
(KERNEL32.DLL)RaiseException函数分析
0xE06D7363就是异常码,软件模拟的异常码是固定的依赖与编译环境。
RaiseException
KiRaiseException行为
- EXCEPTION_RECORD.ExceptionCode最高位清零用于区分CPU异常。
- 调用 KiDispatchException 开始分发异常