1、KiUserExceptionDispatcher()函数分析(此函数在ntdll.dll中)
<1>调用RtlDispatchException()函数查找并执行异常处理函数
<2>RtlDispatchException()函数返回真,调用ZwContine()再次进入0环,但线程再次返回3环时,会从修正后的位置开始执行
<3>RtlDispatchException()函数返回假,调用ZwRaiseException()函数进行第二轮异常分发
_KiUserExceptionDispatcher@8 proc near ; DATA XREF: .text:off_7C923428↑o
.text:7C92E47C
.text:7C92E47C var_C = dword ptr -0Ch
.text:7C92E47C var_8 = dword ptr -8
.text:7C92E47C var_4 = dword ptr -4
.text:7C92E47C arg_0 = dword ptr 4
.text:7C92E47C
.text:7C92E47C mov ecx, [esp+arg_0]
.text:7C92E480 mov ebx, [esp+0]
.text:7C92E483 push ecx
.text:7C92E484 push ebx
.text:7C92E485 call _RtlDispatchException@8 ; RtlDispatchException(x,x)
.text:7C92E48A or al, al
.text:7C92E48C jz short loc_7C92E49A
.text:7C92E48E pop ebx
.text:7C92E48F pop ecx
.text:7C92E490 push 0
.text:7C92E492 push ecx
.text:7C92E493 call _ZwContinue@8 ; ZwContinue(x,x)
.text:7C92E498 jmp short loc_7C92E4A5
.text:7C92E49A ; ---------------------------------------------------------------------------
.text:7C92E49A
.text:7C92E49A loc_7C92E49A: ; CODE XREF: KiUserExceptionDispatcher(x,x)+10↑j
.text:7C92E49A pop ebx
.text:7C92E49B pop ecx
.text:7C92E49C push 0
.text:7C92E49E push ecx
.text:7C92E49F push ebx
.text:7C92E4A0 call _ZwRaiseException@12 ; ZwRaiseException(x,x,x)
.text:7C92E4A5
.text:7C92E4A5 loc_7C92E4A5: ; CODE XREF: KiUserExceptionDispatcher(x,x)+1C↑j
.text:7C92E4A5 add esp, 0FFFFFFECh
.text:7C92E4A8 mov [esp+0Ch+var_C], eax
.text:7C92E4AB mov [esp+0Ch+var_8], 1
.text:7C92E4B3 mov [esp+0Ch+var_4], ebx
.text:7C92E4B7 mov [esp+0Ch+arg_0], 0
.text:7C92E4BF push esp
.text:7C92E4C0 call _RtlRaiseException@4 ; RtlRaiseException(x)
.text:7C92E4C0 _KiUserExceptionDispatcher@8 endp ; sp-analysis failed
在3环的RtlDispatchException函数调用了RtlCallVectoredExceptionHandlers
0环中并没有调用
2、RtlDispatchException函数分析
<1>查找VEH链表(全局链表),如果有则调用
<2>查找SEH(结构化异常处理)链表(局部链表, 在堆栈中),如果有则调用
3、VEH测试
测试代码
#include <windows.h>
#include <stdio.h>
typedef PVOID (NTAPI *FnAddVectoredExceptionHandler)(ULONG, _EXCEPTION_POINTERS *);
FnAddVectoredExceptionHandler MyAddVectoredExceptionHandler;
//VEH异常处理函数只能返回两个值
//EXCEPTION_CONTINUE_EXECUTION 已处理
//EXCEPTION_CONTINUE_SEARCH 未处理
LONG NTAPI VectExceptionHandler(PEXCEPTION_POINTERS pExcepInfo)
{
::MessageBox(NULL, "VEH异常处理函数执行了", "VEH异常", MB_OK);
//除0异常对应的编号是0xC0000094
if(pExcepInfo->ExceptionRecord->ExceptionCode == 0xC0000094){
//函数返回如果想跳过idiv ecx指令执行printf则将Eip+2,idiv ecx 硬编码两个字节
//pExcepInfo->ContextRecord->Eip = pExcepInfo->ContextRecord->Eip + 2;
pExcepInfo->ContextRecord->Ecx = 1;
return EXCEPTION_CONTINUE_EXECUTION;
}
return EXCEPTION_CONTINUE_SEARCH;
}
int main()
{
//1.动态的获取 AddVectoredExceptionHandler 函数地址
HMODULE hMyModule = GetModuleHandle("kernel32.dll");
MyAddVectoredExceptionHandler = (FnAddVectoredExceptionHandler)::GetProcAddress(hMyModule, "AddVectoredExceptionHandler");
//2.参数1表示插入链表的头部,参数0表示插入链表的尾部
MyAddVectoredExceptionHandler(0, (_EXCEPTION_POINTERS *)&VectExceptionHandler);
//3.构造异常
_asm{
xor edx,edx
xor ecx,ecx
mov eax,0x10
idiv ecx //edx:eax除ecx
}
//4.产生异常从这里开始
printf("代码从这里继续执行\n");
getchar();
return 0;
}
4、总结:VEH异常处理流程
<1>CPU捕获异常
<2>通过KiDispatchException进行分发(EIP=KiUserExceptionHandler)
<3>KiUserExceptionHandler调用RtlDispatchException
<4>RtlDispatchException查找VEH处理函数链表,并调用相关处理函数
<5>返回KiUserExceptionHandler异常处理函数
<6>调用ZwContinue再次进入0环(ZwContinue调用NtContinue,主要作用是恢复_TRAP_FRAME,然后通过_KiServiceExit返回3环)
<7>线程再次返回3环,从修正后的位置开始执行