首页
社区
课程
招聘
[原创] (向量化异常处理)VEH hook
发表于: 2014-7-31 11:21 37030

[原创] (向量化异常处理)VEH hook

2014-7-31 11:21
37030
近期在研究VEH HOOK 参考了网上的网上的一些文章  讲解的均不怎么全 也遇到了部分问题
再次向:cvrock kuty bxc致谢。

本文章内容讲的比较细 请耐心观看。

VEH (向量化异常处理)

VEH 的中文名字: 向量化异常处理(Vectored Exception Handling)
1.VEH 最早出现在XP上 因为只有XP及以上Window版本才支持
目前 Windows 平台下实现和使用的异常处理机制主要有 4 种:
  筛选器异常处理,结构化异常处理(Structure Exception Handler, SEH),向量化异常处理(Vectored Exception Handler, VEH),C++异常处理(C++ Exception Handler, C++EH)。
其中 前三种为操作系统提供的异常处理机制,最后一种为C++提供的

VEH通过使用 Win32 API 函数 AddVectoredExceptionHandler可注册新的异常处理函数,函数的参数就是指向 EXCEPTION_POINTERS 结构的指针。同时,增加了函数地址的注册处理程序链表。由于系统中使用一个链表来存储矢量异常处理程序,程序可以安装尽可能多的向量处理器,只要有必要。
在用户模式下发生异常时,异常处理分发函数在内部会先调用遍历 VEH 记录链表的函数, 如果没有找到可以处理异常的注册函数,再开始遍历 SEH 注册链表。
二者之间具体联系:VEH优先权高于SHE,只有所有VEH全不处理某个异常的时候,异常处理权才会到达SHE。只要目标程序中没有利用VEH,那么,你所设计的VEH将是第一个得到控制者。现在采用SEH作为异常处理的普通C/C++程序对你将不会再有干扰,可以通过使用VEH来进行hook处理了。
如果存在调试器,那么控制权转向将会发生新的变化。当异常发生后,首先通知的将会是调试器,调试器不处理才会再返回控制权给VEH;如果VEH不处理,再返回给SHE;若SEH不处理,再给调试器一个机会,如果还不处理,则交由系统处理。

应用层异常处理结构图

VEH回调函数详解

VEH由AddVectoredExceptionHandler添加处理函数 处理函数有一个参数 参数类型为PEXCEPTION_POINTERS结构体
结构PEXCEPTION_POINTERS中保存着当前异常的各个寄存器,堆栈,地址,等多种信息 以下是PEXCEPTION_POINTERS的展开图

PEXCEPTION_POINTERS

VEH Hook原理

1.异常处理结构中 VEH是唯一一个可以接受到所有异常信息的处理 换句话说 所有的异常信息 都会经过VEH
2.异常信息 通常是由[数组越界,内存访问出错,无效参数,int 3]等 造成的
3.一旦发生异常 操作系统会立即便利VEH 如果有处理函数 中断线程 并由处理函数处理。
根据以上信息 可以确定一个思路 比如我们hook 消息框API 给API的首地址写入int 3 断点 当执行时会产生异常 线程暂停 转交给异常处理函数处理 此时则可以在处理函数中做手脚 比如修改堆栈参数等。

相应操作完成后 将int3(0xcc)修改回源代码 修改EIP=addr(异常地址)让此处的代码重新执行一次正确的代码,将Eflags寄存器修改为单步调试模式(Eflags |= 0x100) 返回EXCEPTION_CONTINUE_EXECUTION(-1)让程序继续运行 然后又会产生一次断点(单步异常),此时我们将已经执行过的代码重新修改为int3(0xcc) 返回-1让程序继续运行。

以下部分是代码部分 (代码难看 不喜勿喷)
首先 在DLLMain的初次调用中开始HOOK
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
VEH_HOOK_MessageBoxA();

