一、CPU异常记录
1)CPU产生的异常 2)软件模拟产生的异常
CPU指令检测到异常(例:除0) -->查IDT表,执行中断处理函数 -->CommonDispatchException-->KiDispatchException
_KiTrap00函数分析: 1)保存现场(将寄存器堆栈位置等信息保存到_trap_frame中) 2)调用CommonDispatchException函数(分析参数EAX,EBX中的值) 为什么不把异常直接处理掉?
该函数构造一个_EXCEPTION_RECORD结构体并赋值
type struct_EXCEPTION_RECORD { DWORD ExceptionCode; //异常代码 DWORD ExceptionFlags; //异常状态 struct_EXCEPTION_RECORD* ExceptionRecord; //下一个异常 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.DLLIRtIRaiseException() --> NTINtRaiseException --> NT!KiRaiseException
1)填充ExceptionRecord结构体
type struct_EXCEPTION_RECORD { DWORD ExceptionCode; //异常代码 DWORD ExceptionFlags; //异常状态 struct_EXCEPTION_RECORD* ExceptionRecord; //下一个异常 PVOID ExceptionAddress; //异常发生地址 DWORD NumberParameters; //附加参数个数 ULONG_PTR ExceptionInformation [EXCEPTION_MAXIMUM_PARAMETERS]; //附加参数指针 }
- 调用Ntdll.dll!RtIRaiseException函数
异常可以发生在用户空间,也可以发生在内核空间。 无论是CPU异常还是模拟异常,是用户层异常还是内核异常,都要通过 KiDispatchException函数进行分发。理解这个函数是学好异常的关键,这个函数比较复杂,本节课我们主要分析内核异常是如何分发,如何处理的。
VOID KiDispatchException(ExceptionRecord, ExceptionFrame, TrapFrame,PeviousMode,FirstChance) 1)_KeContextFromKframes将Trap_frame备份到context为返回3环做准备 2)判断先前模式PeviousMode 0是内核调用1是用户层调 3)是否是第一次机会 4)是否有内核调试器 5)如果没有或者内核调试器不处理 6)调用RtIDispatchException
typedef struct_EXCEPTION_REGISTRATION_RECORD { struct_EXCEPTION_REGISTRATION_RECORD *Next; PEXCEPTION_ROUTINE Handler; }EXCEPTION_REGISTRATION_RECORD;
RtIDispatchException的作用就是: 遍历异常链表,调用异常处理函数,如果异常被正确处理了,该函数返回1. 如果当前异常处理函数不能处理该异常,那么调用下一个,以此类推。 如果到最好也没有人处理这个异常,返回0。
VOID KiDispatchException(ExceptionRecord, ExceptionFrame, TrapFrame,PeviousMode,FirstChance) 1)_KeContextFromKframes将Trap_frame备份到context为返回3环做准备 2)判断先前模式PeviousMode 0是内核调用1是用户层调 3)是否是第一次机会 4)是否有内核调试器 5)发送给3环调试 6)如果3环调试器没有处理这个异常修正EIP为KiUserExceptionDispatcher 7)KiDispatchException函数执行结束: CPU异常与模拟异常返回地点不同 CPU异常: CPU检测到异常→查IDT执行处理函数--> CommonDispatchException->KiDispatchException 通过IRETD返回3环 模拟异常: CxxThrowException-RaiseException->RtiRaiseException NTINtRaiseException→>NTIKiRaiseException-->KiDispatchException 通过系统调用返回3环 8)无论通过那种方式,但线程再次回到3环时,将执行KiUserExceptionDispatcher函数
1)调用RtIDispatchException查找并执行异常处理函数 2)如果RtIDispatchException返回真,调用ZwContinue再次进入0环,但线程再次返回3环时,会从修正后的位置开始执行。 3)如果RtIDispatchException返回假,调用ZwRaiseException进行第二轮异常分发
1)查找VEH链表(全局链表),如果有则调用 2)查找SEH链表(局部链表,在堆栈中),如果有则调用 注意:与内核调用时的区别!
1)CPU捕获异常信息 2)通过KiDispatchException进行分发(EIP=KiUserExceptionDispatcher) 3)KiUserExceptionDispatcher调用RtIDispatchException 4)RtIDispatchException查找VEH处理函数链表并调用相关处理函数 5)代码返回到KiUserExceptionDispatcher 6)调用ZwContinue再次进入0环(ZwContinue调用NtContinue,主要作用就是恢复TRAP-FRAME然后通过-KiServiceExit返回到3环)。 7)线程再次返回3环后,从修正后的位置开始执行
1)FS:[0]指向SEH链表的第一个成员 2)SEH的异常处理函数必须在当前线程的堆栈中 3)只有当VEH中的异常处理函数不存在或者不处理才会到SEH链表中查找
描述:当我们程序刚开始执行时,编译器已经替我们注册了一个异常处理程序,因此叫做最后一道防线
UnhandledExceptionFilter 描述:
最后一道防线调用的异常处理程序的过滤函数 只有当它的返回值为EXCEPTION_CONTINUE_SEARCH(0)时,当前线程不存在对应的SEH 只有在当前程序处于调试状态时,才会发生上述情况 执行流程:
通过NtQueryInformationProcess查询当前进程是否正在被调试,如果是,返回EXCEPTION_CONTINUE_SEARCH,此时会进入第二轮分发 如果没有被调试: 1)查询是否通过SetUnhandledExceptionFilter注册处理函数 如果有就调用 2)如果没有通过SetUnhandledExceptionFilter注册处理函数,弹出窗口,让用户选择终止程序还是启动即时调试器 3)如果用户没有启用即时调试器,那么该函数返回EXCEPTION_EXECUTE_HANDLER,此时会执行except中的代码
到此这篇windows驱动开发(windows驱动开发书籍)的文章就介绍到这了,更多相关内容请继续浏览下面的相关推荐文章,希望大家都能在编程的领域有一番成就!版权声明:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若内容造成侵权、违法违规、事实不符,请将相关资料发送至xkadmin@xkablog.com进行投诉反馈,一经查实,立即处理!
转载请注明出处,原文链接:https://www.xkablog.com/goyykf/28794.html