首页
社区
课程
招聘
[原创]VEH分析
发表于: 2013-3-22 18:25 38207

[原创]VEH分析

2013-3-22 18:25
38207

注册了这么长时间还是临时会员,虽然很惬意,但是怪不好意思的,于是决定发一篇文章赚点Kx

转载请注明出处

正文开始:

当程序发生异常的时候,一共有两种处理异常的方式。一种是SEH,这个不在本次的讨论范围内。另一种就是VEH了,那么VEH到底是什么呢?下面来随我体验VEH之旅。

在Windows系统中有一个双向链表,每当操作系统发生异常的时候,系统会检测进程的PEB结构中的EnvironmentUpdateCount元素,当PEB. EnvironmentUpdateCount符合要求的时候,系统将会遍历VEH异常链表,VEH异常处理函数会得到执行。

在Windows中有两个函数:

PVOID WINAPI AddVectoredExceptionHandler(
  _In_  ULONG FirstHandler,
  _In_  PVECTORED_EXCEPTION_HANDLER VectoredHandler
);
PVOID WINAPI AddVectoredContinueHandler(
  _In_  ULONG FirstHandler,
  _In_  PVECTORED_EXCEPTION_HANDLER VectoredHandler
);
这两个函数就是向VEH表链添加异常处理函数的,所不同的是AddVectoredExceptionHandler添加的函数会在SEH异常函数之前执行,而AddVectoredContinueHandler添加的函数,会在SEH异常函数之后执行

        参数说明:
        FirstHandler:是否将VEH函数插入到VEH链表头,插入到链表头的函数先执行。
        VectoredHandler 异常处理函数指针

上面是概述,下面说VEH原理

打开VS编辑代码如下,

生成的程序用OD载入,所有代码如下


我们发现其实AddVectoredExceptionHandler是封装了一下ntdll的RtlAddVectoredExceptionHandler函数

我们用IDA打开Ntdll,找到RtlAddVectoredExceptionHandler函数,情形如下



我们发现,RtlAddVectoredExceptionHandler函数其实是对RtlpAddVectoredHandler的封装,
写成c代码样式如下

PVOID WINAPI RtlAddVectoredExceptionHandler(
  _In_  ULONG FirstHandler,
  _In_  PVECTORED_EXCEPTION_HANDLER VectoredHandler
)
{
        return RtlpAddVectoredHandler(FirstHandler,VectoredHandler,0);
}

看到RtlpAddVectoredHandler的第三个参数被设置成了0,
如果此时你跟踪的是AddVectoredContinueHandler,你会发现此时第三个参数被设置成了1
AddVectoredContinueHandler和AddVectoredExceptionHandler差别就差在第三个参数上,所以才导致AddVectoredExceptionHandler在SEH之前执行,AddVectoredContinueHandler在SEH之后执行。

我们再跟入RtlpAddVectoredHandler函数,情形如下

