VEH(向量化异常处理)

内容回顾:

当用户异常产生后,内核函数KiDispatchException并不是像处理内核异常那样在0环直接进行处理,而是修正3环EIP为KiUserExceptionDispatcher函数后就结束了
这样,当线程再次回到3环时,将会从KiUserExceptionDispatcher函数开始执行

KiUserExceptionDispatcher

  1. 调用RtDispatchException查找并执行异常处理函数
  2. 如果RtDispatchException返回真,调用ZwContinue再次进入0环,但线程再次返回3环时,会从修正后的位置开始执行
  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函数分析

  1. 查找VEH链表(全局链表),如果有则调用(与线程无关)
  2. 查找SEH链表(局部链表,在堆栈中),如果有则调用

注意:与内核调用时的区别

总结:

VEH异常的处理流程

  1. CPU捕获异常信息
  2. 通过KiDispatchException进行分发(EIP==KiUSerExceptionDispatcher)
  3. KiUSerExceptionDispatcher调用RtlDispatchException
  4. RtlDispatchException查找VEH处理函数链表,并调用为相关处理函数
  5. 代码返回KiUserExceptionDispatcher
  6. 调用ZwContine再次进入0环(ZwContinue调用NtContinue,主要作用就是恢复_TRAP_FRAME然后通过_KiServiceExit返回到3环)
  7. 线程再次返回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();

}

实现截图:
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/CSNN2019/article/details/113840002