CobaltStrike逆向学习系列(3):Beacon C2Profile 解析
字数 1414 2025-08-29 08:30:36

CobaltStrike逆向学习系列(3):Beacon C2Profile解析

1. C2Profile概述

C2Profile是CobaltStrike中决定Beacon行为的关键配置文件,它包含了大量控制Beacon行为的参数。理解C2Profile的解析机制对于检测和绕过CobaltStrike具有重要意义。

2. Controller端分析

2.1 核心代码位置

分析位于beacon/BeaconPayload.java中的exportBeaconStage方法,这是处理C2Profile的关键方法。

2.2 数据结构构建

Controller使用四种方法构建C2Profile数据结构:

  1. addShort - 添加短整型数据
  2. addInt - 添加整型数据
  3. addString - 添加字符串数据
  4. addData - 添加任意二进制数据

其中addString本质上调用的是addData方法。

2.3 数据结构格式

每个数据项的存储格式如下:

[索引(2字节)][类型标识(1字节)][长度(1/2/4字节)][数据内容]

类型标识定义:

  • 1: Short类型
  • 2: Int类型
  • 3: Data/Ptr类型

3. Beacon端解析机制

3.1 加载流程

  1. Beacon由Loader加载执行
  2. 通过CreateThread启动执行
  3. 调用ReflectiveLoad加载Beacon DLL
  4. DLLMain被调用两次:
    • 第一次调用(fdwReason=1):解析C2Profile
    • 第二次调用(fdwReason=4):执行核心功能

3.2 内存初始化

  1. 申请0x800大小的内存用于存储
  2. 对内存进行异或操作(使用0x2E作为密钥)
  3. 设置解析结构体:
    • 存储两份C2Profile地址
    • 存储两份C2Profile大小

3.3 解析流程

  1. 读取索引

    • 检查剩余大小是否≥2字节
    • 读取2字节作为索引(index)
    • 调整位置偏移和剩余大小
  2. 读取类型和大小

    • 读取1字节类型(type)
    • 根据类型读取大小:
      • Short: 2字节
      • Int: 4字节
      • Ptr: 4字节(长度)
  3. 数据存储

    • 计算存储位置:index*16 (实现内存对齐)
    • 根据类型处理数据:
      • Short/Int: 直接存储值
      • Ptr:
        1. 根据size申请内存
        2. 检查剩余数据是否足够
        3. 拷贝数据到新内存
        4. 存储指针
  4. 结束条件

    • 当剩余大小<2字节时,解析结束
    • 最后将解析区域清零

4. 关键数据结构

4.1 Controller端结构

// 添加Short示例
settings.addShort(index, value);

// 底层实现
void addShort(int index, short value) {
    addShort(index, (int)value);
}

void addShort(int index, int value) {
    this.addInt(index, 1, 2, value);
}

4.2 Beacon端结构

Beacon中最终存储的结构与Controller端不同,采用索引对齐方式:

+------------+------------+------------+
| 索引0数据  | 索引1数据  | 索引2数据  |
| (16字节)   | (16字节)   | (16字节)   |
+------------+------------+------------+

每个索引位置存储:

  • 类型标识
  • 实际数据(或指针)

5. 检测与绕过

5.1 检测点

  1. 内存特征:

    • 初始的AAAABBBBCCCCDDDD特征
    • 4096的内存大小
    • 0x2E的异或操作
  2. 解析模式:

    • 特定的索引对齐方式
    • 类型标识的固定值

5.2 绕过思路

  1. 修改初始内存特征
  2. 改变异或密钥
  3. 调整内存对齐方式
  4. 自定义类型标识值

6. 总结

C2Profile的解析机制展示了CobaltStrike如何高效地配置和控制Beacon行为。理解这一机制不仅有助于分析CobaltStrike的工作原理,也为检测和防御提供了关键切入点。Controller和Beacon端使用不同的结构表示C2Profile,但通过索引和类型系统保持一致性,这种设计既保证了灵活性又提高了效率。

CobaltStrike逆向学习系列(3):Beacon C2Profile解析 1. C2Profile概述 C2Profile是CobaltStrike中决定Beacon行为的关键配置文件,它包含了大量控制Beacon行为的参数。理解C2Profile的解析机制对于检测和绕过CobaltStrike具有重要意义。 2. Controller端分析 2.1 核心代码位置 分析位于 beacon/BeaconPayload.java 中的 exportBeaconStage 方法,这是处理C2Profile的关键方法。 2.2 数据结构构建 Controller使用四种方法构建C2Profile数据结构: addShort - 添加短整型数据 addInt - 添加整型数据 addString - 添加字符串数据 addData - 添加任意二进制数据 其中 addString 本质上调用的是 addData 方法。 2.3 数据结构格式 每个数据项的存储格式如下: 类型标识定义: 1: Short类型 2: Int类型 3: Data/Ptr类型 3. Beacon端解析机制 3.1 加载流程 Beacon由Loader加载执行 通过 CreateThread 启动执行 调用 ReflectiveLoad 加载Beacon DLL DLLMain被调用两次: 第一次调用(fdwReason=1):解析C2Profile 第二次调用(fdwReason=4):执行核心功能 3.2 内存初始化 申请0x800大小的内存用于存储 对内存进行异或操作(使用0x2E作为密钥) 设置解析结构体: 存储两份C2Profile地址 存储两份C2Profile大小 3.3 解析流程 读取索引 : 检查剩余大小是否≥2字节 读取2字节作为索引(index) 调整位置偏移和剩余大小 读取类型和大小 : 读取1字节类型(type) 根据类型读取大小: Short: 2字节 Int: 4字节 Ptr: 4字节(长度) 数据存储 : 计算存储位置: index*16 (实现内存对齐) 根据类型处理数据: Short/Int: 直接存储值 Ptr: 根据size申请内存 检查剩余数据是否足够 拷贝数据到新内存 存储指针 结束条件 : 当剩余大小 <2字节时,解析结束 最后将解析区域清零 4. 关键数据结构 4.1 Controller端结构 4.2 Beacon端结构 Beacon中最终存储的结构与Controller端不同,采用索引对齐方式: 每个索引位置存储: 类型标识 实际数据(或指针) 5. 检测与绕过 5.1 检测点 内存特征: 初始的AAAABBBBCCCCDDDD特征 4096的内存大小 0x2E的异或操作 解析模式: 特定的索引对齐方式 类型标识的固定值 5.2 绕过思路 修改初始内存特征 改变异或密钥 调整内存对齐方式 自定义类型标识值 6. 总结 C2Profile的解析机制展示了CobaltStrike如何高效地配置和控制Beacon行为。理解这一机制不仅有助于分析CobaltStrike的工作原理,也为检测和防御提供了关键切入点。Controller和Beacon端使用不同的结构表示C2Profile,但通过索引和类型系统保持一致性,这种设计既保证了灵活性又提高了效率。