CobaltStrike逆向学习系列(6):Beacon sleep_mask 分析
字数 1793 2025-08-07 08:22:18

CobaltStrike Beacon sleep_mask 逆向分析教学文档

1. 概述

CobaltStrike 提供了一个内存混淆功能,在 Beacon 休眠(Sleep)时会将自身代码混淆以避免检测。本文详细分析 sleep_mask 功能的实现机制。

2. C2Profile 配置解析

sleep_mask 功能通过 C2Profile 配置启用,关键配置项包括:

  1. rwx 权限设置:决定是否对 text 段进行混淆
  2. obfuscate 设置:本文不重点关注此项
  3. 内存区域配置
    • 存储 text 段结尾地址到 index=41 的位置
    • 检查 text 段与 rdata 段之间的空白区域是否足够256字节(推测用于存放加解密函数)

2.1 内存区域处理流程

  1. 默认添加 0 和 4096 到配置中
  2. 循环添加内容:
    • 循环条件:text 段且不允许使用 rwx
    • 当禁止 rwx 时,text 段不会被添加到 index=42 的项中(不会被混淆)
    • 最后添加零作为结束标记

3. userwx "true" 时的行为分析

3.1 加解密函数定位

  1. 通过设置断点快速定位加解密函数
  2. 调用链分析:
    • 主循环最后有一个处理 Sleep 的函数
    • 通过判断 0x29 位置的值决定是否直接调用 Sleep
    • 使用 sleep_mask 时,0x29 存储 text 段的结尾地址

3.2 加解密过程

  1. 函数参数传递:

    • 传入当前函数和加解密函数
    • 计算两个函数地址的差值(即加解密函数长度)
  2. 内存操作:

    • 从 0x29 取出 text 段结尾地址
    • 从全局变量获取 PE 头位置
    • 相加得到内存中 text 段的结尾地址(用于存放加解密函数)
  3. 关键数据结构:

    • 申请 32 字节空间:
      • 前8字节:PE 头地址
      • 后8字节:0x2A 的地址(之前构造的结构)
    • 将加16的位置传入
  4. 密钥生成:

    • 首选使用 CryptoAPI 生成密钥
    • 失败时使用自定义算法生成密钥
  5. 加解密函数调用:

    • 参数1:构造的结构
    • 参数2:Sleep 函数
    • 参数3:时间参数

3.3 加解密函数分析

  1. 参数解析:

    • 参数是指针类型,取数组下标1的值(0x2A 对应的值)
    • v6:第一个值 sectionAddress
    • v7:第二个值 sectionEnd
    • v3 后移用于判断跳出规则(最后添加的两个零)
  2. 混淆条件:

    • do-while 循环条件:sectionAddress < sectionEnd
    • 效果:对所有代码进行混淆
  3. 解密逻辑:

    • 与加密逻辑对称

3.4 内存状态验证

  1. Sleep 状态:

    • 代码段被混淆
  2. 接收命令状态:

    • 代码段被混淆

结论:允许 RWX 权限时,代码段会被混淆

4. userwx "false" 时的行为分析

4.1 理论验证

根据之前的分析,当禁止 RWX 权限时:

  • text 段不会被添加到 index=42 的混淆项中
  • 代码段不会被混淆

4.2 内存状态验证

  1. Sleep 状态:

    • 代码段保持原样
  2. 接收命令状态:

    • 代码段保持原样

结论:禁止 RWX 权限时,代码段不会被混淆

5. 关键点总结

  1. rwx 权限决定混淆范围

    • 允许时:混淆 text 段
    • 禁止时:不混淆 text 段
  2. 加解密函数位置

    • 位于 text 段与 rdata 段之间的空白区域
    • 需要至少256字节空间
  3. 混淆触发时机

    • Beacon 进入 Sleep 状态时触发加密
    • 接收命令时触发解密
  4. 密钥生成

    • 优先使用 CryptoAPI
    • 备选自定义算法
  5. 数据结构

    • 使用32字节结构存储关键地址信息
    • 以双零作为结束标记

6. 检测与对抗思路

  1. 检测点

    • 查找 text 段与 rdata 段之间的可疑代码(加解密函数)
    • 监控 Sleep 前后的内存变化
    • 检测 CryptoAPI 的异常使用模式
  2. 对抗思路

    • 修改默认的加解密算法
    • 动态调整混淆区域
    • 实现多阶段混淆机制

7. 参考实现伪代码

// 主循环中的Sleep处理
void HandleSleep() {
    if (global_29) { // 使用sleep_mask
        // 准备加解密
        PrepareEncryptDecrypt(current_func, encrypt_func);
        
        // 加密内存
        EncryptMemory();
        
        // 执行Sleep
        Sleep(duration);
        
        // 解密内存
        DecryptMemory();
    } else {
        // 直接Sleep
        Sleep(duration);
    }
}

