再探堆栈欺骗之动态欺骗
字数 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 准备工作
- 确定目标函数的栈帧大小(如
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 欺骗上下文结构体
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 准备阶段
- 保存原始寄存器状态
- 设置目标函数地址
- 处理额外参数(如有)
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. 参考资源
10. 总结
动态堆栈欺骗技术通过主动伪造调用堆栈,有效规避了EDR/AV的堆栈回溯检测。关键技术点包括:
- 精确计算栈帧大小
- 合理构建伪造调用帧
- 正确处理参数传递
- 完善的上下文保存与恢复机制
- 间接系统调用的无缝集成
理解这些技术不仅有助于攻击技术的开发,也能为防御方案的构建提供思路。