Windows下SafeSEH保护机制详解及其绕过方式
字数 1497 2025-08-23 18:31:25

Windows下SafeSEH保护机制详解及其绕过方式

一、SafeSEH保护机制概述

SafeSEH(Safe Structured Exception Handling)是微软针对SEH攻击提出的一种保护机制,旨在防止攻击者通过覆盖异常处理函数指针来执行恶意代码。

1. SafeSEH工作原理

  • 安全SEH表:当程序开启SafeSEH保护后,编译器在编译期间提取所有合法的异常处理函数地址,编入安全SEH表并放入程序映像中。
  • 验证机制:程序调用异常处理函数时,系统会检查函数地址是否位于安全SEH表中。

2. 操作系统在SafeSEH中的作用

异常处理通过RtlDispatchException()函数实现,SafeSEH验证流程如下:

  1. 检查异常处理链是否位于当前程序栈中
  2. 检查异常处理函数指针是否指向当前栈
  3. 通过RtlIsValidHandler()函数进行有效性验证

3. RtlIsValidHandler()验证流程

  1. 检查异常处理函数地址是否位于当前加载模块的内存空间
  2. 检查程序是否设置了IMAGE_DLLCHARACTERISTICS_NO_SEH标识(设置则忽略异常)
  3. 检查程序是否包含安全SEH表,并进行匹配验证
  4. 检查异常处理函数地址是否位于不可执行页(涉及DEP保护)

二、SafeSEH绕过方式分析

1. 允许异常处理函数执行的情况

  1. 异常处理函数位于加载模块之外,且未开启DEP
  2. 异常处理函数位于加载模块内,但模块未开启SafeSEH且不是IL(Intermediate Language)
  3. 异常处理函数位于加载模块内,模块启用SafeSEH且函数指针位于安全SEH表中

2. 主要绕过思路

  1. 利用加载模块之外的空间:使用模块外的短指令作为跳板
  2. 利用未启用SafeSEH的模块:使用这些模块中的指令作为跳板
  3. 攻击安全SEH表
    • 清空安全SEH表制造未启用保护的假象
    • 将跳板注册到安全SEH表中(难度较大)
  4. 利用SEH的终极特权:异常处理指针指向堆区时,无论验证是否通过都会执行

三、SafeSEH绕过实战

方法1:从堆中绕过SafeSEH

原理:利用SafeSEH对堆区异常处理指针的特权(不验证直接执行)

示例代码

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

void test(char* szBuffer) {
    char str[200]{ 0 };
    strcpy(str, szBuffer);
    int a = 0;
    int b = 1 / a; // 触发除零异常
}

