WindowsVEH介绍

admin 2026-02-02 00:41:10 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 文档介绍Windows向量化异常处理(VEH)机制,其具有进程全局性和介入时机早的特点,优先于传统SEH执行。文章详细讲解了注册与移除VEH的API函数、异常处理函数原形及返回值含义,并通过C++代码示例演示了如何捕获除零与内存访问异常。此外,还探讨了VEH在无痕HOOK等高级场景中的应用潜力。 综合评分: 88 文章分类: 二进制安全,逆向分析,免杀


cover_image

Windows VEH 介绍

原创

MyStackTrace MyStackTrace

MyStackTrace

2026年1月22日 23:29 北京

Windows 上的 VEH 全称是 Vectored Exception Handling,即向量化异常处理,它是 Windows 系统提供的一种全局的异常处理机制,允许程序在发生特定异常时执行自定义的处理逻辑。

当程序在运行中发生异常(如除零、访问违规内存)时,CPU 会捕获该异常并交由 Windows 内核处理,内核然后将异常信息传递给用户态的异常分发函数,异常分发函数会按照特定顺序寻找能处理该异常的代码 :

  1. 首先询问调试器(如果进程正在被调试)。

  2. 然后按顺序调用所有已注册的 VEH 处理函数。

  3. 如果 VEH 均未处理,最后才会轮到线程相关的结构化异常处理(Structured Exception Handling,SEH)。

所以,VEH 和传统的 SEH 相比有两个显著的特点:

  • 全局性:与线程相关的结构化异常处理(SEH)不同,VEH 是进程级别的,这意味着通过 VEH 注册的异常处理函数可以对整个进程内发生的特定异常做出响应,而不依赖于单个线程的调用栈。
  • 介入时机早:当程序发生异常时,系统的异常分发器会按照一个特定的顺序来寻找异常处理程序。通常,VEH 会先于传统的 SEH 被调用(除非进程正在被调试,调试器会最先获得机会)。在所有已注册的 VEH 处理函数中,可以通过注册参数指定其被调用的先后顺序。

VEH 的异常处理函数有固定的原型,它接收一个 EXCEPTION_POINTERS 结构体指针作为参数,该结构体包含了详细的异常记录和发生异常时的线程上下文(Context)信息。

我们可以通过函数 AddVectoredExceptionHandler 注册 VEH 异常处理函数,通过函数 RemoveVectoredExceptionHandler 取消已注册的 VEH 异常处理函数 。

  • 参数 First:指定处理函数的调用顺序。如果为非零值,则将该处理函数作为第一个处理函数;如果为零,则作为最后一个处理函数。
  • Handler:指向异常处理函数的指针(PVECTORED_EXCEPTION_HANDLER)。
  • 返回值:返回一个句柄,用来取消已经注册成功的 Hander。

  • 参数 Handle:使用 AddVectoredExceptionHandler 注册 VEH 异常处理函数成功时返回的句柄。

下面是个简单的例子程序,我在程序中故意执行了一个除零操作和一个访问空指针的操作,除零操作会触发 Divide By Zero Exception,访问空指针会触发 Access Violation Exception,通常情况我们的程序触发了这些异常就会立刻崩溃,但是下面的程序使用了 try-except 语句块把会触发异常的代码给圈了起来,并且又注册了 VEH 异常处理函数,因此该程序在经历两次异常处理之后仍然不会崩溃。我们可以根据 VEH 异常处理函数的 EXCEPTION_POINTERS 参数中的信息判断出来这是个什么类型的异常,并且还能够从中获取到该异常相关的信息,比如异常发生的地址,上下文寄存器等。

