使用VEH进行内存对抗
字数 1894 2025-08-09 13:33:40

Windows异常处理机制与VEH内存对抗技术

一、Windows异常处理机制概述

Windows操作系统提供了三种主要的异常处理机制:

  1. VEH (Vectored Exception Handling) - 向量化异常处理
  2. SEH (Structured Exception Handling) - 结构化异常处理
  3. C++ EH (C++ Exception Handling) - C++异常处理

1.1 异常处理流程

Windows异常处理的基本流程如下:

  1. 首先由CPU捕获异常
  2. 内核处理部分异常(如页面错误)
  3. 用户态异常分发流程:
    • 首先调用VEH处理程序
    • 然后遍历SEH链
    • 最后调用未处理异常过滤器

二、向量化异常处理(VEH)

2.1 VEH基本概念

VEH是Windows引入的一种全局异常处理机制,具有以下特点:

  • 通过AddVectoredExceptionHandler函数注册
  • 处理程序以链表形式存储
  • 执行顺序先于SEH
  • 可以处理所有线程的异常

2.2 VEH相关API

// 添加VEH处理程序
PVOID AddVectoredExceptionHandler(
  ULONG First,  // 0表示添加到链表尾部,1表示添加到头部
  PVECTORED_EXCEPTION_HANDLER Handler
);

// 移除VEH处理程序
ULONG RemoveVectoredExceptionHandler(PVOID Handle);

// VEH处理函数原型
LONG CALLBACK VectoredExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo);

2.3 VEH处理函数参数

VEH处理函数接收一个EXCEPTION_POINTERS结构指针:

typedef struct _EXCEPTION_POINTERS {
  PEXCEPTION_RECORD ExceptionRecord;  // 异常记录
  PCONTEXT ContextRecord;             // 线程上下文
} EXCEPTION_POINTERS, *PEXCEPTION_POINTERS;

EXCEPTION_RECORD包含异常代码、地址等信息,CONTEXT结构包含寄存器状态。

三、结构化异常处理(SEH)

3.1 SEH基本概念

SEH是Windows平台特有的异常处理机制:

  • 基于栈的异常处理
  • 使用__try__except__finally关键字
  • 每个线程有自己的SEH链
  • 处理顺序后于VEH

3.2 SEH链结构

SEH链是一个链表结构,每个节点包含:

  • 处理函数指针
  • 指向下一个节点的指针
  • 安全cookie等数据

3.3 SEH与编译器

编译器会将__try/__except块转换为SEH结构:

// 源代码
__try {
  // 可能引发异常的代码
} __except(filter_expression) {
  // 异常处理代码
}

// 编译器生成的伪代码
struct _EXCEPTION_REGISTRATION_RECORD seh;
seh.Handler = exception_handler;
seh.Next = fs:[0];  // 添加到SEH链头部
fs:[0] = &seh;

四、C++异常处理

C++异常处理基于SEH实现,但有自己的特点:

  • 使用trycatchthrow关键字
  • 可以处理任意类型的异常对象
  • 需要运行时支持(如MSVCRT)

五、VEH在内存对抗中的应用

5.1 内存保护技术

VEH可用于实现以下内存保护技术:

  1. 内存断点:通过设置页面保护属性,在访问时触发异常
  2. 代码校验:检查关键代码是否被修改
  3. 反调试:检测调试器的内存操作

5.2 VEH内存断点实现

实现内存断点的基本步骤:

  1. 使用VirtualProtect修改内存页属性为PAGE_GUARDPAGE_NOACCESS
  2. 注册VEH处理程序捕获访问异常
  3. 在处理程序中检查访问合法性
  4. 恢复原始内存属性并继续执行

示例代码片段:

// 设置内存断点
DWORD oldProtect;
VirtualProtect(targetAddr, size, PAGE_NOACCESS | PAGE_GUARD, &oldProtect);

// VEH处理程序
LONG CALLBACK VectoredHandler(PEXCEPTION_POINTERS ExceptionInfo) {
  if (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) {
    // 检查访问地址是否合法
    if (ExceptionInfo->ExceptionRecord->ExceptionInformation[1] == targetAddr) {
      // 处理非法访问
      // ...
      // 恢复执行
      ExceptionInfo->ContextRecord->Eip = (DWORD)safe_continue_addr;
      return EXCEPTION_CONTINUE_EXECUTION;
    }
  }
  return EXCEPTION_CONTINUE_SEARCH;
}

