
Agente C2 Adaptix usando Crystal Palace PIC linker e sistema de módulos PICO
Um agente C2 para Adaptix construído com Crystal Palace — um linker PIC (Position Independent Code) personalizado e sistema de módulos PICO. Demonstra como construir agentes shellcode modulares onde cada componente (transporte, tarefas, ofuscação) é um blob PICO separado carregado em tempo de execução.
Este agente não inclui nenhuma técnica de evasão e não deve ser usado como está em operações reais. É uma implementação de referência para construir agentes com Crystal Palace e o sistema de módulos PICO.
Crystal Palace é um linker PIC que pega objetos COFF compilados e produz executáveis independentes de posição. Conceitos-chave:
make pic +gofirst) — O shellcode executável principal. Contém o código de bootstrap, o resolvedor DFR e os marcadores de seção onde os módulos PICO são linkados. Chamado diretamente pelo loader.make object) — Blobs de código autocontidos com suas próprias seções de código e dados. Carregados em tempo de execução via PicoLoad() da libtcg. Cada PICO tem um ponto de entrada (go()) chamável por ponteiro de função.MODULE$Function (ex.: KERNEL32$VirtualAlloc) por chamadas a resolve(mod_hash, func_hash) usando hash ROR13. Sem tabela de importação. Todos os argumentos string (nomes de DLL, nomes de função) são construídos na pilha como arrays de char para evitar texto puro no binário.entry_module, transport_module, etc.) através da diretiva link no arquivo .spec.{LoadLibraryA, GetProcAddress} passada para PicoLoad() para que os módulos PICO possam resolver seus próprios símbolos DFR.Código fonte C → mingw-gcc → objetos COFF → link do Crystal Palace → shellcode PIC raw → loader (Exe/Dll/Svc)
O arquivo .spec define como o Crystal Palace linka tudo:
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() Ponte DFR → consulta de hash da libtcg
├── AllocateAndLoadModule() PicoLoad para cada PICO em região RWX compartilhada
│
└── chama entry module go() com ponteiros para todos os outros módulos
│
├── Módulo de Entrada (entry.c)
│ MvState, checkin, transact (formato de fio RC4), loop de tarefas
│
├── Módulo de Transporte (transport.c)
│ HTTP/HTTPS POST via LibWinHttp
│
├── Módulo de Tarefas (tasks.c)
│ Distribuição de comandos: whoami (0x30), sleep (0x20), exit (0x10)
│
└── Módulo de Ofuscação (obfuscation.c)
Sleep Ekko — cadeia ROP de fila de temporizadores que criptografa a
memória do módulo com RC4 (SystemFunction033) durante o sono,
descriptografa ao acordar
┌─────────────────────────────┐
│ 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
└─────────────────────────────┘
A região RWX compartilhada é o que o Ekko criptografa/descriptografa durante os ciclos de sono.
Todo o tráfego é criptografado com RC4 (cifra de fluxo, chave de 16 bytes).
Envio: [36B agent_id][RC4(payload)][16B key (apenas no primeiro checkin)]
Recepção: [36B agent_id][RC4(response)]
src_beacon/Source/
├── main.c Core PIC — resolvedor DFR, carregamento de módulos, bootstrap
├── entry.c Entry PICO — estado do agente, checkin, loop de tarefas, transact
├── transport.c Transport PICO — HTTP POST via LibWinHttp
├── tasks.c Task PICO — distribuição whoami/sleep/exit
├── obfuscation.c Obfuscation PICO — sleep Ekko (cadeia ROP de fila de temporizadores + RC4)
├── crypto.c Cifra de fluxo RC4 (mesclada no Entry PICO)
├── packer.c Packer binário BE / parser LE (mesclado no Entry PICO)
└── includes/
├── config.h Definições em tempo de compilação (UUID, sleep, host/port/uri/ssl de callback)
├── crypto.h API RC4
├── packer.h API PackBuf / Parser
├── tcg.h libtcg do Crystal Palace (PicoLoad, findModuleByHash, etc.)
└── HTTP.h API LibWinHttp
| Comando | ID | Descrição |
|---|
x86_64-w64-mingw32-gcc (compilador cruzado MinGW)./setup.sh --ax ../AdaptixC2
whoami, sleep, exit a partir do console do Adaptix
whoami | 0x30 | Retorna COMPUTADOR\usuário |
sleep <segundos> | 0x20 | Atualiza o intervalo de callback |
exit thread|process | 0x10 | Encerra o agente |