利用ReflectiveDLL来武装你的Cobalt Strike
字数 1129 2025-08-20 18:16:55

利用ReflectiveDLL武装Cobalt Strike的详细指南

前言

Cobalt Strike作为当前渗透测试工作中常用的工具,可以通过插件扩展其功能。本文详细讲解如何利用反射DLL技术(ReflectiveDLL)来增强Cobalt Strike的能力,包括C++和Golang两种语言的实现方式。

C++ ReflectiveDLL实现

基本原理

Cobalt Strike的bdllspawn命令基于Stephen Fewer的ReflectiveDLLInjection项目实现,允许不落地加载DLL文件。

关键实现步骤

  1. 参数转换处理
    • ReflectiveDll.c中通过DLLMain函数的lpReserved参数传递数据
    • 需要进行参数类型转换:
#include "ReflectiveLoader.h"
#include <string>
#include <shellapi.h>
#pragma comment(lib, "Shell32.lib")

std::string szargs;
std::wstring wszargs;
std::wstring wsHostFile;
int argc = 0;
LPWSTR* argv = NULL;

// 参数转换代码
szargs = (PCHAR)lpReserved;
wszargs = StringToWString(szargs);
argv = CommandLineToArgvW(wszargs.data(), &argc);
  1. 功能编写示例
hAppInstance = hinstDLL;
printf("C++ ReflectiveDLL\n");

if (lpReserved != NULL) {
    szargs = (PCHAR)lpReserved;
    wszargs = StringToWString(szargs);
    argv = CommandLineToArgvW(wszargs.data(), &argc);
}
if (argv == NULL) {
    printf("[+] Error Arguments ! \n");
    break;
}
printf("[+] Args Count : %d \n", argc);
for (size_t i = 0; i < argc; i++) {
    wprintf(TEXT("[%d] %s \n"), i, argv[i]);
}

fflush(stdout);
ExitProcess(0);
  1. Aggressor Script集成
alias hello {
    $args = substr($0, 6);
    bdllspawn($1, script_resource("reflective_dll.dll"),$args, "test dll", 5000, false);
}

Golang ReflectiveDLL实现

基本原理

通过修改Go程序使其能够作为反射DLL加载,参考go-ReflectiveDLL项目。

关键实现步骤

  1. main.go修改
package main

import "C"

import (
    "fmt"
    "os"
    gsq "github.com/kballard/go-shellquote"
)

//export test
func test(arg string) {
    args, err := gsq.Split(arg)
    if err == nil {
        fmt.Println("Golang ReflectiveDLL")
        os.Args = args
        fmt.Printf("Args Count %d\n",len(os.Args))
        for i := 0; i < len(os.Args); i++ {
            fmt.Printf("[%d] %s\n",i,os.Args[i])
        }
    }
}

func main() {}
  1. dllmain.c实现
#include "dllmain.h"
#include<Windows.h>

BOOL WINAPI DllMain(
    HINSTANCE hinstDLL,
    DWORD fdwReason,
    LPVOID lpReserved)
{
    switch (fdwReason) {
    case DLL_PROCESS_ATTACH:
        {
            GoString goArgs = {0};
            if(lpReserved != NULL){
                goArgs.p = (char*)lpReserved;
                goArgs.n = strlen(lpReserved);
            }else{
                goArgs.p = "";
                goArgs.n = 0;
            }
            test(goArgs);
        }
        break;
    // 其他case处理...
    }
    return TRUE;
}
  1. 编译方法
    • 使用项目提供的x64.bat进行编译
    • 注意:Golang编译的DLL文件较大(约2MB),可能超过Cobalt Strike的1MB限制

进程间通信实现

当注入到其他进程时,可通过命名管道实现输出捕获:

  1. Inject.c修改
// 创建命名管道
HANDLE hPipe = CreateNamedPipe(
    TEXT("\\\\.\\Pipe\\mypipe"),
    PIPE_ACCESS_DUPLEX,
    PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
    PIPE_UNLIMITED_INSTANCES,
    0,
    0,
    NMPWAIT_WAIT_FOREVER,
    NULL);