5.3 反内存补丁技术

利用VEH防止内存被修改:

  1. 注册VEH处理程序捕获EXCEPTION_ACCESS_VIOLATION
  2. 在关键代码区域设置写保护
  3. 当检测到非法写入时,恢复原始数据并记录攻击

5.4 VEH与反调试

VEH可用于检测调试器的常见技术:

  1. 硬件断点检测:检查CONTEXT结构中的调试寄存器
  2. 内存断点检测:检查页面保护属性的异常修改
  3. 单步执行检测:捕获EXCEPTION_SINGLE_STEP异常

六、VEH高级应用技巧

6.1 VEH链操作

由于VEH处理程序以链表形式存储,可以:

  1. 枚举所有已注册的VEH处理程序
  2. 修改或替换特定处理程序
  3. 实现VEH处理程序的动态加载/卸载

6.2 VEH与SEH的交互

VEH和SEH可以协同工作:

  • VEH处理程序可以返回EXCEPTION_CONTINUE_SEARCH将异常传递给SEH
  • 在VEH中修改线程上下文会影响后续SEH处理
  • 可以构建多层防御机制

6.3 性能考虑

VEH处理会影响程序性能:

  • 频繁的异常触发会导致性能下降
  • 应尽量减少VEH处理程序的复杂度
  • 考虑使用条件性保护(只在必要时启用)

七、实际案例:使用VEH保护关键函数

以下是一个完整示例,展示如何使用VEH保护关键函数不被挂钩:

#include <windows.h>
#include <stdio.h>

// 要保护的关键函数
void CriticalFunction() {
  printf("This is a critical function\n");
}

// VEH处理程序
LONG CALLBACK VectoredHandler(PEXCEPTION_POINTERS ExceptionInfo) {
  if (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) {
    PVOID faultAddr = (PVOID)ExceptionInfo->ExceptionRecord->ExceptionInformation[1];
    PVOID funcAddr = (PVOID)CriticalFunction;
    
    // 检查是否是对关键函数的写入操作
    if (faultAddr >= funcAddr && faultAddr < (PVOID)((DWORD_PTR)funcAddr + 0x100)) {
      printf("Detected attempt to modify critical function!\n");
      
      // 恢复原始页面保护
      DWORD oldProtect;
      VirtualProtect(funcAddr, 0x100, PAGE_EXECUTE_READ, &oldProtect);
      
      return EXCEPTION_CONTINUE_EXECUTION;
    }
  }
  return EXCEPTION_CONTINUE_SEARCH;
}

int main() {
  // 添加VEH处理程序
  PVOID hHandler = AddVectoredExceptionHandler(1, VectoredHandler);
  
  // 设置关键函数区域为只读
  DWORD oldProtect;
  VirtualProtect(CriticalFunction, 0x100, PAGE_EXECUTE_READ, &oldProtect);
  
  // 测试
  CriticalFunction();
  
  // 尝试修改关键函数(应该被VEH捕获)
  __try {
    *(BYTE*)CriticalFunction = 0xC3; // RET指令
  } __except(EXCEPTION_EXECUTE_HANDLER) {
    printf("Modification attempt blocked\n");
  }
  
  // 再次调用关键函数,应该仍然正常工作
  CriticalFunction();
  
  // 清理
  RemoveVectoredExceptionHandler(hHandler);
  return 0;
}

八、总结

VEH是Windows平台强大的异常处理机制,在内存对抗中可以发挥重要作用:

  1. 防御优势

    • 先于SEH执行,可以提前拦截异常
    • 全局作用范围,保护所有线程
    • 可以访问完整线程上下文
  2. 攻击检测

    • 检测内存修改尝试
    • 发现调试器活动
    • 防止代码注入
  3. 灵活应用

    • 可以与SEH、C++ EH协同工作
    • 支持动态注册和卸载
    • 可以构建多层防御体系

通过合理使用VEH,可以显著增强应用程序的安全性,特别是在对抗内存攻击方面。然而,也需要注意性能影响和可能的兼容性问题,在实际应用中需要权衡利弊。

