内容回顾:
当用户异常产生后,内核函数KiDispatchException并不是像处理内核异常那样在0环直接进行处理,而是修正3环EIP为KiUserExceptionDispatcher函数后就结束了
这样,当线程再次回到3环时,将会从KiUserExceptionDispatcher函数开始执行
KiUserExceptionDispatcher
- 调用RtDispatchException查找并执行异常处理函数
- 如果RtDispatchException返回真,调用ZwContinue再次进入0环,但线程再次返回3环时,会从修正后的位置开始执行
- 如果RtDispatchException返回假,调用ZwRaiseException进行第二轮异常分发
回到3环后执行如上所述代码,通过
这个函数找到异常处理函数,找到以后,如果处理成功,就通过
回到零环,这里解释一下为什么还要回到0环?
当回到3环时,在0环通过Trap_frame备份到context结构体,,然后修改Trap_frame的EIP值,但当处理完异常之后,还需要回到原来那个地址,也就是context里面保存的EIP值,即EIP的值需要再次修正,回零环的目的也就是把修正后的EIP(即context结构体)重新写到Trap_frame里,之后就会从修正后的位置从0环回到3环(也就是原来从3环进入0环的位置)
但是如果
这个找异常处理函数没有找到的话,那么往下执行就会调用在这里插入图片描述
这个函数(它的作用就是对这个异常进行第二次分发)
首先来看第一次分发(KiDispatchException是一个库函数,在3环和0环代码实现有区别,感觉就像是用了宏定义)
在这个函数里面先调用了如下这个函数:
上图)这个函数作用就是找一个全局链表,这个链表里面存储了一个一个异常处理函数,如果在全局链表里面找到了异常处理函数,那么直接返回;如果找不到当前异常处理函数,那么就往下找,去局部链表里面找
RtDispatchException函数分析
- 查找VEH链表(全局链表),如果有则调用(与线程无关)
- 查找SEH链表(局部链表,在堆栈中),如果有则调用
注意:与内核调用时的区别
总结:
VEH异常的处理流程
- CPU捕获异常信息
- 通过KiDispatchException进行分发(EIP==KiUSerExceptionDispatcher)
- KiUSerExceptionDispatcher调用RtlDispatchException
- RtlDispatchException查找VEH处理函数链表,并调用为相关处理函数
- 代码返回KiUserExceptionDispatcher
- 调用ZwContine再次进入0环(ZwContinue调用NtContinue,主要作用就是恢复_TRAP_FRAME然后通过_KiServiceExit返回到3环)
- 线程再次返回3环后,从修正后的位置开始执行
代码实现
#include<iostream>
#include<Windows.h>
using namespace std;
typedef PVOID (NTAPI *FnAddVectoredExceptionHandler)(ULONG, _EXCEPTION_POINTERS*);
FnAddVectoredExceptionHandler MyAddVectoredContinueHandler;
//VEH异常处理函数只能返回两个值
//EXCEPTION_CONTINUE_EXECUTION 已处理
//EXCEPTION_CONTINUE_SEARCH 未处理
LONG NTAPI VectExcepHandler(PEXCEPTION_POINTERS pExcepInfo)
{
//pExcepInfo->ExceptionRecord(异常的地址,状态等信息)
//pExcepInfo->ContextRecord(异常发生时上下文的环境)
::MessageBoxA(NULL, "VEH异常处理函数执行了", "VEH异常", MB_OK);
if (pExcepInfo->ExceptionRecord->ExceptionCode == 0xC0000094) {
pExcepInfo->ContextRecord->Eip = pExcepInfo->ContextRecord->Eip + 2;
// pExcepInfo->ContextRecord->Ecx = 1;(两个选择:要么修复,要么换个地址)
return EXCEPTION_CONTINUE_EXECUTION;
}
return EXCEPTION_CONTINUE_SEARCH;
}
int main() {
//1.动态获取AddVectoredExceptionHandler函数地址
HMODULE hMyHandle = GetModuleHandle("kernel32.dll");
MyAddVectoredContinueHandler = (FnAddVectoredExceptionHandler)::GetProcAddress(hMyHandle, "AddVectoredExceptionHandler");
//2.参数1表示插入VEH链的头部,0表示插入VEH链的尾部
MyAddVectoredContinueHandler(0, (_EXCEPTION_POINTERS*)&VectExcepHandler);
//3.构造除0异常
__asm
{
xor edx,edx
xor ecx,ecx
mov eax,0x10
idiv ecx //EDX:EAX除以ECX
}
//4.产生异常,从这里开始
printf("异常开始了");
getchar();
}
实现截图: