Windows内核分析索引目录:https://www.cnblogs.com/onetrainee/p/11675224.html
用户层异常的处理 - VEH异常
1.初始VEH异常
1)VEH异常链表是一个全局链表,其模板如下:
LONG NTAPI VehFunc(struct _EXCEPTION_POINTERS* ExceptionInfo) {
return EXCEPTION_CONTINUE_SEARCH;
}
int main(int argc, char* argv[])
{
// 1-veh链头部,0-veh链尾部。
AddVectoredExceptionHandler(1,VehFunc);
return 0;
}
其中 _EXCEPTION_POINTER结构体如下:
typedef struct _EXCEPTION_POINTERS {
PEXCEPTION_RECORD ExceptionRecord; // 异常记录
PCONTEXT ContextRecord; // 异常发生时的各个寄存器的值
} EXCEPTION_POINTERS, *PEXCEPTION_POINTERS;
2)VEH异常的返回值
#define EXCEPTION_EXECUTE_HANDLER 1 // 异常被识别,_except模块中处理该异常
#define EXCEPTION_CONTINUE_SEARCH 0 // 异常未被识别,继续调用下一个Handler来处理异常
#define EXCEPTION_CONTINUE_EXECUTION (-1) // 异常已被忽略或修复,不继续往下寻找
注意:SEH异常与VEH异常返回值是不同的,对于SEH异常,其返回的是一个 enum EXCEPTION_DISPOSITION。
3)我们根据ContextRecord中保存的寄存器我们就可以实现对我们的代码出现异常的修复,下面是除零异常代码的修复:
LONG NTAPI VehFunc(struct _EXCEPTION_POINTERS* ExceptionInfo) {
if (ExceptionInfo->ExceptionRecord->ExceptionCode == 0xc0000094) {
ExceptionInfo->ContextRecord->Eip += 2;
printf("除零异常已被处理了!
");
return EXCEPTION_CONTINUE_EXECUTION;
}
return EXCEPTION_CONTINUE_SEARCH;
}
int main(int argc, char* argv[])
{
// 1-veh链头部,0-veh链尾部。
AddVectoredExceptionHandler(1,VehFunc);
_asm {
mov ebx, 0;
mov eax, 1;
idiv ebx;
}
return 0;
}
2. Ntdll!RtlAddVectoredExceptionHandler函数分析
该函数分析如下,值得注意的是其中的Handler都是被加密的,因此这意味着你不能手动向Veh中加入链表然后期待着被调用触发。
可以看出其调用AllocateHeap,说明存储在堆中,作为一个进程是全局共享的。
3. Ntdll!RtlCallVectoredExceptionHandlers函数分析
该函数就是遍历VEH链表找到函数来进行分析,其函数结构时相当清晰地,VEH的handler被加密了,此时会执行加密。
整体的处理流程下面已经分析地相当透彻了,这里就不在做过多的解释了。