一款基于 Adaptix C2 的代理,使用 Crystal Palace — 一个自定义的 PIC(位置无关代码)链接器和 PICO 模块系统构建。演示了如何构建模块化的 Shellcode 代理,其中每个组件(传输、任务、混淆)都是一个独立的 PICO 数据块,在运行时加载。
本代理不包含任何规避技术,不推荐直接用于实战。它只是一个参考实现,用于演示如何使用 Crystal Palace 和 PICO 模块系统构建代理。
Crystal Palace 是一个 PIC 链接器,它获取编译后的 COFF 目标文件并生成位置无关的可执行文件。关键概念:
make pic +gofirst) — 主可执行 Shellcode。包含引导代码、DFR 解析器以及 PICO 模块链接处的段标记。由加载器直接调用。make object) — 自包含的代码 blob,拥有自己的代码和数据段。在运行时通过 PicoLoad() 从 libtcg 加载。每个 PICO 都有一个可通过函数指针调用的入口点 (go())。MODULE$Function 语法(例如 KERNEL32$VirtualAlloc)替换为对 resolve(mod_hash, func_hash) 的调用,使用 ROR13 哈希。没有导入表。所有字符串参数(DLL 名称、函数名)都作为字符数组在栈上构建,以避免二进制文件中出现明文。.spec 文件中的 link 指令,将 PICO blob 嵌入到核心 PIC 的命名段中(如 entry_module、transport_module 等)。{LoadLibraryA, GetProcAddress} 传递给 PicoLoad(),以便 PICO 模块可以解析自己的 DFR 符号。C 源代码 → mingw-gcc → COFF 目标文件 → Crystal Palace 链接 → 原始 PIC Shellcode → 加载器 (Exe/Dll/Svc)
.spec 文件定义了 Crystal Palace 的链接方式:
x64:
load "Bin/obj/main.x64.o" # 核心 PIC
make pic +gofirst
foreach %LIBS: mergelib %_ # 合并 libtcg
load "Bin/obj/entry.x64.o" # 入口 PICO
make object
load "Bin/obj/crypto.x64.o" # 将 crypto 合并到 entry 中
merge
load "Bin/obj/packer.x64.o" # 将 packer 合并到 entry 中
merge
export
link "entry_module" # 链接到段标记
load "Bin/obj/transport.x64.o" # 传输 PICO
make object
mergelib "lib/LibWinHttp/..."
export
link "transport_module"
... # task_module, obfuscation_module
dfr "resolve" "ror13" # 解析所有 DFR 符号
export
核心 PIC (main.c)
│
├── resolve() DFR 桥 → libtcg 哈希查找
├── AllocateAndLoadModule() 将每个 PICO 加载到共享 RWX 区域
│
└── 调用 entry 模块的 go(),并传递指向所有其他模块的指针
│
├── 入口模块 (entry.c)
│ MvState, 回连, 收发 (RC4 线格式), 任务循环
│
├── 传输模块 (transport.c)
│ 通过 LibWinHttp 进行 HTTP/HTTPS POST
│
├── 任务模块 (tasks.c)
│ 命令派发: whoami (0x30), sleep (0x20), exit (0x10)
│
└── 混淆模块 (obfuscation.c)
Ekko 休眠 — 定时器队列 ROP 链,在休眠期间使用 RC4 (SystemFunction033) 加密模块内存,唤醒时解密
┌─────────────────────────────┐
│ 共享 RWX 区域 │ VirtualAlloc(PAGE_EXECUTE_READWRITE)
│ ├── Entry 代码 │ PicoLoad → 代码在此处
│ ├── Transport 代码 │
│ ├── Task 代码 │
│ └── Obfuscation 代码 │
├─────────────────────────────┤
│ Entry 数据 (RW) │ PicoLoad → 数据在此处(独立分配)
│ Transport 数据 (RW) │
│ Task 数据 (RW) │
│ Obfuscation 数据 (RW) │
├─────────────────────────────┤
│ 核心 PIC(启动后释放) │ 原始 Shellcode,由入口模块释放
└─────────────────────────────┘
共享 RWX 区域是 Ekko 在休眠周期中加密/解密的部分。
所有流量使用 RC4(流密码,16 字节密钥)加密。
发送: [36B agent_id][RC4(payload)][16B key (仅首次回连)]
接收: [36B agent_id][RC4(response)]
src_beacon/Source/
├── main.c 核心 PIC — DFR 解析器、模块加载、引导
├── entry.c 入口 PICO — 代理状态、回连、任务循环、收发
├── transport.c 传输 PICO — 通过 LibWinHttp 的 HTTP POST
├── tasks.c 任务 PICO — whoami/sleep/exit 派发
├── obfuscation.c 混淆 PICO — Ekko 休眠(定时器队列 ROP + RC4)
├── crypto.c RC4 流密码(合并到 entry PICO 中)
├── packer.c 二进制打包器 BE / 解析器 LE(合并到 entry PICO 中)
└── includes/
├── config.h 构建时的定义(UUID、休眠间隔、回调主机/端口/URI/SSL)
├── crypto.h RC4 API
├── packer.h PackBuf / Parser API
├── tcg.h Crystal Palace libtcg(PicoLoad, findModuleByHash 等)
└── HTTP.h LibWinHttp API
| 命令 | ID | 描述 |
|---|---|---|
whoami |
x86_64-w64-mingw32-gcc(MinGW 交叉编译器)./setup.sh --ax ../AdaptixC2
whoami、sleep、exit 命令
| 0x30 |
返回 COMPUTER\用户名 |
sleep <秒数> | 0x20 | 更新回调间隔 |
exit thread|process | 0x10 | 终止代理 |