Cobalt Strike Beacon重构之Bof功能开发
字数 2513 2025-09-01 11:26:02
Cobalt Strike Beacon BOF功能开发详解
0x01. 前言
本文详细解析Cobalt Strike Beacon的BOF(Bypass Object File)功能开发,涵盖BOF介绍、开发流程、COFF文件格式解析、重定位处理机制以及Cobalt Strike客户端的处理逻辑。通过本文,您将全面掌握BOF开发的核心技术。
0x02. BOF介绍
BOF(Bypass Object File)本质上是一个COFF(Common Object File Format)文件,即编译后但未链接的目标文件(.obj)。在Cobalt Strike中,通过inline-execute命令可以将BOF文件加载到Beacon内存中,经过修复后执行。
BOF的优势:
- 提高OPSEC(操作安全性),避免执行高危指令如
shell - 为红队测试人员提供高度可扩展性
- 内存中执行,减少磁盘痕迹
0x03. BOF开发基础
开发环境准备
可以使用Visual Studio或MinGW进行BOF开发,生成.obj文件。推荐使用以下模板项目:
基本开发流程
- 编写C/C++代码
- 编译生成.obj文件
- 使用PEView等工具查看COFF格式
- 通过
inline-execute命令执行BOF
0x04. Beacon内部API
BOF可以调用一系列Beacon内部API,这些API分为以下几类:
1. Win32 API
主要用于函数动态解析:
DECLSPEC_IMPORT WINAPI NETAPI32$DsGetDcNameA(...);
DECLSPEC_IMPORT WINAPI NETAPI32$NetApiBufferFree(...);
2. 数据解析API
- BeaconDataParse
- BeaconDataPtr
3. 内容格式化API
- BeaconFormatAlloc
- BeaconFormatReset
4. 打印输出API
- BeaconOutput
- BeaconPrintf
5. Beacon内部功能API
- BeaconUseToken
- BeaconRevertToken
- BeaconSpawnTemporaryProcess
6. 辅助性API
- toWideChar
0x05. COFF文件格式详解
文件头结构
typedef struct _IMAGE_FILE_HEADER {
WORD Machine; // 目标机器类型(0x14C=x86, 0x8664=x64)
WORD NumberOfSections; // 节区数量
DWORD TimeDateStamp; // 时间戳
DWORD PointerToSymbolTable; // 符号表指针
DWORD NumberOfSymbols; // 符号数量
WORD SizeOfOptionalHeader;
WORD Characteristics;
} IMAGE_FILE_HEADER;
节表结构
typedef struct _IMAGE_SECTION_HEADER {
BYTE Name[8]; // 节区名称(UTF-8编码,占满8字节)
union {
DWORD PhysicalAddress;
DWORD VirtualSize;
} Misc;
DWORD VirtualAddress; // COFF中通常为0
DWORD SizeOfRawData; // 节在文件中的大小
DWORD PointerToRawData; // 节数据在文件中的位置
DWORD PointerToRelocations; // 重定位条目指针
DWORD PointerToLinenumbers; // 行号条目指针
WORD NumberOfRelocations; // 重定位条目数
WORD NumberOfLinenumbers; // 行号条目数
DWORD Characteristics; // 节属性
} IMAGE_SECTION_HEADER;
重定位表结构
typedef struct _IMAGE_RELOCATION {
union {
DWORD VirtualAddress; // 重定位地址偏移(相对于当前节基址)
DWORD RelocCount; // 重定位计数
};
DWORD SymbolTableIndex; // 符号表索引
WORD Type; // 重定位类型
} IMAGE_RELOCATION;
重定位类型(x64架构)
| 类型值 | 名称 | 描述 |
|---|---|---|
| 1 | IMAGE_REL_AMD64_ABSOLUTE | 绝对地址 |
| 2 | IMAGE_REL_AMD64_ADDR64 | 64位绝对地址 |
| 3 | IMAGE_REL_AMD64_ADDR32 | 32位绝对地址 |
| 4 | IMAGE_REL_AMD64_REL32 | 32位相对地址 |
| 5 | IMAGE_REL_AMD64_REL32_1 | 32位相对地址(偏移1字节) |
| 6 | IMAGE_REL_AMD64_REL32_2 | 32位相对地址(偏移2字节) |
| 7 | IMAGE_REL_AMD64_REL32_3 | 32位相对地址(偏移3字节) |
| 8 | IMAGE_REL_AMD64_REL32_4 | 32位相对地址(偏移4字节) |
| 9 | IMAGE_REL_AMD64_REL32_5 | 32位相对地址(偏移5字节) |
符号表结构
typedef struct _IMAGE_SYMBOL {
union {
BYTE ShortName[8]; // 符号名(≤8字节)
struct {
DWORD Short; // 前4字节为0
DWORD Long; // 后4字节为字符表偏移
} Name;
};
DWORD Value; // 符号在节中的偏移或绝对偏移
SHORT SectionNumber; // 符号所属节区号
WORD Type; // 符号类型(0x0=非函数,0x20=函数)
BYTE StorageClass; // 存储类
BYTE NumberOfAuxSymbols; // 辅助符号数
} IMAGE_SYMBOL;
存储类(StorageClass)
| 值 | 名称 | 描述 |
|---|---|---|
| 2 | EXTERNAL | 外部符号 |
| 3 | STATIC | 静态符号 |
| 6 | LABEL | 标签符号 |
0x06. Cobalt Strike客户端处理流程
1. 客户端处理步骤
- Coff文件内容传入
PostExInlineObject#go函数 - 调用
OBJExecutable#parse解析COFF文件 - 构造数据包,包含:
- 命令号
- obj入口函数(go)
- .text段数据长度+内容
- .rdata段数据长度+内容
- .data段数据长度+内容
- 重定位信息
- 入口函数参数
2. 重定位信息结构
客户端通过OBJExecutable#getRelocation返回的重定位信息结构:
| 类型值 | 描述 |
|---|---|
| 1024 | 重定位位置在.rdata区段 |
| 1027 | 重定位对应外部函数 |
| 1028 | 重定位信息结束标识符 |
3. Beacon端处理流程
- 解析数据包内容
- 分配内存(初始RW,后改为RWX)
- 处理重定位信息
- 执行BOF
关键处理函数:
processRelocation: 处理重定位FindOrAddDynamicFunction: 查找或添加动态函数
0x07. BOF开发常见问题
1. 未初始化的全局变量
问题:Cobalt Strike 4.4客户端未处理.bss段
解决方案:避免使用未初始化的全局变量
2. Windows API调用崩溃
问题:堆不匹配导致崩溃
解决方案:使用正确的堆分配方式
// 正确分配方式
char* buffer = (char*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
// 正确释放方式
HeapFree(GetProcessHeap(), 0, buffer);
3. 堆栈扩展问题
问题:缺少_chkstk_ms辅助函数
解决方案:避免使用大量栈空间(>4KB)
4. 大型switch语句崩溃
问题:BOF只适合小型switch语句
解决方案:改用if/else结构
5. x64下全局变量错误
问题:编译器优化导致全局变量位置错误
解决方案:添加额外的非零全局变量打乱对齐
0x08. 总结
本文详细介绍了BOF开发的全流程,从基础概念到COFF文件格式解析,再到Cobalt Strike客户端的处理机制。关键点包括:
- BOF本质是未链接的COFF文件
- COFF文件格式的详细结构解析
- 重定位处理的核心机制
- Beacon内部API的分类和使用
- 常见问题及解决方案
通过掌握这些知识,您可以开发出高效、稳定的BOF功能模块,提升红队测试的灵活性和隐蔽性。