Cobaltstrike4.0 —— shellcode分析
字数 2162 2025-08-06 18:07:56

Cobalt Strike 4.0 Shellcode 深度分析

0x01 概述

本文详细分析Cobalt Strike 4.0生成的shellcode工作原理,涵盖从初始shellcode执行到最终Beacon加载的全过程。

0x02 Shellcode分析流程

一、Shellcode生成

  1. 通过Cobalt Strike生成Payload(1600字节)
  2. 创建加载器(Stager Loader)执行该Payload

二、Shellcode Loader实现

#include <windows.h>

int main(void) {
    unsigned char buf[] = {payload_bytes}; 
    HANDLE myHeap = HeapCreate(HEAP_CREATE_ENABLE_EXECUTE, 0, 0);
    void* exec = HeapAlloc(myHeap, HEAP_ZERO_MEMORY, sizeof(buf));
    memcpy(exec, buf, sizeof(buf));
    ((void(*)())exec)();
    return 0;
}

编译注意事项:

  • 关闭优化、安全检查、随机基址等选项
  • 使用x86 Release模式生成

三、Shellcode执行流程分析

第一阶段:Stager

  1. 初始执行

    • 通过pop ebp获取EIP
    • 压入特征码和参数("wininet"和特征码726774C)
  2. 模块遍历

    • 通过FS寄存器获取TEB→PEB→PEB_LDR_DATA→InMemoryOrderLinks
    • 遍历模块列表(_LDR_DATA_TABLE_ENTRY结构)
    • 获取模块基址(结构体0x18偏移处)
  3. 特征码计算

    ; 模块名特征算法
    1. 对每个字符判断,如果大于0x60就减0x20(小写转大写)
    2. 累加前将上一次结果循环右移14位
    3. 累加当前字符值
    
  4. 函数查找

    • 找到导出表(PE头0x78偏移)
    • 遍历导出函数名,计算特征值(算法同上但无大小写转换)
    • 比较模块特征值+函数特征值与目标特征码
  5. 关键函数获取

    • 找到的9个关键wininet函数:
      • InternetOpenA (A779563A)
      • InternetConnectA (C69F8957)
      • HttpOpenRequestA (3B2E55EB)
      • HttpSendRequestA (7B18062D)
      • GetDesktopWindow (315E2145)
      • InternetErrorDlg (0BE057B7)
      • VirtualAlloc (E553A458)
      • InternetReadFile (E2899612)
  6. Beacon下载

    • 建立与C2服务器的连接
    • 发送GET请求
    • 使用VirtualAlloc开辟内存
    • InternetReadFile读取响应内容并执行

第二阶段:Beacon解密

  1. 解密过程
    • 从偏移46开始的内容与固定3D偏移内容进行4字节异或
    • 解密长度:0x33000字节
    • 解密后得到PE文件(起始标志4D5A)

第三阶段:反射加载

  1. PE执行

    • 通过pop edi; jmp edi跳转到解密数据45偏移处
    • 使用Reflective DLL Injection技术
  2. ReflectiveLoader函数

    • 定位PE头部
    • 获取kernel32模块基址(特征码6A4ABC5B)
    • 查找6个关键函数:
      • GetProcessAddress
      • GetModuleHandleA
      • LoadLibraryA
      • LoadLibraryExA
      • VirtualAlloc
      • VirtualProtect
  3. DLL加载过程

    • 文件格式到内存格式的拉伸
    • 修复导入表(IAT)
    • 修复重定位表(按页处理,每页0x1000大小)
  4. DLL入口调用

    • 调用DllEntryPoint(非直接DllMain)
    • 首次调用fdwReason=1(初始化)
    • 第二次调用fdwReason=4

第四阶段:DllMain分析

  1. 初始化阶段(fdwReason=1)

    • 解密配置数据(循环0x1000次)
    • 还原C2配置信息(IP、端口、UA、心跳时间等)
  2. 主逻辑阶段(fdwReason=4)

    • 通过VirtualQuery检查内存页面属性
    • 建立心跳循环:
      • 使用InternetOpen、InternetConnect等建立连接
      • 发送心跳请求
      • 通过InternetReadFile获取响应
    • 命令分发:
      • 根据响应类型执行不同操作
      • Beacon内置100种任务类型

