Modular PIC C2 Agents (reprise)
文章介绍了如何通过合并COFF文件构建模块化C2代理,并利用Crystal Palace的新功能简化开发流程。通过make coff和merge命令可将多个COFF合并为一个自包含的二进制文件,并支持导出为PICO供反射加载器使用。未来计划探索Java API实现更程序化的功能构建。 2025-9-12 22:27:47 Author: rastamouse.me(查看原文) 阅读量:4 收藏

A few months ago, I published a post called Modular PIC C2 Agents where I mused about what it could look like to build a C2 agent out of individual (modular) COFFs. The idea was to build a capability by swapping interchangeable parts in and out based on the requirements of the agent.

The process was a little convoluted to say the least, involved some abuses of Crystal Palace, and put a lot of heavy lifting on the reflective loader. However, Raffi has since made some changes that make this a lot easier.

COFF Merging

In my previous attempt, I had the reflective loader load each PICO individually and patch in the relevant function pointers at load-time (i.e. load PICO 1, then load PICO 2 and patch in a pointer to a function within PICO 1).

The latest version of Crystal Palace introduces new make coff and merge commands. make coff will turn the data on the current stack into something called a COFF "exporter". This is a construct that I like to think of as a stack of COFFs. You can add multiple COFFs to the stack and then export them.

For example, the following spec will merge coff1.x64.o and coff2.x64.o into a single blob:

name     "Merge COFFs"
author   "Rasta Mouse"

x64:
    load "bin/coff1.x64.o"    # load first coff
        make coff             # create coff exporter

    load "bin/coff2.x64.o"    # loader second coff
        merge                 # merge it with the first

    export                    export merged coff

merge.spec

The output of this are the raw bytes of the merged COFF. And because Crystal Palace is a linker, it will do the heavy lifting in linking functions together. The result is a fully-functional and self-contained COFF.

For example, if COFF2 had a function called show_message:

#include <windows.h>
 
WINBASEAPI int WINAPI USER32$MessageBoxW (HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType);
 
void show_message(LPCWSTR lpText) {
    /* call Win32 API*/
    USER32$MessageBoxW(NULL, lpText, L"Merged", MB_OK);
}

coff2.c

Then COFF1 can just call it.

#include <windows.h>

extern void show_message(LPCWSTR lpText);

void go() {
    show_message(L"Hello World");
}

coff1.c

You don't need headers or even the extern declaration (although the compiler will give you warnings without it). The merged COFF can then be saved to disk, or turned into a PICO and given to a reflective loader. An example of that could be:

name     "Simple Loader"
author   "Rasta Mouse"

x64:
    load "bin/loader.x64.o"    # read reflective loader
        make pic               # turn it into pic

    run "merge.spec"           # process the merged coff
        make object            # turn it into a PICO
        export                 # export to raw bytes
        link "merged_pico"     # link pico to reflective loader

    export                     # export the whole lot

loader.spec

Running piclink against this loader specification will produce a PIC blob that contains the reflective loader + merged PICO.

Future work?

I quite enjoyed working with COFFs in this way because it's so much easier from a development perspective.

I'm also interested in looking at the Java API a bit more to see how one might build a merged capability in a more progammatic fashion (imagine a GUI where you configure & build a capability by checking/unchecking "features" to include in the final output).


文章来源: https://rastamouse.me/modular-pic-c2-agents-reprise/
如有侵权请联系:admin#unsafe.sh