主动堆栈欺骗
字数 1725 2025-08-29 22:41:01

主动堆栈欺骗技术详解

1. 核心概念

主动堆栈欺骗(Active Stack Spoofing)是一种高级的反调试和反检测技术,其核心在于通过伪造多个栈帧,使栈回溯时呈现出函数被多次调用的假象,而实际上这些调用并未真实发生。

关键特点:

  • 伪造多个栈帧结构
  • 修改RSP寄存器指向伪造的栈帧
  • 利用系统函数的固定偏移量
  • 保持堆栈平衡以避免崩溃

2. 基本原理

2.1 栈帧结构

在x64架构中,函数调用时:

  1. 调用者将返回地址压入栈中
  2. 被调用函数通常通过sub rsp, X分配栈空间
  3. 函数返回时通过add rsp, X释放空间并ret返回

2.2 伪造原理

  1. 手动构造看似合法的栈帧
  2. 将RSP指向伪造的栈帧顶部
  3. 包含伪造的返回地址链
  4. 保持堆栈平衡(分配与释放的空间一致)

3. 技术实现细节

3.1 准备工作

  1. 获取关键函数地址

    • RtlUserThreadStart及其偏移量(示例中为+0x21)
    • BaseThreadInitThunk
    • 目标函数地址(如printf
  2. 计算栈空间大小

    • 通过.pdata段的PRUNTIME_FUNCTIONUNWIND_INFO解析
    • 处理各种UWOP_*操作码计算总栈大小

3.2 关键数据结构

typedef struct _UNWIND_HISTORY_TABLE {
    ULONG Count;
    UCHAR Search;
    ULONG LowAddress;
    ULONG HighAddress;
    PRUNTIME_FUNCTION Entry[MAX_UNWIND_HISTORY_TABLE_ENTRIES];
} UNWIND_HISTORY_TABLE, *PUNWIND_HISTORY_TABLE;

3.3 栈空间计算逻辑

  1. 检查pRuntimeFunction有效性
  2. 解析UnwindData获取PUNWIND_INFO
  3. 遍历UnwindCode处理不同操作码:
    • UWOP_PUSH_NONVOL
    • UWOP_ALLOC_SMALL
    • UWOP_ALLOC_LARGE
    • UWOP_SET_FPREG
  4. 处理UNW_FLAG_CHAININFO标志的级联函数
  5. 返回总栈大小(包括8字节返回地址)

4. 具体实现步骤

4.1 跳板准备

  1. 查找jmp [rbx]指令(机器码\xFF\x23
  2. 存储跳板地址到p.trampoline

4.2 Spoof函数实现

Spoof proc
    pop rax                 ; 保存返回地址到rax
    mov rdi, [rsp+20h]      ; 获取结构体指针
    mov rsi, [rsp+28h]      ; 获取目标函数地址
    ; ... 其他实现细节
Spoof endp

4.3 参数处理

  1. 前四个参数通过rcx, rdx, r8, r9传递
  2. 其余参数通过栈传递(影子空间预留0x20字节)
  3. 多参数处理:
    • 使用r11记录已处理参数数量
    • 通过r13定位额外参数位置
    • 计算所需栈空间并调整rsp

4.4 伪造栈帧

  1. 分配200字节空间
  2. push 0截断真实返回地址
  3. 构造伪造的返回地址链:
    • RtlUserThreadStart
    • BaseThreadInitThunk
    • 跳板帧
  4. 保存真实返回地址到r12(非易失性寄存器)

4.5 执行流程

  1. 将跳板地址(jmp rbx)压入伪造栈帧顶部
  2. 执行目标函数(如printf)
  3. 函数返回时跳转到跳板地址
  4. 通过jmp rbx返回到修复代码

5. 关键点解析

5.1 返回地址处理

  • 正常call指令会压入返回地址
  • 使用jmp时需手动压入伪造返回地址
  • 通过精确控制rsp确保执行流正确返回

5.2 堆栈平衡

  • 每个伪造的栈帧必须保持分配与释放的空间一致
  • 考虑影子空间(0x20字节)的影响
  • 确保retrsp指向正确的伪造返回地址

5.3 系统调用处理

  • 直接传递syscall地址(如pNtAllocateVirtualMemory + 0x12
  • 模拟内核函数调用前的准备工作

6. 实际应用示例

6.1 LoudSunRun项目分析

  1. 获取printf地址
  2. 查找jmp [rbx]跳板
  3. 计算各函数栈大小
  4. 构造伪造调用链:
    Gadget Frame (jmp rbx)
    BaseThreadInitThunk
    RtlUserThreadStart
    

6.2 多参数处理示例

mov r13, rsp
add r13, 30h                ; 定位第七个参数
mov r14, 200h + 8           ; 基础空间 + push 0
add r14, [三个函数栈大小]    ; 添加各函数栈空间
sub r14, 20h                ; 减去影子空间
; ... 参数复制逻辑

7. 注意事项

  1. 系统版本差异:

    • 关键函数偏移量随系统版本变化
    • 需动态获取或针对特定版本调整
  2. 寄存器使用:

    • 使用非易失性寄存器(r12-r15)保存关键值
    • 易失性寄存器可能在调用中被修改
  3. 调试器兼容性:

    • 某些汇编写法在x64dbg中不合法
    • 依赖汇编器的语法容错能力

8. 总结

主动堆栈欺骗是一种高级的调用栈操纵技术,通过精心构造伪造的栈帧和精确控制执行流,可以实现:

  • 隐藏真实调用链
  • 绕过基于栈回溯的检测机制
  • 实现更隐蔽的函数调用

关键技术点在于对x64调用约定、栈帧结构和返回机制的深入理解,以及对寄存器、内存布局的精确控制。

主动堆栈欺骗技术详解 1. 核心概念 主动堆栈欺骗(Active Stack Spoofing)是一种高级的反调试和反检测技术,其核心在于通过伪造多个栈帧,使栈回溯时呈现出函数被多次调用的假象,而实际上这些调用并未真实发生。 关键特点: 伪造多个栈帧结构 修改RSP寄存器指向伪造的栈帧 利用系统函数的固定偏移量 保持堆栈平衡以避免崩溃 2. 基本原理 2.1 栈帧结构 在x64架构中,函数调用时: 调用者将返回地址压入栈中 被调用函数通常通过 sub rsp, X 分配栈空间 函数返回时通过 add rsp, X 释放空间并 ret 返回 2.2 伪造原理 手动构造看似合法的栈帧 将RSP指向伪造的栈帧顶部 包含伪造的返回地址链 保持堆栈平衡(分配与释放的空间一致) 3. 技术实现细节 3.1 准备工作 获取关键函数地址 : RtlUserThreadStart 及其偏移量(示例中为+0x21) BaseThreadInitThunk 目标函数地址(如 printf ) 计算栈空间大小 : 通过 .pdata 段的 PRUNTIME_FUNCTION 和 UNWIND_INFO 解析 处理各种 UWOP_* 操作码计算总栈大小 3.2 关键数据结构 3.3 栈空间计算逻辑 检查 pRuntimeFunction 有效性 解析 UnwindData 获取 PUNWIND_INFO 遍历 UnwindCode 处理不同操作码: UWOP_PUSH_NONVOL UWOP_ALLOC_SMALL UWOP_ALLOC_LARGE UWOP_SET_FPREG 处理 UNW_FLAG_CHAININFO 标志的级联函数 返回总栈大小(包括8字节返回地址) 4. 具体实现步骤 4.1 跳板准备 查找 jmp [rbx] 指令(机器码 \xFF\x23 ) 存储跳板地址到 p.trampoline 4.2 Spoof函数实现 4.3 参数处理 前四个参数通过 rcx, rdx, r8, r9 传递 其余参数通过栈传递(影子空间预留0x20字节) 多参数处理: 使用 r11 记录已处理参数数量 通过 r13 定位额外参数位置 计算所需栈空间并调整 rsp 4.4 伪造栈帧 分配200字节空间 push 0 截断真实返回地址 构造伪造的返回地址链: RtlUserThreadStart 帧 BaseThreadInitThunk 帧 跳板帧 保存真实返回地址到 r12 (非易失性寄存器) 4.5 执行流程 将跳板地址( jmp rbx )压入伪造栈帧顶部 执行目标函数(如 printf ) 函数返回时跳转到跳板地址 通过 jmp rbx 返回到修复代码 5. 关键点解析 5.1 返回地址处理 正常 call 指令会压入返回地址 使用 jmp 时需手动压入伪造返回地址 通过精确控制 rsp 确保执行流正确返回 5.2 堆栈平衡 每个伪造的栈帧必须保持分配与释放的空间一致 考虑影子空间(0x20字节)的影响 确保 ret 时 rsp 指向正确的伪造返回地址 5.3 系统调用处理 直接传递 syscall 地址(如 pNtAllocateVirtualMemory + 0x12 ) 模拟内核函数调用前的准备工作 6. 实际应用示例 6.1 LoudSunRun项目分析 获取 printf 地址 查找 jmp [rbx] 跳板 计算各函数栈大小 构造伪造调用链: 6.2 多参数处理示例 7. 注意事项 系统版本差异: 关键函数偏移量随系统版本变化 需动态获取或针对特定版本调整 寄存器使用: 使用非易失性寄存器( r12-r15 )保存关键值 易失性寄存器可能在调用中被修改 调试器兼容性: 某些汇编写法在x64dbg中不合法 依赖汇编器的语法容错能力 8. 总结 主动堆栈欺骗是一种高级的调用栈操纵技术,通过精心构造伪造的栈帧和精确控制执行流,可以实现: 隐藏真实调用链 绕过基于栈回溯的检测机制 实现更隐蔽的函数调用 关键技术点在于对x64调用约定、栈帧结构和返回机制的深入理解,以及对寄存器、内存布局的精确控制。