// 加解密函数
void EncryptDecryptFunc(void* structure) {
    uint64_t* params = (uint64_t*)structure;
    uint64_t sectionStart = params[0];
    uint64_t sectionEnd = params[1];
    
    // 生成密钥
    if (!GenerateKeyWithCryptoAPI()) {
        GenerateKeyWithCustomAlgo();
    }
    
    // 混淆代码
    while (sectionStart < sectionEnd) {
        // 混淆操作
        XorMemory(sectionStart, key);
        sectionStart++;
    }
}

8. 扩展研究建议

  1. 分析不同CobaltStrike版本的sleep_mask实现差异
  2. 研究绕过内存扫描的进阶混淆技术
  3. 探索对抗EDR的sleep_mask增强方案
  4. 开发基于此原理的自定义混淆模块

通过本文分析,可以深入理解CobaltStrike Beacon的sleep_mask工作机制,为红队工具开发和蓝队检测提供技术参考。

CobaltStrike Beacon sleep_ mask 逆向分析教学文档 1. 概述 CobaltStrike 提供了一个内存混淆功能,在 Beacon 休眠(Sleep)时会将自身代码混淆以避免检测。本文详细分析 sleep_ mask 功能的实现机制。 2. C2Profile 配置解析 sleep_ mask 功能通过 C2Profile 配置启用,关键配置项包括: rwx 权限设置 :决定是否对 text 段进行混淆 obfuscate 设置 :本文不重点关注此项 内存区域配置 : 存储 text 段结尾地址到 index=41 的位置 检查 text 段与 rdata 段之间的空白区域是否足够256字节(推测用于存放加解密函数) 2.1 内存区域处理流程 默认添加 0 和 4096 到配置中 循环添加内容: 循环条件:text 段且不允许使用 rwx 当禁止 rwx 时,text 段不会被添加到 index=42 的项中(不会被混淆) 最后添加零作为结束标记 3. userwx "true" 时的行为分析 3.1 加解密函数定位 通过设置断点快速定位加解密函数 调用链分析: 主循环最后有一个处理 Sleep 的函数 通过判断 0x29 位置的值决定是否直接调用 Sleep 使用 sleep_ mask 时,0x29 存储 text 段的结尾地址 3.2 加解密过程 函数参数传递: 传入当前函数和加解密函数 计算两个函数地址的差值(即加解密函数长度) 内存操作: 从 0x29 取出 text 段结尾地址 从全局变量获取 PE 头位置 相加得到内存中 text 段的结尾地址(用于存放加解密函数) 关键数据结构: 申请 32 字节空间: 前8字节:PE 头地址 后8字节:0x2A 的地址(之前构造的结构) 将加16的位置传入 密钥生成: 首选使用 CryptoAPI 生成密钥 失败时使用自定义算法生成密钥 加解密函数调用: 参数1:构造的结构 参数2:Sleep 函数 参数3:时间参数 3.3 加解密函数分析 参数解析: 参数是指针类型,取数组下标1的值(0x2A 对应的值) v6:第一个值 sectionAddress v7:第二个值 sectionEnd v3 后移用于判断跳出规则(最后添加的两个零) 混淆条件: do-while 循环条件:sectionAddress < sectionEnd 效果:对所有代码进行混淆 解密逻辑: 与加密逻辑对称 3.4 内存状态验证 Sleep 状态: 代码段被混淆 接收命令状态: 代码段被混淆 结论 :允许 RWX 权限时,代码段会被混淆 4. userwx "false" 时的行为分析 4.1 理论验证 根据之前的分析,当禁止 RWX 权限时: text 段不会被添加到 index=42 的混淆项中 代码段不会被混淆 4.2 内存状态验证 Sleep 状态: 代码段保持原样 接收命令状态: 代码段保持原样 结论 :禁止 RWX 权限时,代码段不会被混淆 5. 关键点总结 rwx 权限决定混淆范围 : 允许时:混淆 text 段 禁止时:不混淆 text 段 加解密函数位置 : 位于 text 段与 rdata 段之间的空白区域 需要至少256字节空间 混淆触发时机 : Beacon 进入 Sleep 状态时触发加密 接收命令时触发解密 密钥生成 : 优先使用 CryptoAPI 备选自定义算法 数据结构 : 使用32字节结构存储关键地址信息 以双零作为结束标记 6. 检测与对抗思路 检测点 : 查找 text 段与 rdata 段之间的可疑代码(加解密函数) 监控 Sleep 前后的内存变化 检测 CryptoAPI 的异常使用模式 对抗思路 : 修改默认的加解密算法 动态调整混淆区域 实现多阶段混淆机制 7. 参考实现伪代码 8. 扩展研究建议 分析不同CobaltStrike版本的sleep_ mask实现差异 研究绕过内存扫描的进阶混淆技术 探索对抗EDR的sleep_ mask增强方案 开发基于此原理的自定义混淆模块 通过本文分析,可以深入理解CobaltStrike Beacon的sleep_ mask工作机制,为红队工具开发和蓝队检测提供技术参考。