MessageBoxA  hook步骤如下
1.添加异常处理函数  并指定参数为第零个 (第一个执行)
2.备份MessageBoxA的第一个字节
3.在MessageBoxA第一个字节写入int3(cc)

void VEH_HOOK_MessageBoxA()
{
AddVectoredExceptionHandler(0,CALL_MessageBoxA);
MessageBoxA_Addr=(PVOID)&MessageBoxA;
MessageBoxA_Ole_INT=*(BYTE*)MessageBoxA_Addr;
VirtualProtect((void*)MessageBoxA_Addr,BREAKPOINTLEN,dwNewProtect,&dwOldProtect);
*(BYTE*)(MessageBoxA_Addr)=0xcc;
VirtualProtect((void*)MessageBoxA_Addr,BREAKPOINTLEN,dwNewProtect,&dwOldProtect);
}

现在来看一下 异常处理函数的初步处理步骤

0.判断是否是int3异常
1.修改EIP为异常发生处地址(再执行一次)
2.判断异常发生地址不等于0(无意义)
3.修改堆栈的参数
4.修改寄存器上下文
5.备份CPU控制寄存器
6.CPU控制寄存器设置为单步模式
7.恢复先前备份的MessageBoxA第一个字节的代码
8.返回-1 让其继续运行


LONG NTAPI CALL_MessageBoxA(struct _EXCEPTION_POINTERS *ExceptionInfo)
{
if(ExceptionInfo->ExceptionRecord->ExceptionCode==EXCEPTION_BREAKPOINT)
{
addr=ExceptionInfo->ExceptionRecord->ExceptionAddress;
if (addr!=(PVOID)0)
{
//修改参数
char *lpText="Hello World!";
*(int*)((ExceptionInfo->ContextRecord->Esp)+0x8)=(int)lpText;
*(int*)((ExceptionInfo->ContextRecord->Esp)+0xc)=(int)lpText;
sprintf(lpbuff,"My::%s=%s",lpText,0);
OutputDebugStringA(lpbuff);
//修改状态
ExceptionInfo->ContextRecord->ContextFlags=CONTEXT_CONTROL;
ExceptionInfo->ContextRecord->Eip = /*(DWORD)&MessageBoxA;*/(DWORD)addr;
EFlags=ExceptionInfo->ContextRecord->EFlags;
ExceptionInfo->ContextRecord->EFlags |= 0x100;
//恢复代码
VirtualProtect((void*)addr,BREAKPOINTLEN,dwNewProtect,&dwOldProtect);
*(BYTE*)(addr) = MessageBoxA_Ole_INT;
VirtualProtect((void*)addr,BREAKPOINTLEN,dwOldProtect,&dwNewProtect);
OutputDebugStringA("My::单步运行,取消断点");
//AddVectoredExceptionHandler(NULL,(PVECTORED_EXCEPTION_HANDLER)ExceptionInfo);
return EXCEPTION_CONTINUE_EXECUTION;
}
}

首先呢 大家注意  我们上面有设置CPU的寄存器为单步模式  也就是说CPU在运行一条汇编指令的时候会再次产生异常 而后借此机会我们将被恢复为正确代码的MessageBoxA重新改为int3 让其下次依然可以被我们拦截处理。

1.判断异常类型是否等于单步类型
2.恢复CPU控制寄存器
3.恢复MessageBoxA的代码
4.返回让其继续运行


else if ( ExceptionInfo->ExceptionRecord->ExceptionCode == STATUS_SINGLE_STEP )
{
//还原断点,标志位。
OutputDebugStringA("My::还原断点");
ExceptionInfo->ContextRecord->EFlags =EFlags;
*(BYTE*)(addr) = 0xcc;
return EXCEPTION_CONTINUE_EXECUTION;
}
return EXCEPTION_EXECUTE_HANDLER;
}


以下是源码  与PPT 如果觉得不错  记得给点感谢之类的哦
VEH_Hook.rar   VEH Hook ppt.rar

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