// 等待连接并读取数据
while (1) {
    if (ReadFile(hPipe, buf, 256, &rlen, NULL)) {
        printf("\t%s", buf);
    } else {
        printf("\n[+] Read Data From Pipe End!\n");
        break;
    }
}
  1. DLL端实现
HANDLE hPipe = CreateFile(
    TEXT("\\\\.\\Pipe\\mypipe"),
    GENERIC_READ | GENERIC_WRITE,
    0,
    NULL,
    OPEN_EXISTING,
    FILE_ATTRIBUTE_NORMAL,
    NULL);

char buf[256] = "";
sprintf(buf, "C++ ReflectiveDLL\n");
WriteFile(hPipe, buf, sizeof(buf), &wlen, 0);

注意事项

  1. Golang DLL大小限制

    • Cobalt Strike限制反射DLL大小在1MB以内
    • Golang编译的简单DLL就有约2MB,不适合直接使用
    • 可考虑Cobalt Strike 4.1+的Beacon Object File (BOF)功能替代
  2. 参数传递

    • 原始ReflectiveDLLInjection项目中的inject无法传参
    • 需要修改代码将参数传入LoadRemoteLibraryR函数
  3. 进程注入选择

    • 注入当前进程可直接传参
    • 注入其他进程需要先将参数写入目标进程内存

替代方案

对于Golang程序,可考虑以下方案:

  1. 使用Cobalt Strike 4.1+的BOF功能
  2. 将核心功能拆分为小型DLL
  3. 使用混合编程(Go调用C/C++)

示例代码

完整示例代码可参考:
https://github.com/uknowsec/ReflectiveDLLInjection-Notes

参考资料

  1. ReflectiveDLLInjection项目
  2. go-ReflectiveDLL项目
  3. Weaponizing Go for Cobalt Strike
  4. Cobalt Strike BOF文档
利用ReflectiveDLL武装Cobalt Strike的详细指南 前言 Cobalt Strike作为当前渗透测试工作中常用的工具,可以通过插件扩展其功能。本文详细讲解如何利用反射DLL技术(ReflectiveDLL)来增强Cobalt Strike的能力,包括C++和Golang两种语言的实现方式。 C++ ReflectiveDLL实现 基本原理 Cobalt Strike的 bdllspawn 命令基于Stephen Fewer的 ReflectiveDLLInjection 项目实现,允许不落地加载DLL文件。 关键实现步骤 参数转换处理 : 在 ReflectiveDll.c 中通过 DLLMain 函数的 lpReserved 参数传递数据 需要进行参数类型转换: 功能编写示例 : Aggressor Script集成 : Golang ReflectiveDLL实现 基本原理 通过修改Go程序使其能够作为反射DLL加载,参考 go-ReflectiveDLL 项目。 关键实现步骤 main.go修改 : dllmain.c实现 : 编译方法 : 使用项目提供的 x64.bat 进行编译 注意:Golang编译的DLL文件较大(约2MB),可能超过Cobalt Strike的1MB限制 进程间通信实现 当注入到其他进程时,可通过命名管道实现输出捕获: Inject.c修改 : DLL端实现 : 注意事项 Golang DLL大小限制 : Cobalt Strike限制反射DLL大小在1MB以内 Golang编译的简单DLL就有约2MB,不适合直接使用 可考虑Cobalt Strike 4.1+的Beacon Object File (BOF)功能替代 参数传递 : 原始ReflectiveDLLInjection项目中的inject无法传参 需要修改代码将参数传入 LoadRemoteLibraryR 函数 进程注入选择 : 注入当前进程可直接传参 注入其他进程需要先将参数写入目标进程内存 替代方案 对于Golang程序,可考虑以下方案: 使用Cobalt Strike 4.1+的BOF功能 将核心功能拆分为小型DLL 使用混合编程(Go调用C/C++) 示例代码 完整示例代码可参考: https://github.com/uknowsec/ReflectiveDLLInjection-Notes 参考资料 ReflectiveDLLInjection项目 go-ReflectiveDLL项目 Weaponizing Go for Cobalt Strike Cobalt Strike BOF文档