再探堆栈欺骗之动态欺骗
字数 1468 2025-08-03 16:48:23

动态堆栈欺骗技术详解

1. 概述

堆栈欺骗(Stack Spoofing)是一种反检测技术,主要用于规避EDR/AV产品的堆栈回溯检测机制。本文重点介绍动态堆栈欺骗技术,即在任意函数调用时主动伪造调用堆栈的技术。

2. 基础知识

2.1 堆栈帧结构

在x64架构下,典型的堆栈帧包含以下部分:

  • 返回地址
  • 保存的非易失性寄存器
  • 局部变量空间
  • 参数空间

2.2 调用约定

x64调用约定关键点:

  • 前4个参数通过RCX、RDX、R8、R9传递
  • 额外参数通过堆栈传递
  • RAX、RCX、RDX、R8、R9、R10、R11为易失性寄存器
  • RBX、RBP、RDI、RSI、RSP、R12-R15为非易失性寄存器

3. 手动堆栈欺骗

3.1 准备工作

  1. 确定目标函数的栈帧大小(如sub rsp, 0x78
  2. 计算需要伪造的帧数(通常2-3帧)
  3. 识别常见线程起始帧(如RtlUserThreadStart+0x28

3.2 实施步骤

  1. 定位当前栈底
  2. 向下移动栈指针(如0x78字节)
  3. 伪造第一帧(写入伪造的返回地址)
  4. 重复步骤2-3伪造第二帧
  5. 验证堆栈伪造效果(如使用Process Hacker查看)

4. LoudSunRun项目分析

4.1 项目特点

  • 基于SilentMoonwalk项目的简化实现
  • 支持直接调用和间接系统调用
  • 支持多参数传递
  • 代码量较小便于学习

4.2 关键函数

4.2.1 CalculateFunctionStackSizeWrapper

计算目标函数的栈帧大小:

  • 解析UNWIND_INFO结构
  • 计算栈空间需求
  • 考虑异常处理等特殊情况

4.2.2 Spoof函数

核心欺骗函数,参数结构:
1-4: 目标函数的前4个参数
5: 欺骗上下文结构体
6: 目标函数地址
7: 额外参数数量

4.3 欺骗上下文结构体

typedef struct _SPOOF_CONTEXT {
    PCONTEXT OriginalContext;  // 原始上下文
    DWORD SSN;                 // 系统调用号(间接调用时使用)
    PVOID FakeReturnAddress1;  // 伪造返回地址1
    PVOID FakeReturnAddress2;  // 伪造返回地址2
    PVOID FakeReturnAddress3;  // 伪造返回地址3
    PVOID JmpGadget;           // JMP [RBX]指令地址
    PVOID FixupAddress;        // 修复函数地址
} SPOOF_CONTEXT, *PSPOOF_CONTEXT;

5. 技术实现细节

5.1 准备阶段

  1. 保存原始寄存器状态
  2. 设置目标函数地址
  3. 处理额外参数(如有)

5.2 堆栈伪造

  1. 分配伪造堆栈空间(通常0x200字节)
  2. 压入终止标记(push 0)
  3. 构建伪造的调用帧:
    • 计算每帧的RSP偏移
    • 写入伪造的返回地址
    • 重复构建多帧

5.3 跳转准备

  1. 设置RBX寄存器指向修复函数
  2. 准备系统调用号(间接调用时)
  3. 跳转到目标函数

5.4 返回处理

  1. 通过JMP [RBX]跳转到修复函数
  2. 恢复原始堆栈状态
  3. 恢复保存的寄存器
  4. 返回到原始调用点

6. 多参数处理

对于超过4个参数的函数调用:

  1. 计算额外参数在堆栈上的位置
  2. 确定伪造堆栈中的参数偏移:
    • 基础偏移 = 伪造堆栈大小 + 终止标记 + 伪造帧大小
    • 每个参数偏移增加8字节
  3. 将额外参数复制到计算出的位置

7. 间接系统调用实现

  1. 将系统调用号存入RAX
  2. 跳转到syscall指令地址
  3. 使用直接找到的syscall指令地址或动态查找

8. 防御检测方法

检测堆栈欺骗的可能方法:

  1. 检查返回地址前的指令是否为CALL指令
  2. 验证调用帧的连续性
  3. 检查堆栈指针的合理性
  4. 分析UNWIND_INFO的一致性

9. 参考资源

  1. x64 Deep Dive
  2. Windows x64调用约定
  3. SilentMoonwalk项目
  4. Unwind Info解析

10. 总结

动态堆栈欺骗技术通过主动伪造调用堆栈,有效规避了EDR/AV的堆栈回溯检测。关键技术点包括:

  • 精确计算栈帧大小
  • 合理构建伪造调用帧
  • 正确处理参数传递
  • 完善的上下文保存与恢复机制
  • 间接系统调用的无缝集成

理解这些技术不仅有助于攻击技术的开发,也能为防御方案的构建提供思路。

动态堆栈欺骗技术详解 1. 概述 堆栈欺骗(Stack Spoofing)是一种反检测技术,主要用于规避EDR/AV产品的堆栈回溯检测机制。本文重点介绍动态堆栈欺骗技术,即在任意函数调用时主动伪造调用堆栈的技术。 2. 基础知识 2.1 堆栈帧结构 在x64架构下,典型的堆栈帧包含以下部分: 返回地址 保存的非易失性寄存器 局部变量空间 参数空间 2.2 调用约定 x64调用约定关键点: 前4个参数通过RCX、RDX、R8、R9传递 额外参数通过堆栈传递 RAX、RCX、RDX、R8、R9、R10、R11为易失性寄存器 RBX、RBP、RDI、RSI、RSP、R12-R15为非易失性寄存器 3. 手动堆栈欺骗 3.1 准备工作 确定目标函数的栈帧大小(如 sub rsp, 0x78 ) 计算需要伪造的帧数(通常2-3帧) 识别常见线程起始帧(如 RtlUserThreadStart+0x28 ) 3.2 实施步骤 定位当前栈底 向下移动栈指针(如0x78字节) 伪造第一帧(写入伪造的返回地址) 重复步骤2-3伪造第二帧 验证堆栈伪造效果(如使用Process Hacker查看) 4. LoudSunRun项目分析 4.1 项目特点 基于SilentMoonwalk项目的简化实现 支持直接调用和间接系统调用 支持多参数传递 代码量较小便于学习 4.2 关键函数 4.2.1 CalculateFunctionStackSizeWrapper 计算目标函数的栈帧大小: 解析UNWIND_ INFO结构 计算栈空间需求 考虑异常处理等特殊情况 4.2.2 Spoof函数 核心欺骗函数,参数结构: 1-4: 目标函数的前4个参数 5: 欺骗上下文结构体 6: 目标函数地址 7: 额外参数数量 4.3 欺骗上下文结构体 5. 技术实现细节 5.1 准备阶段 保存原始寄存器状态 设置目标函数地址 处理额外参数(如有) 5.2 堆栈伪造 分配伪造堆栈空间(通常0x200字节) 压入终止标记(push 0) 构建伪造的调用帧: 计算每帧的RSP偏移 写入伪造的返回地址 重复构建多帧 5.3 跳转准备 设置RBX寄存器指向修复函数 准备系统调用号(间接调用时) 跳转到目标函数 5.4 返回处理 通过JMP [ RBX ]跳转到修复函数 恢复原始堆栈状态 恢复保存的寄存器 返回到原始调用点 6. 多参数处理 对于超过4个参数的函数调用: 计算额外参数在堆栈上的位置 确定伪造堆栈中的参数偏移: 基础偏移 = 伪造堆栈大小 + 终止标记 + 伪造帧大小 每个参数偏移增加8字节 将额外参数复制到计算出的位置 7. 间接系统调用实现 将系统调用号存入RAX 跳转到syscall指令地址 使用直接找到的syscall指令地址或动态查找 8. 防御检测方法 检测堆栈欺骗的可能方法: 检查返回地址前的指令是否为CALL指令 验证调用帧的连续性 检查堆栈指针的合理性 分析UNWIND_ INFO的一致性 9. 参考资源 x64 Deep Dive Windows x64调用约定 SilentMoonwalk项目 Unwind Info解析 10. 总结 动态堆栈欺骗技术通过主动伪造调用堆栈,有效规避了EDR/AV的堆栈回溯检测。关键技术点包括: 精确计算栈帧大小 合理构建伪造调用帧 正确处理参数传递 完善的上下文保存与恢复机制 间接系统调用的无缝集成 理解这些技术不仅有助于攻击技术的开发,也能为防御方案的构建提供思路。