上传的附件:
收藏
免费 5
支持
分享
最新回复 (37)
雪    币: 2143
活跃值: (720)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
2
图挂了。
2014-7-31 11:24
0
雪    币: 2588
活跃值: (3579)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
图片看不到
2014-7-31 11:24
0
雪    币: 457
活跃值: (218)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
4
图片可以了  刚才空间禁止了
2014-7-31 11:32
0
雪    币: 457
活跃值: (218)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
5
图片可以了  刚才空间禁止了
2014-7-31 11:36
0
雪    币: 119
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
前排看加精
2014-7-31 11:40
0
雪    币: 7068
活跃值: (3517)
能力值: ( LV12,RANK:340 )
在线值:
发帖
回帖
粉丝
7
我这么有面子啊
2014-7-31 12:29
0
雪    币: 60
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
我们上面有设置CPU的寄存器为单步模式


是哪句代码?

。。。看到了。
2014-7-31 13:06
0
雪    币: 459
活跃值: (344)
能力值: ( LV8,RANK:120 )
在线值:
发帖
回帖
粉丝
9
楼主的名字,曾几何时,貌似在广海看到过
忽然回忆起了,之前写的关于VEH 的东东
2014-7-31 14:10
0
雪    币: 218
活跃值: (223)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
不错,支持一下
不过现在这种手法运用没多大用处了,现在crc改一字节照样查出来
2014-7-31 14:44
0
雪    币: 457
活跃值: (218)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
11
申精!!!!!!!!!!!!!!!!!!!!!!!!!!
2014-7-31 15:29
0
雪    币: 435
活跃值: (1207)
能力值: ( LV13,RANK:388 )
在线值:
发帖
回帖
粉丝
12
~我去验证下
2014-7-31 15:58
0
雪    币: 457
活跃值: (218)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
13
广海呆过一段时间  人少 没人交流技术  所以也就不去了
2014-7-31 17:34
0
雪    币: 11
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
不错的技术~
2014-8-1 14:46
0
雪    币: 11
活跃值: (40)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
感觉来回修复函数头这个思路不太好
不过还是感谢楼主的整体思路
2014-8-1 18:35
0
雪    币: 45
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
我也是这样感觉。可以把第一条指令放到一个置执行属性的buffer里面,后面跟个跳转用来跳转到第二指令,
int3不修复。Eip指向这个buffer,这样感觉会更好些。
2014-8-1 20:11
0
雪    币: 58
活跃值: (72)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
17
感谢LZ分享
2014-8-1 20:15
0
雪    币: 11
活跃值: (40)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
18
用缺页异常如何……
2014-8-2 19:12
1
雪    币: 995
活跃值: (669)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
19
觉得写入INT3 有的游戏会CRC扫描不安全 不知道设置内存页面不可执行可以吗
2014-8-3 14:28
1
雪    币: 457
活跃值: (218)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
20
这个只是我第一次研究学习而已  没太重视 技术学到了 剩下的就是思路了
2014-8-4 13:36
0
雪    币: 4873
活跃值: (3112)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
21
讲的比较接地气~支持下。
2014-11-19 12:43
0
雪    币: 4873
活跃值: (3112)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
22
+1  
2014-11-19 12:45
0
雪    币: 130
活跃值: (392)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
23
马克~~
2015-6-7 15:32
0
雪    币: 6890
活跃值: (8944)
能力值: ( LV17,RANK:797 )
在线值:
发帖
回帖
粉丝
24
MessageBoxA_Addr=(PVOID)&MessageBoxA;
取出来的地址不一定是是MessageBoxA的真实地址吧?
2015-6-7 16:45
0
雪    币: 6890
活跃值: (8944)
能力值: ( LV17,RANK:797 )
在线值:
发帖
回帖
粉丝
25
可以下硬件断点吧。
2015-6-7 17:01
0
游客
登录 | 注册 方可回帖
返回
//