=============== S U B R O U T I N E =======================================
.text:77EE51E0
.text:77EE51E0 ; Attributes: bp-based frame
.text:77EE51E0
.text:77EE51E0 ; __stdcall RtlpAddVectoredHandler(x, x, x)
.text:77EE51E0 _RtlpAddVectoredHandler@12 proc near    ; CODE XREF: RtlAddVectoredExceptionHandler(x,x)+Dp
.text:77EE51E0                                         ; RtlAddVectoredContinueHandler(x,x)+Dp
.text:77EE51E0
.text:77EE51E0 arg_0           = dword ptr  8
.text:77EE51E0 arg_4           = dword ptr  0Ch
.text:77EE51E0 arg_8           = dword ptr  10h
.text:77EE51E0
.text:77EE51E0 ; FUNCTION CHUNK AT .text:77ECF76D SIZE 00000012 BYTES
.text:77EE51E0
.text:77EE51E0                 mov     edi, edi
.text:77EE51E2                 push    ebp
.text:77EE51E3                 mov     ebp, esp
.text:77EE51E5                 mov     eax, large fs:18h
.text:77EE51EB                 mov     eax, [eax+30h]
.text:77EE51EE                 push    esi
.text:77EE51EF                 push    10h             ; Size
.text:77EE51F1                 push    0               ; int
.text:77EE51F3                 push    dword ptr [eax+18h] ; int
.text:77EE51F6                 call    _RtlAllocateHeap@12 ; RtlAllocateHeap(x,x,x)
.text:77EE51FB                 mov     esi, eax
.text:77EE51FD                 test    esi, esi
.text:77EE51FF                 jz      short loc_77EE5263
.text:77EE5201                 push    ebx
.text:77EE5202                 push    edi
.text:77EE5203                 push    [ebp+arg_4]
.text:77EE5206                 mov     dword ptr [esi+8], 1
.text:77EE520D                 call    _RtlEncodePointer@4 ; RtlEncodePointer(x)
.text:77EE5212                 mov     ebx, [ebp+arg_8]
.text:77EE5215                 imul    ebx, 0Ch
.text:77EE5218                 add     ebx, offset _LdrpVectorHandlerList
.text:77EE521E                 push    ebx
.text:77EE521F                 mov     [esi+0Ch], eax
.text:77EE5222                 lea     edi, [ebx+4]
.text:77EE5225                 call    _RtlAcquireSRWLockExclusive@4 ; RtlAcquireSRWLockExclusive(x)
.text:77EE522A                 cmp     [edi], edi
.text:77EE522C                 jnz     short loc_77EE5245
.text:77EE522E                 mov     ecx, large fs:18h
.text:77EE5235                 mov     eax, [ebp+arg_8]
.text:77EE5238                 mov     ecx, [ecx+30h]
.text:77EE523B                 add     eax, 2
.text:77EE523E                 add     ecx, 28h
.text:77EE5241                 lock bts [ecx], eax
.text:77EE5245
.text:77EE5245 loc_77EE5245:                           ; CODE XREF: RtlpAddVectoredHandler(x,x,x)+4Cj
.text:77EE5245                 cmp     [ebp+arg_0], 0
.text:77EE5249                 jz      loc_77ECF76D
.text:77EE524F                 mov     eax, [edi]
.text:77EE5251                 mov     [esi], eax
.text:77EE5253                 mov     [esi+4], edi
.text:77EE5256                 mov     [eax+4], esi
.text:77EE5259                 mov     [edi], esi
.text:77EE525B
.text:77EE525B loc_77EE525B:                           ; CODE XREF:RtlpAddVectoredHandler(x,x,x)-15A66j
.text:77EE525B                 push    ebx
.text:77EE525C                 call    _RtlReleaseSRWLockExclusive@4 ; RtlReleaseSRWLockExclusive(x)
.text:77EE5261                 pop     edi
.text:77EE5262                 pop     ebx
.text:77EE5263
.text:77EE5263 loc_77EE5263:                           ; CODE XREF: RtlpAddVectoredHandler(x,x,x)+1Fj
.text:77EE5263                 mov     eax, esi
.text:77EE5265                 pop     esi
.text:77EE5266                 pop     ebp
.text:77EE5267                 retn    0Ch
.text:77EE5267 _RtlpAddVectoredHandler@12 endp
.text:77EE5267

经过分析VEH链表是下面这个样子的

typedef struct _VECTORED_LIST//表链结构
{
        _VECTORED_LIST* pNext;//表链的向后指针
        _VECTORED_LIST* pPrevious;        //表链的向前指针
        DWORD dwMark;//一个有效标记,
        PVECTORED_EXCEPTION_HANDLER VectoredFunction;//加密后的异常处理函数指针

}VECTORED_LIST ,*PVECTORED_LIST;

typedef struct _VECTORED_LIST_ENTR//表链入口
{
        DWORD dwUnknown;//没弄明白是干啥的
        PVECTORED_LIST Head;//记录了VECTORED_LIST表链的第一个
        PVECTORED_LIST Tail;        //记录了VECTORED_LIST表链的最后一个

}VECTORED_LIST_ENTR,*PVECTORED_LIST_ENTR;

VECTORED_LIST_ENTR结构是表链的一个入口,所有的表链都挂载这个入口上,真正的表链结构是VECTORED_LIST

下面再来看RtlpAddVectoredHandler函数,RtlpAddVectoredHandler逆成C是下面的样子,这才是正主。

PVOID WINAPI RtlpAddVectoredHandler(
        _In_  ULONG FirstHandler,
        _In_  PVECTORED_EXCEPTION_HANDLER VectoredHandler,
        _In_  ULONG Key
        )
{
        PPEB pPeb=0;
        __asm
        {
                //取得PEB地址
                mov eax,fs:[0x18]
                mov eax,[eax+0x30]
                mov pPeb,eax
        }
        //申请内存
        PVECTORED_LIST vl=RtlAllocateHeap(pPeb->DefaultHeap,0,sizeof(VECTORED_LIST));

        if (vl==0)
        {
                return 0;
        }
        vl->dwMark=1;
        //加密指针,把参数VectoredHandler加密
        DWORD dwEncodePointer=RtlEncodePointer(VectoredHandler);

        //LdrpActiveThreadCount是全局变量
        PVECTORED_LIST_ENTR pVectordListEntr=LdrpActiveThreadCount;

        //根据key选择挂在哪一个链上,key==0的时候所挂载的链上的函数,是从RtlAddVectoredExceptionHandler来的,这一条链上是要在SEH执行前执行的       
        pVectordListEntr=&pVectordListEntr[Key];

        //Slim读写锁
        RtlAcquireSRWLockExclusive(pVectordListEntr->Head);

        //看看链表是否为空,自己指向自己就说明链表为空
        if (pVectordListEntr->Head==(PVECTORED_LIST)&pVectordListEntr->Head)
        {
                //标志位,很重要,如果不设置这位,将不会检测VEH链
                pPeb->EnvironmentUpdateCount|=(0x1<<(Key+2));

        }
        if (FirstHandler==0)
        {
                //放在链表的后面
                vl->pNext=(PVECTORED_LIST)pVectordListEntr;
                vl->pPrevious=pVectordListEntr->Tail;
                pVectordListEntr->Tail->pNext=vl;
                pVectordListEntr->Tail=vl;

        }
        else
        {
                //放在链表前面
                vl->pNext=pVectordListEntr->Head;
                vl->pPrevious=(PVECTORED_LIST)pVectordListEntr;
                pVectordListEntr->Head->pPrevious=vl;
                pVectordListEntr->Head=vl;
        }

        RtlReleaseSRWLockExclusive(pVectordListEntr->Head);

        return vl;
}
从上面的代码可以看出VEH的地址是存储在LdrpActiveThreadCount这个全局变量里的,而VEH有两个表链入口,表链入口0,和链表入口1,
表链入口0所挂载的异常处理函数,是函数AddVectoredExceptionHandler挂载上去的,换句话说,表链入口0所挂载的函数是要在SEH异常之前执行的。
而链表入口1所挂载的异常处理函数,是通过AddVectoredContinueHandler挂上去的,也就是说,表链入口1所挂载的函数是要在SEH异常之后执行的。
AddVectoredContinueHandler和AddVectoredExceptionHandler的代码上的差别,上面有提到,这里不在说了。