0x03 关键技术点

一、特征码算法

目的:

  1. 缩短shellcode长度
  2. 对抗静态分析

模块名特征算法:

def calc_hash(name):
    hash_val = 0
    for c in name:
        if c > 0x60:  # 小写字母
            c -= 0x20  # 转大写
        hash_val = ((hash_val >> 14) | (hash_val << (32 - 14))) & 0xFFFFFFFF
        hash_val = (hash_val + c) & 0xFFFFFFFF
    return hash_val

二、Windows R3模块基址获取

通过FS寄存器链式查找:

  1. FS[0] → TEB
  2. TEB → PEB
  3. PEB → PEB_LDR_DATA
  4. PEB_LDR_DATA → InMemoryOrderLinks
  5. 遍历_LDR_DATA_TABLE_ENTRY结构获取模块信息

三、检测思路

流量侧检测:

  1. Beacon下载请求特征:
    • 满足checksum8算法
    • 返回约20000字节
  2. Beacon内容解密:
    • 固定异或解密方式
  3. 心跳流量特征:
    • URI模式
    • 元数据传输字段
  4. TLS特征:
    • 默认证书
    • 特定握手模式

主机侧检测:

  1. 内存扫描:
    • 查找Beacon初始化解密的数据模式
  2. Shellcode行为检测:
    • FS寄存器模块查找
    • 反射加载行为
  3. 动态加载检测:
    • 非常规DLL加载方式

0x04 完整执行流程总结

  1. 初始Shellcode执行

    • 动态解析API
    • 下载Beacon
  2. Beacon处理

    • 解密PE文件
    • 反射加载DLL
  3. DLL初始化

    • 解密配置
    • 建立通信
  4. 主循环

    • 心跳机制
    • 命令执行

附录:关键数据结构

_LDR_DATA_TABLE_ENTRY

struct _LDR_DATA_TABLE_ENTRY {
    struct _LIST_ENTRY InLoadOrderLinks;        //0x0              
    struct _LIST_ENTRY InMemoryOrderLinks;      //0x8  
    struct _LIST_ENTRY InInitializationOrderLinks; //0x10               
    VOID* DllBase;                             //0x18                          
    VOID* EntryPoint;                          //0x1c                           
    ULONG SizeOfImage;                         //0x20                                 
    struct _UNICODE_STRING FullDllName;        //0x24                           
    struct _UNICODE_STRING BaseDllName;       //0x2c                           
    //...
};

PE导出表结构

