
Implant y C2 multiplataforma impulsados por syscalls — syscalls directas (Win), syscalls en crudo (Linux), canales HTTPS/DNS/ICMP. Sin capa winapi.
Cero WinAPI. Cada primitiva NT se resuelve en tiempo de ejecución desde ntdll en memoria —
las instrucciones SYSCALL se emiten directamente mediante stubs de ensamblador Plan9, sin tabla de importaciones,
sin tocar los hooks de ntdll en modo usuario. C2 sobre HTTPS / DNS / ICMP, AES-256-GCM por
mensaje. Windows nativo. Compilaciones para Linux. Compilaciones para macOS.
Esto no es una librería de envoltura de syscalls. Es un framework de implante completo donde
cada operación — desde inyectar código hasta leer archivos o persistir en el
registro — pasa por syscalls Nt* en crudo resueltas al arrancar desde la tabla de exportación
de ntdll actual. No existen llamadas a WinAPI en el binario. Nada que un EDR
pueda enganchar en modo usuario.
B8 xx xx 00 00 0F 05 (directo) o
4C 8B D1 B8 xx xx 00 00 0F 05 (Hells Gate). Cada nombre de función se
hashea en tiempo de compilación — sin cadenas en texto plano en el binario.asm_amd64.s) carga el SSN en EAX,
establece 7 argumentos a mano, ejecuta SYSCALL. Retorno vía RAX/RDX.0F 05 C3 (syscall;ret) dentro de
ntdll, llama a través de él. La trampa de CPU aterriza dentro de ntdll — la pila de llamadas
muestra frames de ntdll, no frames del implante. Ningún hook de modo usuario sobrevive..text como RWX, copia los bytes originales desde el ntdll
mapeado en disco, restaura la protección, vacía la icache, aniquila la caché de SSN.
Cada hook de modo usuario colocado por cualquier EDR desaparece.El agente rota automáticamente entre técnicas de inyección. Cada llamada usa un método diferente — dos inyecciones nunca se ven iguales en forense.
Ejecuta todas las comprobaciones, devuelve un informe de amenaza puntuado. Auto-destrucción en Crítico.
Todo vía syscalls Nt*, sin WinAPI.
EnablePrivilege(index) — establece cualquier privilegio por LUIDEnableAllTokenPrivileges() — 20 privilegios a la vez (Debug, Impersonate, TCB, Backup, Restore, etc.)GetProcessTokenIntegrityLevel() — consulta la integridad obligatoriaStealProcessToken(pid) — abre + duplica el token de otro procesoImpersonateThread() / RevertToSelf()EnumVirtualMemory() — recorre todas las regiones virtuales vía NtQueryVirtualMemoryFindWritableExecRegions() — encuentra regiones comprometidas PAGE_EXECUTE_READWRITEHideRegion() — establece PAGE_NOACCESS para ocultar memoria de los escáneresUnhideRegion() — restaura la protección originalNtCreateFile → NtReadFile / NtWriteFile → NtClose. Cero llamadas a CreateFileA,
ReadFile, WriteFile o DeleteFileW. ReadFileContents(),
WriteFileContents(), DeleteFileNt(), FileExists().
NtCreateKey → NtSetValueKey. AddRunKeyPersistence(), RemoveRunKeyPersistence().
Sin RegCreateKeyEx, RegSetValueEx ni ninguna llamada a Advapi32.
EnumerateSystemHandles() — todos los handles abiertos en el sistema vía
NtQuerySystemInformation(SystemHandleInformation)FindEDRHandles() — compara los PIDs propietarios contra 30+ nombres de procesos EDR
conocidos (MsSense, CrowdStrike, Sentinel, Cylance, Carbon Black, etc.)CloseEDRHandles() — cierra los handles de monitorización que el EDR colocó en tu
procesoIsProcessMonitored() — comprobación booleana: ¿estamos siendo vigilados?NtFreeVirtualMemory.PatchAMSI() — AmsiScanBuffer → MOV EAX, 0; RETPatchETW() — EtwEventWrite → RETPatchNtTraceEvent() — NtTraceEvent → RETPatchDbgUiRemoteBreakin() — breakin de hilo → RETPatchInstrumentationCallbacks() — ThreadHideFromDebuggerTodos los canales implementan la interfaz Channel. Añadir NTP, DoH o TURN
significa implementar la interfaz — cero cambios en el agente.
AEAD AES-256-GCM por mensaje. Nonce único de 12 bytes por mensaje. Llavero por implante. Derivación de clave basada en passphrase disponible. 3 tests, todos pasando.
voidsyscall/
syscallwin/ Direct/indirect NT syscalls + evasion
asm_amd64.s Syscall/IndirectSyscall/ReadGSBase/SetGSBase/asm_cpuid/asm_rdtsc
resolve.go PEB→LDR→ntdll walk, PE export parse, SSN cache, prologue scan
stubs.go ~25 Nt* wrappers, DirectSyscall, IndirectSyscallByHash
hash.go djb2 hash (string + UTF-16 pointer)
constants.go MEM_*, PAGE_*, THREAD_*, TOKEN_*, OBJ_*, REG_*, FILE_*, STATUS_*
unhook.go UnhookNtdll, SelfDel
peb.go PEB patching (BeingDebugged, NtGlobalFlag, Heap, DebugPort)
token.go Privilege escalation, token theft, impersonation
vad.go VAD enumeration, hide/unhide regions
files.go File I/O via Nt* syscalls
registry.go Registry persistence via Nt* syscalls
fingerprint.go SSN dump, build fingerprint, hex export/import
inject_advanced.go 4 injection methods: section mapping, hollow, APC, module stomp
antianalysis.go VM/sandbox/debug/timing detection, scored threat report
handles.go System handle enumeration, EDR handle killer
memcrypt.go Vault (re-keying XOR), SecureDelete, StackEncrypt, WipeMemory
syscallnix/ Linux/darwin raw syscalls
patches/ AMSI, ETW, NtTraceEvent, DbgUiRemoteBreakin, InstrumentationCallbacks
loader/ CreateThread/APC/module-stomp injection
channels/ HTTP, DNS (TXT), ICMP — Channel interface
crypto/ AES-256-GCM, envelope, passphrase variant (3 tests)
server/ SessionManager, Task Queue, interactive REPL
agent/ Config, beacon loop, 10 task handlers
cmd/server/main.go CLI with REPL
cmd/agent/main.go Windows-only entrypoint
GOOS=windows GOARCH=amd64 go build -ldflags="-s -w" -o voidsyscall-agent.exe ./cmd/agent
GOOS=windows GOARCH=amd64 go build -ldflags="-s -w" -o voidsyscall-server.exe ./cmd/server
GOOS=linux GOARCH=amd64 go build -ldflags="-s -w" -o server-linux ./cmd/server
GOOS=darwin GOARCH=arm64 go build -ldflags="-s -w" -o server-darwin ./cmd/server
Ofuscación con garble:
GOOS=windows GOARCH=amd64 garble -literals -tiny build -ldflags="-s -w" \
-o voidsyscall-agent.exe ./cmd/agent
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes
./voidsyscall-server.exe --cert cert.pem --key key.pem --https-port 443
./voidsyscall-agent.exe -c agent/example-config.json
ReadGSBase (asm) → GS:[0x60] → TEBLdrInMemoryOrderModuleList → coincidir ntdll.dll vía hash djb2IMAGE_DOS_HEADER → e_lfanew → IMAGE_NT_HEADERS → DataDirectory[0] = Tabla de ExportaciónAddressOfNames[], djb2 cada uno, coincidir objetivoAddressOfFunctions[ordinal] → dirección de funciónB8 xx xx 00 00 0F 05 (directo), B8 xx xx 00 00 C3 (early-ret), o 4C 8B D1 B8 xx xx 00 00 0F 05 (Hells Gate)Sin nombres de funciones en el binario. Solo hashes djb2. La instrucción syscall
evita cada hook de modo usuario.
TaskShell // exec via cmd.exe
TaskInject // polymorphic: section/hollow/APC/stomp
TaskPatch // AMSI/ETW/both
TaskEvasion // PEB patches + VM/sandbox/debug/timing detection
TaskHandles // enumerate + kill EDR monitoring handles
TaskFingerprint // dump SSN build fingerprint
TaskToken // privilege escalation + impersonation
TaskVault // encrypted in-memory storage
TaskSleep // jitter-aware sleep
TaskExit // clean shutdown
Entregado: Bucle de beacon, cola de tareas, 3 canales C2, 4 métodos de inyección,
10+ comprobaciones de evasión, enumeración/cierre de handles, manipulación de tokens, operaciones de VAD,
E/S de archivos, persistencia en el registro, huella de SSN, cifrado de memoria,
parcheo de AMSI/ETW, criptografía AES-GCM, gestión de sesiones, REPL interactivo.
3 tests de criptografía pasan. go build limpio en Windows.
Aún no: Agente autónomo para Linux (existen compilaciones, sin lógica de agente), rotación de claves de sesión, loader por etapas, canales NTP/DoH, programación de persistencia.
MIT — LICENSE
| Método | Cómo funciona | Por qué es sigiloso |
|---|
| Mapeo de sección | NtCreateSection → NtMapViewOfSection (remoto) → NtCreateThreadEx | Sin asignación RWX en el VAD. La sección está respaldada por archivo. Los escáneres de memoria ven PAGE_EXECUTE_READ, no PAGE_EXECUTE_READWRITE. |
| Process hollow | NtCreateUserProcess (suspendido) → NtSuspendProcess → base de imagen a cero → asignar + escribir shellcode → NtSetContextThread (RIP = shellcode) → NtResumeProcess | El proceso aparece como un svchost.exe legítimo en el taskmgr. Solo difiere el contenido de la memoria. |
| Encolado de APC | Enumerar hilos vía NtQuerySystemInformation → NtOpenThread → NtQueueApcThread | No se crea un hilo nuevo. Sin TEB nuevo. Sin asignación de pila nueva. Se dispara cuando el hilo entra en espera alertable. |
| Module stomping | Asignar en el objetivo → escribir cabecera PE mínima + shellcode → NtCreateThreadEx en el punto de entrada | La lista de módulos muestra un nombre de DLL plausible. La cabecera PE es lo suficientemente válida para engañar a la enumeración de módulos. |
| Comprobación | Método |
|---|
| Detección de VM | Escaneo de firma de hipervisor CPUID leaf 0x40000000 (VMware, VirtualBox, Hyper-V, KVM, Xen, QEMU, Parallels) + fallback leaf 0x40000001 |
| Detección de sandbox | Recuento de CPU, artefactos de registro (VMware Tools, VBox Guest Additions, servicios VMware/VBox), escaneo de procesos de sandbox (30+ nombres conocidos: wireshark, procmon, x64dbg, ida, etc.) |
| Detección de depurador | PEB.BeingDebugged, PEB.NtGlobalFlag, flags de depuración del heap, ProcessDebugPort, ProcessDebugObjectHandle, ProcessDebugFlags, breakpoints de hardware DR0-7, comprobación de single-step por temporización |
| Anomalía de temporización | Basado en RDTSC: 50 muestras de latencia de NtQuerySystemInformation, media/desviación estándar, marca si >10% de las muestras exceden 3σ de varianza. Detecta la sobrecarga de instrumentación. |
| Evasión de PEB | Parchea BeingDebugged, NtGlobalFlag, flags de ProcessHeap, DebugPort, ThreadHideFromDebugger — todo vía lecturas del segmento GS + NtWriteVirtualMemory. Sin llamadas a API. |
| Canal | Formato en el cable | Requisitos |
|---|
| HTTPS | POST binario, framing personalizado, UA/ruta aleatorizados | certificado TLS |
| DNS | subdominio <idx>-<total>-<base32>, respuesta TXT | resolución DNS |
| ICMPv4 | payload en ID+seq de echo request/reply | socket crudo (root/Admin) |
| Tarea | Byte | Payload |
|---|
| shell | 0x01 | comando UTF-8 |
| inject | 0x02 | PID (4 bytes LE) + shellcode |
| patch | 0x03 | 0x01=AMSI, 0x02=ETW, 0x03=ambos |
| sleep | 0x04 | segundos (4 bytes LE) |
| evasion | 0x10 | 0x01=completo, 0x02=VM, 0x03=sandbox, 0x04=debug, 0x05=timing, 0x06=informe |
| handles | 0x11 | 0x01=contar, 0x02=enumerar EDR, 0x03=cerrar EDR, 0x04=¿monitorizado? |
| vault | 0x12 | operaciones de almacenamiento cifrado |
| fingerprint | 0x13 | volcar huella de compilación de SSN |
| token | 0x14 | 0x01=habilitar todo, 0x02=integridad, 0x03=privilegio debug, 0x04=impersonar |
| exit | 0xFF | — |
map[uint32]uint16