进阶篇:

如果要替换修改VEH异常处理函数可以如下操作



卸载VEH异常处理函数可以这么做



让VEH失效的话可以这么做



下面的附件里包含了文中的所有代码资源

VEH分析.zip


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

上传的附件:
收藏
免费 10
支持
分享
最新回复 (39)
雪    币: 44153
活跃值: (20200)
能力值: (RANK:350 )
在线值:
发帖
回帖
粉丝
2
恭喜你!有精华文章就可以直接转为正式会员。
2013-3-22 18:29
0
雪    币: 190
活跃值: (40)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
3
牛掰啊,顶精华文章
2013-3-22 19:08
0
雪    币: 257
活跃值: (67)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
4
很不错的文章,支持一下
2013-3-22 20:13
0
雪    币: 186
活跃值: (111)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
精华文章  学习+学习
2013-3-22 20:26
0
雪    币: 95901
活跃值: (200549)
能力值: (RANK:10 )
在线值:
发帖
回帖
粉丝
6
Thanks for you.
2013-3-22 21:29
0
雪    币: 114
活跃值: (180)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
很不错,支持楼主。
2013-3-22 22:38
0
雪    币: 102
活跃值: (14)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
谢谢楼主,先顶后看。
2013-3-22 23:36
0
雪    币: 458
活跃值: (306)
能力值: ( LV12,RANK:400 )
在线值:
发帖
回帖
粉丝
9
正好要学习这个,感谢 楼主。。
2013-3-23 00:12
0
雪    币: 125
活跃值: (21)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
数据结构,本子没电了,马克明天看
2013-3-23 00:39
0
雪    币: 341
活跃值: (138)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
11
前排。。。。。。。
2013-3-23 09:45
0
雪    币: 793
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
Good,Thanks for share!
2013-3-23 10:57
0
雪    币: 707
活跃值: (1301)
能力值: ( LV9,RANK:190 )
在线值:
发帖
回帖
粉丝
13
支持楼主,学习了
2013-3-23 18:11
0
雪    币: 80
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
这么久才发~~~~~~
2013-3-24 12:00
0
雪    币: 135
活跃值: (63)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
15
mark一下,看看怎么分析的
2013-3-25 21:32
0
雪    币: 220
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
mark下,正需要了解veh~~~~~
2013-3-26 08:44
0
雪    币: 208
活跃值: (40)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
17
先收藏,明天再仔细拜读。
2013-3-26 22:40
0
雪    币: 213
活跃值: (147)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
18
不错,学习。
2013-4-22 18:53
0
雪    币: 722
活跃值: (535)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
19
嗯。说得很详细啊。在网上找的资料都木有这么细了。
2013-4-22 22:34
0
雪    币: 29
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
20
学习啊。这里面的流程好复杂。还有如何在OD里面断在处理函数入口? bp貌似不好使
2013-12-5 09:27
0
雪    币: 29
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
21
如何用OD调试VEH的处理函数呢?
2013-12-5 10:01
0
雪    币: 77
活跃值: (48)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
22
mark
2014-1-17 09:28
0
雪    币: 42
活跃值: (26)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
23
记一下   以后有需要再看
2014-1-17 14:14
0
雪    币: 630
活跃值: (570)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
24
mark  有点深度,慢慢学
2014-1-20 16:24
0
雪    币: 7048
活跃值: (3522)
能力值: ( LV12,RANK:340 )
在线值:
发帖
回帖
粉丝
25
十分有用~突然发现一点,LZ分析的VEH的系统应该是>=Vista的,在XP上不存在AddVectoredContinueHandler这个函数的。
2014-2-26 14:30
0
游客
登录 | 注册 方可回帖
返回
//