
Agente C2 de Adaptix que utiliza el enlazador PIC Crystal Palace y el sistema de módulos PICO
Un agente de C2 de Adaptix construido con Crystal Palace: un enlazador PIC (Código Independiente de Posición) personalizado y un sistema de módulos PICO. Demuestra cómo construir agentes de shellcode modulares donde cada componente (transporte, tareas, ofuscación) es un blob PICO separado que se carga en tiempo de ejecución.
Este agente no incluye ninguna técnica de evasión y no está pensado para ser utilizado tal cual en operaciones. Es una implementación de referencia para construir agentes con Crystal Palace y el sistema de módulos PICO.
Crystal Palace es un enlazador PIC que toma objetos COFF compilados y produce ejecutables independientes de posición. Conceptos clave:
make pic +gofirst) — El shellcode ejecutable principal. Contiene el código de arranque, el resolvedor DFR y marcadores de sección donde se enlazan los módulos PICO. Es llamado directamente por el cargador.make object) — Blobs de código autocontenidos con sus propias secciones de código y datos. Se cargan en tiempo de ejecución mediante PicoLoad() de libtcg. Cada PICO tiene un punto de entrada (go()) invocable a través de un puntero a función.MODULE$Function (ej. KERNEL32$VirtualAlloc) con llamadas a resolve(mod_hash, func_hash) utilizando hashing ROR13. Sin tabla de importaciones. Todos los argumentos de cadena (nombres de DLL, nombres de funciones) se construyen en la pila como arrays de caracteres para evitar texto plano en el binario.entry_module, transport_module, etc.) mediante la directiva link en el archivo .spec.{LoadLibraryA, GetProcAddress} pasada a PicoLoad() para que los módulos PICO puedan resolver sus propios símbolos DFR.C source → mingw-gcc → COFF objects → Crystal Palace link → raw PIC shellcode → loader (Exe/Dll/Svc)
El archivo .spec define cómo Crystal Palace enlaza todo:
x64:
load "Bin/obj/main.x64.o" # Core PIC
make pic +gofirst
foreach %LIBS: mergelib %_ # Merge libtcg
load "Bin/obj/entry.x64.o" # Entry PICO
make object
load "Bin/obj/crypto.x64.o" # merge crypto into entry
merge
load "Bin/obj/packer.x64.o" # merge packer into entry
merge
export
link "entry_module" # link at section marker
load "Bin/obj/transport.x64.o" # Transport PICO
make object
mergelib "lib/LibWinHttp/..."
export
link "transport_module"
... # task_module, obfuscation_module
dfr "resolve" "ror13" # resolve all DFR symbols
export
Core PIC (main.c)
│
├── resolve() DFR bridge → libtcg hash lookup
├── AllocateAndLoadModule() PicoLoad each PICO into shared RWX region
│
└── calls entry module go() with pointers to all other modules
│
├── Entry Module (entry.c)
│ MvState, checkin, transact (RC4 wire format), task loop
│
├── Transport Module (transport.c)
│ HTTP/HTTPS POST via LibWinHttp
│
├── Task Module (tasks.c)
│ Command dispatch: whoami (0x30), sleep (0x20), exit (0x10)
│
└── Obfuscation Module (obfuscation.c)
Ekko sleep — timer-queue ROP chain that encrypts module memory
with RC4 (SystemFunction033) during sleep, decrypts on wake
┌─────────────────────────────┐
│ Shared RWX Region │ VirtualAlloc(PAGE_EXECUTE_READWRITE)
│ ├── Entry code │ PicoLoad → code here
│ ├── Transport code │
│ ├── Task code │
│ └── Obfuscation code │
├─────────────────────────────┤
│ Entry data (RW) │ PicoLoad → data here (separate alloc)
│ Transport data (RW) │
│ Task data (RW) │
│ Obfuscation data (RW) │
├─────────────────────────────┤
│ Core PIC (freed after boot) │ Original shellcode, freed by entry module
└─────────────────────────────┘
La región RWX compartida es lo que Ekko cifra/descifra durante los ciclos de sueño.
Todo el tráfico está cifrado con RC4 (cifrado de flujo, clave de 16 bytes).
Send: [36B agent_id][RC4(payload)][16B key (first checkin only)]
Receive: [36B agent_id][RC4(response)]
src_beacon/Source/
├── main.c PIC Principal — resolvedor DFR, carga de módulos, arranque
├── entry.c PICO de entrada — estado del agente, checkin, bucle de tareas, transacción
├── transport.c PICO de transporte — HTTP POST mediante LibWinHttp
├── tasks.c PICO de tareas — despacho de whoami/sleep/exit
├── obfuscation.c PICO de ofuscación — sueño Ekko (cola de temporizador ROP + RC4)
├── crypto.c Cifrado de flujo RC4 (fusionado en el PICO de entrada)
├── packer.c Empaquetador binario BE / analizador LE (fusionado en el PICO de entrada)
└── includes/
├── config.h Definiciones en tiempo de compilación (UUID, sueño, host/puerto/uri/ssl de callback)
├── crypto.h RC4 API
├── packer.h PackBuf / Parser API
├── tcg.h Crystal Palace libtcg (PicoLoad, findModuleByHash, etc.)
└── HTTP.h LibWinHttp API
| Command | ID | Description |
|---|
x86_64-w64-mingw32-gcc (compilador cruzado MinGW)./setup.sh --ax ../AdaptixC2
whoami, sleep, exit desde la consola de Adaptix
whoami | 0x30 | Devuelve COMPUTER\username |
sleep <seconds> | 0x20 | Actualiza el intervalo de callback |
exit thread|process | 0x10 | Termina el agente |