int main() {
    char* Buffer = (char*)malloc(500);
    _asm int 3; // 调试断点
    HANDLE hFile = CreateFileA("payload.txt", GENERIC_READ, NULL, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    DWORD dwReadSize = 0;
    char* MyPayload = (char*)malloc(500);
    memset(MyPayload, 0, 500);
    ReadFile(hFile, MyPayload, 500, &dwReadSize, NULL);
    test(MyPayload);
    return 0;
}

Payload结构

  1. Shellcode
  2. 填充指令(\x90)
  3. 堆中payload的起始地址

方法2:利用未启用SafeSEH的模块

原理:将异常处理指针指向未启用SafeSEH模块中的指令

步骤

  1. 创建未启用SafeSEH的DLL,包含跳板指令
// dllmain.cpp
#include "pch.h"
void jump() {
    __asm {
        pop eax
        pop eax
        retn
    }
}
  1. 在漏洞程序中加载该DLL并触发溢出

Payload结构

  1. 填充nop指令至SEH偏移处
  2. 跳板指令地址(指向DLL中的指令)
  3. 少量nop指令
  4. Shellcode

方法3:利用加载模块之外的地址

原理:类型为Map的映射文件不受SafeSEH验证

方法

  1. 在Map类型的映射文件中寻找跳板指令(gadgets)
  2. 构造payload使异常处理指针指向这些指令
  3. 跳板指令跳转到Shellcode执行

四、防御建议

  1. 启用DEP(Data Execution Prevention)保护
  2. 启用ASLR(Address Space Layout Randomization)
  3. 结合使用GS、SafeSEH等多种保护机制
  4. 避免使用不安全的函数如strcpy等
  5. 对输入数据进行严格验证

五、总结

SafeSEH虽然提供了对SEH的保护,但仍存在多种绕过方式。安全防护需要多层防御体系,单一保护机制难以应对所有攻击场景。理解这些绕过技术有助于开发更安全的软件和设计更完善的防护机制。

Windows下SafeSEH保护机制详解及其绕过方式 一、SafeSEH保护机制概述 SafeSEH(Safe Structured Exception Handling)是微软针对SEH攻击提出的一种保护机制,旨在防止攻击者通过覆盖异常处理函数指针来执行恶意代码。 1. SafeSEH工作原理 安全SEH表 :当程序开启SafeSEH保护后,编译器在编译期间提取所有合法的异常处理函数地址,编入安全SEH表并放入程序映像中。 验证机制 :程序调用异常处理函数时,系统会检查函数地址是否位于安全SEH表中。 2. 操作系统在SafeSEH中的作用 异常处理通过 RtlDispatchException() 函数实现,SafeSEH验证流程如下: 检查异常处理链是否位于当前程序栈中 检查异常处理函数指针是否指向当前栈 通过 RtlIsValidHandler() 函数进行有效性验证 3. RtlIsValidHandler()验证流程 检查异常处理函数地址是否位于当前加载模块的内存空间 检查程序是否设置了 IMAGE_DLLCHARACTERISTICS_NO_SEH 标识(设置则忽略异常) 检查程序是否包含安全SEH表,并进行匹配验证 检查异常处理函数地址是否位于不可执行页(涉及DEP保护) 二、SafeSEH绕过方式分析 1. 允许异常处理函数执行的情况 异常处理函数位于加载模块之外,且未开启DEP 异常处理函数位于加载模块内,但模块未开启SafeSEH且不是IL(Intermediate Language) 异常处理函数位于加载模块内,模块启用SafeSEH且函数指针位于安全SEH表中 2. 主要绕过思路 利用加载模块之外的空间 :使用模块外的短指令作为跳板 利用未启用SafeSEH的模块 :使用这些模块中的指令作为跳板 攻击安全SEH表 : 清空安全SEH表制造未启用保护的假象 将跳板注册到安全SEH表中(难度较大) 利用SEH的终极特权 :异常处理指针指向堆区时,无论验证是否通过都会执行 三、SafeSEH绕过实战 方法1:从堆中绕过SafeSEH 原理 :利用SafeSEH对堆区异常处理指针的特权(不验证直接执行) 示例代码 : Payload结构 : Shellcode 填充指令(\x90) 堆中payload的起始地址 方法2:利用未启用SafeSEH的模块 原理 :将异常处理指针指向未启用SafeSEH模块中的指令 步骤 : 创建未启用SafeSEH的DLL,包含跳板指令 在漏洞程序中加载该DLL并触发溢出 Payload结构 : 填充nop指令至SEH偏移处 跳板指令地址(指向DLL中的指令) 少量nop指令 Shellcode 方法3:利用加载模块之外的地址 原理 :类型为Map的映射文件不受SafeSEH验证 方法 : 在Map类型的映射文件中寻找跳板指令(gadgets) 构造payload使异常处理指针指向这些指令 跳板指令跳转到Shellcode执行 四、防御建议 启用DEP(Data Execution Prevention)保护 启用ASLR(Address Space Layout Randomization) 结合使用GS、SafeSEH等多种保护机制 避免使用不安全的函数如strcpy等 对输入数据进行严格验证 五、总结 SafeSEH虽然提供了对SEH的保护,但仍存在多种绕过方式。安全防护需要多层防御体系,单一保护机制难以应对所有攻击场景。理解这些绕过技术有助于开发更安全的软件和设计更完善的防护机制。