
WasmForge — compila programmi Go e C# in eseguibili nativi a singolo binario, sandboxati con WASM, con output polimorfo.
WasmForge compila programmi Go e C# in WebAssembly, poi li impacchetta come singoli binari nativi. Gli eseguibili risultanti isolano il codice guest all'interno di un runtime WASM (un fork per build di wazero). Dall'interno di quel sandbox, i guest ottengono accesso trasparente a networking, socket raw, API Win32 e API dei framework macOS.
Puoi scrivere Go normale usando net.Dial, net.Listen o net/http. Puoi anche migrare un progetto C# .NET Framework esistente. In entrambi i casi, il risultato è un singolo binario che gira su Windows o macOS, senza richiedere all'utente di modificare il codice sorgente guest.

Uno sguardo veloce a questo progetto renderà abbastanza ovvio che è stato sviluppato con un uso INTENSO di LLM. Anche una parte della documentazione lo è stata – ma questa sezione no. Ho fatto del mio meglio per "de-slopificare" questo README e per rendere il processo di utilizzo di WasmForge il più semplice possibile. Inoltre, mentre gli LLM scriveranno documentazione che loda pesantemente i propri risultati, le limitazioni non sono rese ABBASTANZA chiare.
Per impostare correttamente le aspettative: sebbene sia stato testato con molte funzionalità diverse di Go, NON è una soluzione completa per tutti i programmi Go. C'è ancora una percentuale significativa dell'API Win32 che non è supportata correttamente (come le API che richiedono callback thunk). Sliver, ad esempio, funziona per un buon numero di comandi ma NON è una portabilità 1:1 completa. ls, per esempio, mostrerà ancora percorsi con / invece del classico C:\ poiché il blob WASM non è completamente ingannato per rendersi conto di essere all'interno di Windows. Ci sono altre funzionalità che causeranno semplicemente un crash. Assicurati di testare qualsiasi funzionalità che intendi utilizzare prima di provare a usarla su un target reale. Se qualcosa non funziona, prova a costruire l'esempio più basilare dell'API che è rotta e apri un issue / invia una PR.
Il lato C# è più una prova di concetto che una implementazione vera e propria. Il processo utilizzato per compilare C# in WASM è troppo sperimentale e significa che WasmForge spesso deve riscrivere una buona parte del programma comunque per farlo funzionare. Alla fine probabilmente ho dedicato troppo tempo a questa funzionalità e avrei dovuto semplicemente consigliare alle persone di usare un LLM per riscrivere il codice C# come codice Go. Probabilmente è meno doloroso da gestire. Detto questo, il pattern generale C# -> Wasm -> WasmForge FUNZIONA e riesce a bypassare un buon numero di rilevamenti specifici di C#.
A tal proposito – WasmForge è pensato principalmente per gestire rilevamenti STATICI. Il processo di transpilazione supera la maggior parte dei rilevamenti, anche per la scansione in memoria, ma alla fine se il tuo binario ha stringhe molto ovvie come mimikatz o sliver ci sono alcune scansioni in memoria a basso sforzo che causeranno un rilevamento. L'offuscamento automatico delle stringhe sarà probabilmente aggiunto in futuro poiché è una funzionalità abbastanza facile da automatizzare, ma per il primo passaggio non ho voluto aggiungere ulteriore complessità alla pipeline di build per mantenere il debug relativamente semplice.
Sebbene ci siano stati alcuni sforzi per pulire/consolidare il codice sorgente in questo repository, è ancora piuttosto disorganizzato. Ci sono diverse cartelle per diversi processi di test. I test unitari base tendono a trovarsi in examples/ e test/ mentre alcuni test più complessi pensati per essere eseguiti in un ambiente di laboratorio completo vivono in testdata/. Ci sono anche numerosi strumenti solo per sviluppo/test nelle cartelle scripts/ e internal/devtools. Questi saranno necessari solo se stai cercando di impostare il tuo ambiente di test per ulteriori sviluppi. In generale, qualsiasi sviluppo con LLM di qualcosa di così complesso richiede un numero di casi di test molto espliciti per guidare la generazione, altrimenti ti ritrovi con qualcosa che non funziona affatto. Il progetto include questi harness in modo che chiunque sia curioso possa sviluppare ulteriormente gli strumenti o contribuire al progetto.
Spero che la comunità trovi questi strumenti relativamente facili da usare e col tempo continueremo a migliorarli. Forse un giorno la compilazione C# funzionerà davvero come quella Go.
Ci sono tre modi per ottenere wasmforge:
Binario precompilato. Scarica una release dalla pagina Releases – build CLI per Linux, macOS e Windows sono allegate a ogni tag.
Immagine Docker. Per progetti C# / .NET, l'immagine in bundle include ogni
prerequisito (.NET 10 SDK, carico di lavoro NativeAOT-LLVM, WASI SDK 24.0,
wasm-ld, osslsigncode) preinstallato. Costruiscila una volta con
make docker-build e guidala con make docker-run – vedi
docs/CSHARP.md per il flusso di lavoro completo. Questo è il
percorso consigliato per C#.
Compila dal sorgente.
make build
make build rigenera l'archivio embedded internal/build/build_assets.tar.gz
e poi compila la CLI. Se esegui solo go build -o wasmforge ./cmd/wasmforge otterrai un binario funzionante, ma le build in modalità distribuzione
(quando la CLI viene eseguita al di fuori di questo albero dei sorgenti) useranno un archivio
embedded obsoleto. Vedi CONTRIBUTING.md per la spiegazione più lunga.
La directory examples/ contiene programmi Go eseguibili che puoi compilare subito.
Vedi examples/README.md per il menu completo.
GOOS=windows GOARCH=amd64 ./wasmforge build \
--ghost traefik \
-o myapp.exe \
/path/to/your/project
Il bridge API Win32 viene attivato automaticamente ogni volta che GOOS=windows – non devi
più passare --win32-apis per il caso comune.
--ghost traefik sostituisce la distribuzione dei simboli gopclntab embedded per assomigliare al proxy inverso Traefik. Tra i profili in bundle, questo produce il tasso di rilevamento VirusTotal più basso. Altri profili e istruzioni per generarli tuoi si trovano in docs/GHOST-PROFILES.md.
I target Windows vengono automaticamente firmati con un certificato autofirmato per impostazione predefinita. Usa --sign google.com per falsificare il certificato TLS di un dominio, oppure --no-sign per disabilitare completamente la firma.
# Intel
GOOS=darwin GOARCH=amd64 ./wasmforge build -o myapp /path/to/your/project
# Apple Silicon
GOOS=darwin GOARCH=arm64 ./wasmforge build -o myapp /path/to/your/project
Non sono necessari flag aggiuntivi. Il bridge dei framework macOS si attiva automaticamente ogni volta che GOOS=darwin. Vedi docs/MACOS.md per il bridge dei framework, il supporto purego/ObjC e altre note specifiche di Apple.
# Supporto socket raw (richiede CAP_NET_RAW o root al momento della build)
./wasmforge build --raw-sockets -o myapp ./path/to/project
# Output verboso (utile per le prime build)
GOOS=windows GOARCH=amd64 ./wasmforge build --ghost traefik --win32-apis -v -o tool.exe /path/to/project
# VERSIONINFO PE personalizzato (solo Windows)
./wasmforge build --pe-company "Acme Corp" --pe-product "AcmeTool" --pe-file-version "10.0.19041.1" ...
I progetti C# (file .csproj) vengono rilevati automaticamente. WasmForge esegue l'intero pipeline di migrazione, patch e build NativeAOT-WASI in un unico comando:
GOOS=windows GOARCH=amd64 ./wasmforge build --win32-apis -o seatbelt.exe path/to/Seatbelt/Seatbelt/
Per il lavoro C# raccomandiamo vivamente l'ambiente di build Docker. Include tutti i prerequisiti (.NET 10 SDK, carico di lavoro NativeAOT-LLVM, WASI SDK 24.0, wasm-ld) in modo che non sia necessario installarli sull'host. Le istruzioni complete si trovano in docs/CSHARP.md.
wasmforge build [package] Compila un pacchetto Go (o C#) in un binario nativo con sandbox WASM
-o, --output <path> Percorso del binario di output
--ghost <nome> Profilo ghost: traefik, caddy, terraform (vedi docs/GHOST-PROFILES.md)
--raw-sockets Abilita supporto socket raw
--win32-apis Abilita bridge API Win32 (target Windows)
--sign <modalità> Firma il binario: 'self' o nome di dominio (predefinito: self per Windows)
--no-sign Disabilita la firma automatica predefinita per target Windows
--tags <tags> Tag di build Go (separati da virgola)
--pe-company / --pe-product / --pe-description / --pe-copyright / --pe-file-version
Sovrascritture VERSIONINFO PE
-v, --verbose Output di build verboso
wasmforge run [package] Compila ed esegue immediatamente
wasmforge clean Rimuove i GOROOT patchati in cache (~/.wasmforge/cache/)
wasmforge version Stampa la versione
wasmforge dotnet-migrate <dir> Migra un progetto .NET Framework a .NET 10 NativeAOT-WASI
wasmforge dotnet-patch <dir> Applica patch ai sorgenti C# NativeAOT-WASI
WasmForge colma il divario tra WASM e l'host sottostante in modo che i programmi guest non debbano farlo.
API di piattaforma. TCP, UDP, DNS, HTTP, TLS e socket raw funzionano senza modifiche al codice guest sia su Windows che su macOS. Su Windows, WasmForge fa da proxy per l'intera superficie Win32: registro, I/O file, processi, caricamento DLL e SyscallN con fino a 15 argomenti. La traduzione dei puntatori è automatica. Le catene vtable COM vengono rispecchiate in modo che il CLR e altre API COM pesanti funzionino end-to-end. Su macOS, dlopen e dlsym raggiungono qualsiasi framework (Security, CoreGraphics, IOKit e così via), e ebitengine/purego più il runtime Objective-C funzionano out of the box.
Hosting .NET e migrazione. Il CLR si carica attraverso la catena standard (CoInitializeEx, CLRCreateInstance, Load_3, Invoke_3). AMSI viene patchato all'avvio in modo che Assembly.Load(byte[]) non blocchi strumenti noti. Un pipeline separato NativeAOT-WASI prende progetti .NET Framework esistenti e produce singoli binari PE Windows senza bisogno del runtime .NET sul target.
Memoria host e shellcode. Un proxy di memoria host basato su VirtualAlloc è raggiungibile dall'interno del guest. Ciò rende possibile l'esecuzione di loader COFF/BOF e shellcode senza uscire dal sandbox WASM.
Yield cooperativo. API Win32 bloccanti (Sleep, WaitForSingleObject, ReadFile e simili) non congelano le goroutine WASM. L'host invia la chiamata su una goroutine in background e segnala al guest di fare yield fino a quando il risultato non è pronto.
Output polimorfo. Ogni build produce un binario strutturalmente unico. Gli opcode WASM vengono permutati, gli ID delle sezioni e i magic byte sono randomizzati, e ogni identificatore, import PE, stringa VERSIONINFO, blocco di licenza e nome del file sorgente viene cancellato. Il fork di wazero in bundle viene riscritto per corrispondere al bytecode permutato. Il ghost profiling riscrive i simboli gopclntab per corrispondere a veri binari Go enterprise (Traefik, Caddy, Terraform). Gli output Windows sono firmati Authenticode per impostazione predefinita, autofirmati o falsificando il certificato TLS di un dominio reale tramite osslsigncode.
+-------------------- Guest WASM (wasip1) --------------------+
| |
| Il tuo programma Go (net, net/http, os; funziona in modo trasparente) |
| |
+----------- ABI go:wasmimport (opcode personalizzati) -------+
|
+----------- Runtime host (fork di wazero per build) ---------+
| |
| 90+ funzioni host (networking, proxy OS, API di piattaforma) |
| Windows: traduzione puntatori, memoria shadow, mirroring COM |
| macOS: bridge framework dlopen/dlsym, trampolini ABI |
| |
+----------- wazero (VM personalizzata: opcode/magic permutati) ------+
|
Kernel OS / API Windows / Framework macOS
Il pipeline di build si compone di sei fasi.
syscall/ e net/ per networking WASM. Viene cachato in ~/.wasmforge/cache/.GOOS=wasip1 GOARCH=wasm contro la stdlib patchata. Gli stub automatici coprono le lacune specifiche della piattaforma. Gli sysshim per golang.org/x/sys e ebitengine/purego vengono iniettati quando tali import sono presenti.main.go polimorfo con identificatori randomizzati, un fork di wazero per build corrispondente, risorse PE incorporate e -trimpath.osslsigncode.WasmForge compila ed esegue progetti Go di terze parti non modificati, inclusi quelli con codice complesso specifico della piattaforma.
Programmi .NET NativeAOT-WASI:
Vedi docs/BUILDING-SLIVER.md per un tutorial passo-passo su Sliver e docs/CSHARP.md per il pipeline C#.
WasmForge gira su host di build Linux, macOS o Windows. È richiesto Go 1.25 o successivo.
Alcune funzionalità necessitano di configurazione aggiuntiva. I socket raw richiedono CAP_NET_RAW o root. Il bridge Win32 richiede un target Windows con --win32-apis (altri target restituiscono ENOSYS). Il bridge dei framework macOS richiede un target macOS e viene rilevato automaticamente da GOOS=darwin. La firma del codice richiede osslsigncode nel PATH. I progetti C# richiedono .NET 10 SDK, il carico di lavoro NativeAOT-LLVM e WASI SDK 24.0. In alternativa, l'immagine Docker in bundle (coperta in docs/CSHARP.md) include tutti questi prerequisiti preinstallati.
L'harness di test di parità (test/parity/) e gli script di lab plant in scripts/lab-setup/ assumono inoltre un intervallo Active Directory configurato con Ludus che esegue GOAD (Game of Active Directory) – ogni valore predefinito sevenkingdoms.local / kingslanding / SEVENKINGDOMS-CA è un valore predefinito di GOAD, sovrascrivibile tramite variabili d'ambiente WASMFORGE_PARITY_* (vedi test/parity/internal/lab/lab.go). Vedi docs/internals/PARITY-HARNESS.md e docs/internals/LAB-STABILITY.md per la configurazione completa del laboratorio.
Inizia da qui
Approfondimenti
Riferimenti per i manutentori
Concesso in licenza sotto Apache License, Version 2.0. Vedi LICENSE e NOTICE per i dettagli.
Copyright (c) 2025-2026 Praetorian Security, Inc.
| Programma | Piattaforma | Descrizione | Validato |
|---|
| Sliver | Windows | Framework C2, uso intenso di Win32 | Beacon HTTPS, whoami, ps, netstat, execute-assembly (Rubeus, Seatbelt) |
| Sliver | macOS | Framework C2 (beacon + session) | pwd, ls, download, execute, proxy SOCKS5 |
| go-clr | Windows | Hosting CLR .NET + esecuzione assembly | Catena di caricamento CLR, triage Rubeus, scansione sistema Seatbelt |
| Chisel | Windows | Tunnel TCP/UDP su HTTP con SOCKS5 | Connettività tunnel, forwarding proxy |
| Ligolo-ng | Windows | Tunneling avanzato e pivoting | Interfaccia TUN, connettività agente |
| goffloader | Windows | Loader COFF/BOF con unsafe.Pointer | VirtualAlloc, esecuzione shellcode, parsing PE, risoluzione IAT |
| Programma | Piattaforma | Descrizione | Validato |
|---|
| Seatbelt | Windows | Enumerazione di sicurezza | La maggior parte dei comandi passa; alcuni che richiedono WMI / callback Defender sono mantenuti con stub onesti in attesa del supporto del bridge. |
| Rubeus | Windows | Strumenti Kerberos | Le operazioni di hash e token funzionano direttamente; i verbi di rete (asktgt, kerberoast, asreproast) passano attraverso il bridge TCP; le query LSA (klist, logonsession) corrispondono ai baseline nativi. |
| Argomento | Documento |
|---|
| Esempi eseguibili (scanner TCP, server HTTP, ping ICMP) | examples/README.md |
| Costruzione di Sliver end-to-end (Windows + macOS) | docs/BUILDING-SLIVER.md |
| Compilazione di progetti C# / .NET (flusso Docker) | docs/CSHARP.md |
| Target macOS e bridge dei framework | docs/MACOS.md |
| Utilizzo dei profili ghost e costruzione di profili personalizzati | docs/GHOST-PROFILES.md |
Variabili d'ambiente di build (ricetta R80, ogni opzione WASMFORGE_*) | docs/ENVIRONMENT.md |
| Argomento | Documento |
|---|
| Architettura — modulo host, pipeline di build, decisioni progettuali | docs/ARCHITECTURE.md |
| Contribuire — organizzazione del repo, prerequisiti, aggiunta di funzioni host | CONTRIBUTING.md |
| Politica di sicurezza + divulgazione | SECURITY.md |
| Codice di condotta | CODE_OF_CONDUCT.md |
| Argomento | Documento |
|---|
| Contratto API host — export registrati, stabilità delle firme | docs/internals/HOST-API-CONTRACT.md |
| Interni del patcher AST — regole di sostituzione stringhe e dispatch | docs/internals/AST-PATCHER.md |
| Harness di parità — esecuzione di differenze C# nativo vs WASM | docs/internals/PARITY-HARNESS.md |
| Stabilità del laboratorio — configurazione range Ludus + GOAD, script watchdog | docs/internals/LAB-STABILITY.md |