#include&nbsp;<Windows.h>#include&nbsp;<stdio.h>
LONG WINAPI&nbsp;VectoredExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo){&nbsp; &nbsp;&nbsp;switch&nbsp;(ExceptionInfo->ExceptionRecord->ExceptionCode)&nbsp; &nbsp; {&nbsp; &nbsp;&nbsp;case&nbsp;EXCEPTION_ACCESS_VIOLATION:&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;printf("Access violation exception caught at address: 0x%p\n",&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ExceptionInfo->ExceptionRecord->ExceptionAddress);&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;printf("Attempt to %s at address: 0x%p\n",&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ExceptionInfo->ExceptionRecord->ExceptionInformation[0] ?&nbsp;"write"&nbsp;:&nbsp;"read",&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (PVOID)ExceptionInfo->ExceptionRecord->ExceptionInformation[1]);&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;EXCEPTION_CONTINUE_SEARCH;
&nbsp; &nbsp;&nbsp;case&nbsp;EXCEPTION_INT_DIVIDE_BY_ZERO:&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;printf("Integer divide by zero exception caught at address: 0x%p\n",&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ExceptionInfo->ExceptionRecord->ExceptionAddress);&nbsp; &nbsp; &nbsp; &nbsp; ExceptionInfo->ContextRecord->Rax =&nbsp;0;&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;EXCEPTION_CONTINUE_SEARCH;
&nbsp; &nbsp;&nbsp;case&nbsp;EXCEPTION_STACK_OVERFLOW:&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;printf("Stack overflow exception caught\n");&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;EXCEPTION_CONTINUE_SEARCH;
&nbsp; &nbsp;&nbsp;default:&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;printf("Unhandled exception code: 0x%08X\n",&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ExceptionInfo->ExceptionRecord->ExceptionCode);&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;EXCEPTION_CONTINUE_SEARCH;&nbsp; &nbsp; }}
int&nbsp;CauseDividedByZeroException(int&nbsp;a){&nbsp; &nbsp;&nbsp;return&nbsp;a /&nbsp;0;&nbsp;// This will cause a divide by zero exception}
void&nbsp;CauseAccessViolationException(){&nbsp; &nbsp;&nbsp;int&nbsp;*p =&nbsp;NULL;&nbsp; &nbsp; *p =&nbsp;1;&nbsp;// This will cause an access violation exception}
int&nbsp;main(int&nbsp;argc,&nbsp;char&nbsp;*argv[]){&nbsp; &nbsp; PVOID handlerHandle =&nbsp;AddVectoredExceptionHandler(1, VectoredExceptionHandler);&nbsp; &nbsp;&nbsp;if&nbsp;(handlerHandle ==&nbsp;NULL)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;printf("Failed to install vectored exception handler. Error: %lu\n",&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;GetLastError());&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;1;&nbsp; &nbsp; }
&nbsp; &nbsp;&nbsp;printf("Vectored exception handler installed successfully\n");
&nbsp; &nbsp; __try&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;printf("%d\n",&nbsp;CauseDividedByZeroException(10));&nbsp; &nbsp; }&nbsp; &nbsp; __except(EXCEPTION_EXECUTE_HANDLER)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;printf("Divide by zero exception handled via __except block\n");&nbsp; &nbsp; }
&nbsp; &nbsp; __try&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;CauseAccessViolationException();&nbsp; &nbsp; }&nbsp; &nbsp; __except(EXCEPTION_EXECUTE_HANDLER)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;printf("Access violation handled via __except block\n");&nbsp; &nbsp; }
&nbsp; &nbsp;&nbsp;printf("This program exit successfully\n");
&nbsp; &nbsp;&nbsp;return&nbsp;0;}

下面是这个程序的运行效果,可以看到当程序执行除零的代码和访问空指针的代码时,程序都会跳转到我们注册的 VEH 处理函数(VectoredExceptionHandler)中进行对应的处理,最终程序还是正常退出了。

在上面的 VEH 异常处理函数中,我们的返回值都是 EXCEPTION_CONTINUE_SEARCH,表示当前 VEH 处理程序不处理此异常,系统应继续调用 VEH 链中的下一个处理程序(如果还有的话),如果所有 VEH 处理程序都返回此值,则系统会继续按正常流程处理异常(即进入 SEH 链)。此外还有两个异常处理函数的返回值 EXCEPTION_EXECUTE_HANDLER 和 EXCEPTION_CONTINUE_EXECUTION。EXCEPTION_EXECUTE_HANDLER 表示当前 VEH 处理程序已经处理了异常,并且系统应该停止搜索其他处理程序(包括 VEH 和 SEH),然后,系统会认为异常已处理,并继续执行原程序流程,但不会回到异常发生点。EXCEPTION_CONTINUE_EXECUTION 表示异常已被当前 VEH 处理程序处理,并且系统应该从异常发生的位置继续执行,处理程序必须确保导致异常的条件已经得到修正,否则会再次触发异常,比如上面这个例子,就不能返回 EXCEPTION_CONTINUE_EXECUTION,因为我们的 VEH 异常处理函数并没有修复异常,仅仅是打印了一些信息而已,如果返回 EXCEPTION_CONTINUE_EXECUTION 会导致这个程序不停的触发异常,陷入死循环中。

VEH 的强大之处在于其全局性和介入时机早,因此被广泛应用于一些特定领域,比如实现无痕 HOOK,这是 VEH 一个非常经典和强大的应用,通过在目标函数入口插入一个断点指令(如 int 3),当函数被调用触发断点异常时,VEH 处理函数会捕获这个异常。在处理函数中,可以执行自定义代码(如记录日志、修改参数等),然后修改线程上下文(如 EIP/RIP 寄存器)使其跳转到钩子函数或直接返回,从而实现拦截和监控,而无需像传统 inline hook 那样修改大量原始代码。这些有意思的应用我们后面可以来尝试一下😁。


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:MyStackTrace MyStackTrace MyStackTrace《Windows VEH 介绍》

WindowsVEH介绍 网络安全文章

WindowsVEH介绍

文章总结: 文档介绍Windows向量化异常处理(VEH)机制,其具有进程全局性和介入时机早的特点,优先于传统SEH执行。文章详细讲解了注册与移除VEH的API
评论:0   参与:  0