Toolkit di reverse engineering AI-first: analisi statica, decompilatore SSA, memoria live, provenienza. Sorgente disponibile (PolyForm Noncommercial).
Da un hardware watchpoint in un processo live alla esatta istruzione decompilata che ha modificato il valore.
Gli scanner di memoria trovano l'indirizzo. I decompilatori spiegano il codice. N0xis li collega.
$ n0x provenance trace --pid 9348 --addr 0x7ff68bef3010 --kind write
"function_va": "0x7ff68bef1580", // containing function, auto-resolved
"decompiled_context": [
"rax.2 = (*(uint32_t*)(0x7ff68bef3010) - 0x1);",
"*(uint32_t*)(0x7ff68bef3010) = rax.2;" // ← the statement that moved your value
]
Questo è il hp -= 1; del sorgente, recuperato da un processo in esecuzione — l'indirizzo
sotto watchpoint compare nell'istruzione. Verificato su Windows e Linux.
Una scansione "trova cosa accede a questo" normalmente si ferma a una riga di disassembly grezza, e un decompilatore normalmente non ha alcun input da watchpoint live. Qui le due metà sono unite: il colpo del watchpoint viene risolto attraverso la stessa pipeline SSA che decompila il file.
Binari precompilati per Linux e Windows — ultima release.
curl -LO https://github.com/Structio-labs/N0xis/releases/latest/download/n0xis-linux-x86_64
chmod +x n0xis-linux-x86_64 && ./n0xis-linux-x86_64 --version
Oppure compilalo: cargo build --workspace --release (Windows e Linux; nessun MSVC Build Tools
necessario — rust-toolchain.toml fissa l'host gnu).
Ogni comando stampa un oggetto JSON — inclusi gli errori di argomento: {"ok":true,"data":…,"meta":…} o
{"ok":false,"error":…}. Aggiungi --pretty per leggerlo; il codice di uscita è non-zero in caso di fallimento.
n0x doctor # environment check
n0x profile --file game.exe # triage: sections, exports, engine hints
n0x function discover --file game.exe --pdata # exact .pdata discovery
n0x decomp pseudo --file game.exe --addr 0x140012a00 --style ssa --pretty
n0x provenance trace --pid 4821 --addr 0x1a2b3c40 --kind write --pretty
Gli stessi comandi funzionano su un --pid live, un --file statico, uno --snapshot catturato, o un
processo remoto via SSH. È normale plumbing Unix —
n0x function discover --file game.exe --pdata | jq -r '.data.functions[].va' alimenta il comando
successivo. n0x guide elenca tutti i 113 comandi, generati dal binario così non derivano mai — e un test
fa fallire la build se questo numero cambia.
Da un agente: punta qualsiasi client MCP su n0xis-mcp — 25 tool che restituiscono l'identico
envelope {ok,data,meta}, JSON-RPC su stdio.
{ "mcpServers": { "n0xis": { "command": "/path/to/n0xis-mcp" } } }
--explain: quale sotto-pass ha cambiato cosa, a quale indirizzo), non una risposta black-box..rdata e simboli Itanium
_ZTV), .NET NativeAOT RVA ↔ Namespace.Type.Method, LuaJIT, Bitsquid, IL2CPP —
così un'immagine stripped si legge come sorgente, non come sub_XXXX..n0xt, annotazioni versionate, caching content-addressed,
diffing di funzioni/versioni.Windows e Linux, PE e ELF, una pipeline — file statici, processi live, snapshot e target remoti fluiscono tutti attraverso gli stessi pass e lo stesso JSON versionato.
Non c'è mai nondeterminismo ML nel core. Una GUI desktop vive in un repo separato: n0xis-gui.
Alpha. Ogni affermazione sotto è una misurazione contro una fonte esterna allo strumento — il kernel, le tabelle dell'immagine stessa, o il processo target stesso. Dove non esiste tale fonte, lo dice, perché implementato e verificato non sono la stessa affermazione.
Memoria live, contro un target usa-e-getta che pianta valori noti:
/proc/<pid>/mem, uno sbagliato e corretto. Gli
altri due sono solo per Windows e lo rifiutano dicendolo. Quello sbagliato era scan dissect, che
sceglieva la larghezza di un campo prima del suo allineamento e quindi leggeva una struct quattro byte fuori fase dal
suo primo errore in poi: un campo su sei corretto contro un layout noto dal suo stesso sorgente, cinque
su sei dopo.ui focus correttamente non trova alcuna finestra su un target console; stack backtrace è
solo Linux — l'unico punto in cui l'adapter Linux è avanti.Il decoder, contro un disassembler indipendente — la base su cui tutto il resto poggia, e finora controllato solo dai pass costruiti sopra di esso, che leggono tutti lo stesso stream:
objdump. Tre forme costruite ad hoc esatte,
20 000 istruzioni di una shared library e 20 000 di una DLL di sistema a 32 bit, zero
disaccordi e zero confini che una delle due parti avesse da sola. Ampliato a 60 000 istruzioni
di un binario browser stripped da 334 MB: 2 disaccordi, entrambi dentro una stringa ASCII incorporata
in .text dove il riferimento stesso decodifica (bad) — non è codice, e nessuna delle due letture è
quella giusta.llvm-objdump (le codifiche a larghezza fissa rendono i confini
vacui). Vedi la riga ARM64 sotto.llvm-mc --mattr=+all e da n0xis. 241 entrambi le chiamano istruzione, 304 entrambi le rifiutano —
e 48 (8.0%) sono codifiche riservate che n0xis legge come istruzioni, con 7 (1.2%) vere
istruzioni che rifiuta (per lo più atomiche LSE). Tre delle 48 sono state decodificate a mano e sono
genuinamente UNALLOCATED. Quel divario è tenuto da un bound che fallisce se cresce, e dichiarato
qui invece di essere omesso: una word riservata letta come istruzione trasforma dati in un
programma plausibile.Estensioni delle funzioni, contro la tabella di unwind dell'immagine stessa e la lista di export del linker:
start..end di ogni FDE da objdump --dwarf=frames uguale all'estensione recuperata —
3 787 confrontate su questa macchina (10 + le 3 777 di libc), inizio e fine, esatti; separatamente
misurate a 15 467 e 14 355 su due grandi librerie.