Windows异常处理机制与VEH内存对抗技术 一、Windows异常处理机制概述 Windows操作系统提供了三种主要的异常处理机制: VEH (Vectored Exception Handling) - 向量化异常处理 SEH (Structured Exception Handling) - 结构化异常处理 C++ EH (C++ Exception Handling) - C++异常处理 1.1 异常处理流程 Windows异常处理的基本流程如下: 首先由CPU捕获异常 内核处理部分异常(如页面错误) 用户态异常分发流程: 首先调用VEH处理程序 然后遍历SEH链 最后调用未处理异常过滤器 二、向量化异常处理(VEH) 2.1 VEH基本概念 VEH是Windows引入的一种全局异常处理机制,具有以下特点: 通过 AddVectoredExceptionHandler 函数注册 处理程序以链表形式存储 执行顺序先于SEH 可以处理所有线程的异常 2.2 VEH相关API 2.3 VEH处理函数参数 VEH处理函数接收一个 EXCEPTION_POINTERS 结构指针: EXCEPTION_RECORD 包含异常代码、地址等信息, CONTEXT 结构包含寄存器状态。 三、结构化异常处理(SEH) 3.1 SEH基本概念 SEH是Windows平台特有的异常处理机制: 基于栈的异常处理 使用 __try 、 __except 、 __finally 关键字 每个线程有自己的SEH链 处理顺序后于VEH 3.2 SEH链结构 SEH链是一个链表结构,每个节点包含: 处理函数指针 指向下一个节点的指针 安全cookie等数据 3.3 SEH与编译器 编译器会将 __try / __except 块转换为SEH结构: 四、C++异常处理 C++异常处理基于SEH实现,但有自己的特点: 使用 try 、 catch 、 throw 关键字 可以处理任意类型的异常对象 需要运行时支持(如MSVCRT) 五、VEH在内存对抗中的应用 5.1 内存保护技术 VEH可用于实现以下内存保护技术: 内存断点 :通过设置页面保护属性,在访问时触发异常 代码校验 :检查关键代码是否被修改 反调试 :检测调试器的内存操作 5.2 VEH内存断点实现 实现内存断点的基本步骤: 使用 VirtualProtect 修改内存页属性为 PAGE_GUARD 或 PAGE_NOACCESS 注册VEH处理程序捕获访问异常 在处理程序中检查访问合法性 恢复原始内存属性并继续执行 示例代码片段: 5.3 反内存补丁技术 利用VEH防止内存被修改: 注册VEH处理程序捕获 EXCEPTION_ACCESS_VIOLATION 在关键代码区域设置写保护 当检测到非法写入时,恢复原始数据并记录攻击 5.4 VEH与反调试 VEH可用于检测调试器的常见技术: 硬件断点检测 :检查 CONTEXT 结构中的调试寄存器 内存断点检测 :检查页面保护属性的异常修改 单步执行检测 :捕获 EXCEPTION_SINGLE_STEP 异常 六、VEH高级应用技巧 6.1 VEH链操作 由于VEH处理程序以链表形式存储,可以: 枚举所有已注册的VEH处理程序 修改或替换特定处理程序 实现VEH处理程序的动态加载/卸载 6.2 VEH与SEH的交互 VEH和SEH可以协同工作: VEH处理程序可以返回 EXCEPTION_CONTINUE_SEARCH 将异常传递给SEH 在VEH中修改线程上下文会影响后续SEH处理 可以构建多层防御机制 6.3 性能考虑 VEH处理会影响程序性能: 频繁的异常触发会导致性能下降 应尽量减少VEH处理程序的复杂度 考虑使用条件性保护(只在必要时启用) 七、实际案例:使用VEH保护关键函数 以下是一个完整示例,展示如何使用VEH保护关键函数不被挂钩: 八、总结 VEH是Windows平台强大的异常处理机制,在内存对抗中可以发挥重要作用: 防御优势 : 先于SEH执行,可以提前拦截异常 全局作用范围,保护所有线程 可以访问完整线程上下文 攻击检测 : 检测内存修改尝试 发现调试器活动 防止代码注入 灵活应用 : 可以与SEH、C++ EH协同工作 支持动态注册和卸载 可以构建多层防御体系 通过合理使用VEH,可以显著增强应用程序的安全性,特别是在对抗内存攻击方面。然而,也需要注意性能影响和可能的兼容性问题,在实际应用中需要权衡利弊。