typedef struct _IMAGE_EXPORT_DIRECTORY {
    DWORD   Characteristics;
    DWORD   TimeDateStamp;
    WORD    MajorVersion;
    WORD    MinorVersion;
    DWORD   Name;
    DWORD   Base;
    DWORD   NumberOfFunctions;
    DWORD   NumberOfNames;
    DWORD   AddressOfFunctions;     // RVA from base of image
    DWORD   AddressOfNames;         // RVA from base of image
    DWORD   AddressOfNameOrdinals;  // RVA from base of image
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;

重定位表结构

typedef struct _IMAGE_BASE_RELOCATION {
    DWORD   VirtualAddress;
    DWORD   SizeOfBlock;
    // Followed by WORD TypeOffset[1]
} IMAGE_BASE_RELOCATION;

注:本文分析基于Cobalt Strike 4.0版本,不同版本实现细节可能有所差异。

Cobalt Strike 4.0 Shellcode 深度分析 0x01 概述 本文详细分析Cobalt Strike 4.0生成的shellcode工作原理,涵盖从初始shellcode执行到最终Beacon加载的全过程。 0x02 Shellcode分析流程 一、Shellcode生成 通过Cobalt Strike生成Payload(1600字节) 创建加载器(Stager Loader)执行该Payload 二、Shellcode Loader实现 编译注意事项: 关闭优化、安全检查、随机基址等选项 使用x86 Release模式生成 三、Shellcode执行流程分析 第一阶段:Stager 初始执行 : 通过 pop ebp 获取EIP 压入特征码和参数("wininet"和特征码726774C) 模块遍历 : 通过FS寄存器获取TEB→PEB→PEB_ LDR_ DATA→InMemoryOrderLinks 遍历模块列表(_ LDR_ DATA_ TABLE_ ENTRY结构) 获取模块基址(结构体0x18偏移处) 特征码计算 : 函数查找 : 找到导出表(PE头0x78偏移) 遍历导出函数名,计算特征值(算法同上但无大小写转换) 比较模块特征值+函数特征值与目标特征码 关键函数获取 : 找到的9个关键wininet函数: InternetOpenA (A779563A) InternetConnectA (C69F8957) HttpOpenRequestA (3B2E55EB) HttpSendRequestA (7B18062D) GetDesktopWindow (315E2145) InternetErrorDlg (0BE057B7) VirtualAlloc (E553A458) InternetReadFile (E2899612) Beacon下载 : 建立与C2服务器的连接 发送GET请求 使用VirtualAlloc开辟内存 InternetReadFile读取响应内容并执行 第二阶段:Beacon解密 解密过程 : 从偏移46开始的内容与固定3D偏移内容进行4字节异或 解密长度:0x33000字节 解密后得到PE文件(起始标志4D5A) 第三阶段:反射加载 PE执行 : 通过 pop edi; jmp edi 跳转到解密数据45偏移处 使用Reflective DLL Injection技术 ReflectiveLoader函数 : 定位PE头部 获取kernel32模块基址(特征码6A4ABC5B) 查找6个关键函数: GetProcessAddress GetModuleHandleA LoadLibraryA LoadLibraryExA VirtualAlloc VirtualProtect DLL加载过程 : 文件格式到内存格式的拉伸 修复导入表(IAT) 修复重定位表(按页处理,每页0x1000大小) DLL入口调用 : 调用DllEntryPoint(非直接DllMain) 首次调用fdwReason=1(初始化) 第二次调用fdwReason=4 第四阶段:DllMain分析 初始化阶段(fdwReason=1) : 解密配置数据(循环0x1000次) 还原C2配置信息(IP、端口、UA、心跳时间等) 主逻辑阶段(fdwReason=4) : 通过VirtualQuery检查内存页面属性 建立心跳循环: 使用InternetOpen、InternetConnect等建立连接 发送心跳请求 通过InternetReadFile获取响应 命令分发: 根据响应类型执行不同操作 Beacon内置100种任务类型 0x03 关键技术点 一、特征码算法 目的: 缩短shellcode长度 对抗静态分析 模块名特征算法: 二、Windows R3模块基址获取 通过FS寄存器链式查找: FS[ 0 ] → TEB TEB → PEB PEB → PEB_ LDR_ DATA PEB_ LDR_ DATA → InMemoryOrderLinks 遍历_ LDR_ DATA_ TABLE_ ENTRY结构获取模块信息 三、检测思路 流量侧检测: Beacon下载请求特征: 满足checksum8算法 返回约20000字节 Beacon内容解密: 固定异或解密方式 心跳流量特征: URI模式 元数据传输字段 TLS特征: 默认证书 特定握手模式 主机侧检测: 内存扫描: 查找Beacon初始化解密的数据模式 Shellcode行为检测: FS寄存器模块查找 反射加载行为 动态加载检测: 非常规DLL加载方式 0x04 完整执行流程总结 初始Shellcode执行 : 动态解析API 下载Beacon Beacon处理 : 解密PE文件 反射加载DLL DLL初始化 : 解密配置 建立通信 主循环 : 心跳机制 命令执行 附录:关键数据结构 _ LDR_ DATA_ TABLE_ ENTRY PE导出表结构 重定位表结构 注:本文分析基于Cobalt Strike 4.0版本,不同版本实现细节可能有所差异。