
Plugin per BianryNinja che identifica vulnerabilità nei binari decompilati, con scansioni programmatiche e supporto LLM.
Ricerca di vulnerabilità assistita da LLM per Binary Ninja.
VulnFanatic-NG aggiunge un pannello laterale che analizza il binario corrente e chiede a un LLM — un modello compatibile con OpenAI ospitato localmente per impostazione predefinita, oppure Anthropic Claude, Google Gemini o Azure OpenAI (vedi Backend LLM) — di stabilire se il codice sospetto è davvero vulnerabile. Funziona principalmente dall'output del decompilatore (HLIL) di Binary Ninja, ripiegando sull'assembly quando necessario, e segnala solo problemi confermati con riferimenti cliccabili al codice.
Una scansione viene eseguita in un massimo di tre fasi (la Fase 3 è opzionale e solo online):
Trova i punti di chiamata delle funzioni pericolose definite in
rules/phase1_rules.json — strcpy,
memcpy, sprintf/stringhe di formato, system, alloca, scanf, API
di comandi/exec, RNG debole, la famiglia free/delete (use-after-free / double-free),
letture di input non attendibile in buffer a dimensione fissa (recv/read/fread/ReadFile),
iniezione SQL (sqlite3_exec/mysql_query/PQexec), verifica dei certificati TLS
disabilitata (SSL_CTX_set_verify/curl), SSRF e gestione impropria
dei privilegi (setuid/setresgid), la famiglia memset/bzero e
confronti con una lunghezza controllata dall'attaccante (memcmp/strncmp →
bypass dell'autenticazione), in C/C++, Win32 e (per quanto possibile) Rust FFI. La copertura
include le varianti fortificate _chk (FORTIFY) e quelle _s dell'Annex K. Le funzioni
di output formattato limitato (snprintf e varianti) hanno una propria regola
sicura di default, così un argomento di dimensione corretto non viene segnalato come overflow. I punti di chiamata vengono
trovati in tre modi: chiamate dirette ai simboli nominati; chiamate instradate attraverso
thunk di forwarding / stub PLT (i chiamanti reali vengono recuperati, quindi un import
raggiunto solo tramite stub non viene perso); e — a meno che
vulnfanatic.scanIndirectCalls sia disattivata — chiamate indirette inviate attraverso un
puntatore a funzione o vtable che Binary Ninja ha risolto a una funzione pericolosa.
Per ogni punto di chiamata costruisce un contesto interprocedurale, incentrato sul decompilatore,
limitato a un budget di token (default 100k):
__*_chk e quelle con controllo dei limiti *_s hanno argomenti iniziali
aggiuntivi, spostando la posizione di formato/dimensione/destinazione,s->buf
si risolve nella dimensione reale dell'array del campo piuttosto che nella dimensione del puntatore di s;
anche le definizioni di struct nella sezione dei tipi riportano le dimensioni in byte per campo,0x40
o limitata a [0, 0xff]), che il modello usa come riferimento reale quando confronta una
dimensione con la capacità di un buffer invece di fare supposizioni,vulnfanatic.includeStackLayout),if/loop/ che proteggono la chiamata),Questo contesto, insieme a un prompt specifico per la regola, viene inviato al modello, che restituisce un verdetto strutturato. I non-problemi vengono scartati. I prompt sono ottimizzati per un modello di codice locale potente (ad es. Qwen2.5-Coder) e gli chiedono di analizzare l'intero flusso e di emettere solo JSON.
Al modello viene chiesto di privilegiare il recall — segnalare problemi plausibili e rilevanti per la sicurezza ed esprimere l'incertezza attraverso una Confidence piuttosto che scartare ciò che non può dimostrare completamente. Mostra il suo lavoro in uno scratchpad che cita i frammenti di codice verbatim su cui si è basato (la sorgente di input, ogni guardia, la dimensione/lunghezza, il tipo rilevante e il sink), che viene salvato sulla segnalazione così puoi verificare il ragionamento.
Ogni segnalazione ha una Confidence (alta/media/bassa): alta = l'intera catena è mostrata
nel contesto; media = probabile, con uno o due collegamenti dedotti; bassa = una pista
che merita una revisione manuale. Questa è la metrica principale (la stima della severità del modello è
un campo secondario). Imposta vulnfanatic.minConfidence per scartare tutto ciò che è sotto una soglia.
Per impostazione predefinita VulnFanatic-NG privilegia il recall (trovare i problemi reali). Se ricevi troppi falsi positivi, puoi stringere con una delle seguenti opzioni:
vulnfanatic.validationPass (default disattivata) — esegue un secondo passaggio LLM che
ricontrolla ogni problema segnalato contro lo stesso contesto (verificando i frammenti dello
scratchpad e ripercorrendo il flusso) e può correggere il verdetto o la confidenza.
Raddoppia le chiamate LLM per i candidati segnalati.
vulnfanatic.validatorModel (più validatorProvider / validatorBaseUrl /
validatorApiKey) per eseguire il secondo passaggio su un modello diverso. Una seconda
opinione è molto più utile da un modello indipendente — condivide meno punti ciechi
ed è molto meno propensa ad approvare acriticamente il primo verdetto (i modelli tendono a
preferire le proprie risposte). Un buon pattern è una cascata: un modello veloce come
analista (recall ampio) e il tuo modello più forte come validatore, che gira solo
sui candidati segnalati. Lascia vuoto il modello validatore per validare con il
modello analista. Il validatore dovrebbe essere almeno capace quanto l'analista — uno
più debole aggiunge per lo più falsi rifiuti. Tutto tranne provider/URL base/chiave/
modello viene ereditato dalle impostazioni di connessione dell'analista; una chiave del validatore vuota
riusa la chiave dell'analista; e se l'endpoint del validatore non è raggiungibile, il primo
verdetto viene mantenuto (la segnalazione non viene mai persa a causa di un'interruzione del validatore).vulnfanatic.minConfidence (default low) — alza a / per segnalare
solo segnalazioni più solide.Velocità. La maggior parte della latenza per chiamata è data dal ragionamento scritto, quindi
vulnfanatic.verdictReasoning controlla quanto scrive il modello:
concise (default) — una breve motivazione di 1–3 frasi, senza codice verbatim. Molto
più veloce di full con poca perdita di accuratezza; puoi anche abbassare
vulnfanatic.maxResponseTokens.full — lo scratchpad dettagliato con frammenti citati (il più verificabile, il più lento).none — solo il verdetto. Il più veloce; abbinalo a un backend in grado di ragionare
(vulnfanatic.reasoningEffort) così il pensiero interno del modello fa il lavoro.
Su un modello locale semplice none perde accuratezza (nessuna chain-of-thought).Funzionalità di precisione di supporto sempre attive (informano il modello senza sopprimere le segnalazioni):
_s (Annex K) e
_chk (FORTIFY) e le API con lunghezza limitata come sicure, a meno che l'argomento
della dimensione stesso sia sbagliato.Il pulsante Scan Offline esegue la Fase 1 senza modello — euristiche puramente programmatiche
dichiarate nel blocco offline di ogni regola in phase1_rules.json. Segnala
i punti di chiamata pericolosi ed elimina quelli evidentemente sicuri, assegnando una
Confidence euristica:
memcpy/memmove con lunghezza costante, uno
strcpy da una stringa costante, un printf con formato costante, un system
con un comando costante, ecc. — chiamate il cui argomento determinante è una costante
a tempo di compilazione e quindi non può essere controllato dall'attaccante. "Costante" include valori che
l'analisi value-set di Binary Ninja ha fissato a un numero a monte, non solo
argomenti letterali.strlen/dimensione,
if (len < …)) da qualche parte nel flusso — incluse le funzioni chiamate lungo il percorso — quindi potrebbe essere già gestito. (Un ramo che
menziona semplicemente la variabile senza confrontarla non conta più, eliminando una
fonte di declassamenti spuri.)Le euristiche usano un piccolo vocabolario dichiarativo nelle regole
(constant_safe_args, eliminate_if_all_args_constant, format_arg_lookup,
length_guard_vars, base_confidence, skip) valutato da predicati Python —
nessun codice incorporato da passare a exec. La maggior parte delle regole ha una definizione offline (overflow,
format-string, command-exec, scanf, gestione dei percorsi, RNG debole, parsing numerico debole,
modifiche dei privilegi, dimensione delle allocazioni, …). Solo le due categorie che richiedono davvero
analisi semantica vengono saltate offline e lasciate all'LLM: la famiglia free/delete
(use-after-free / double-free, che richiede il tracciamento del ciclo di vita dei puntatori) e la verifica
TLS (il bug è un valore costante specifico come SSL_VERIFY_NONE). Il
riepilogo offline riporta quanti siti sono stati segnalati / eliminati / saltati (richiedono
l'LLM) / non riusciti, così i conteggi tornano. Questo è un triage rapido; per un giudizio reale — e
per le categorie saltate — esegui la scansione LLM completa.
Le segnalazioni offline costruiscono comunque lo stesso contesto interprocedurale completo che una scansione
online invierebbe (solo per i siti segnalati) e lo memorizzano, così una volta che le hai triagate
possono essere esportate come dati di fine-tuning proprio come le segnalazioni online. Disattiva con
vulnfanatic.offlineBuildContext se vuoi la massima velocità offline.
Viene eseguita solo quando il binario sembra avere simboli / nomi di variabile reali. Individua
le funzioni sensibili alla sicurezza definite in
rules/phase2_rules.json —
autenticazione, crittografia (incl. algoritmi deboli), verifica di firme/certificati,
gestione di sessioni/token, controllo degli accessi, gestione di segreti/chiavi,
validazione dell'input, confronto di segreti non a tempo costante e
deserializzazione non sicura — abbinate per nome di funzione e stringhe referenziate, poi controllate
dal modello.
Un audit di hardening del firmware contro attacchi a iniezione di guasti (glitch di tensione/clock/EM)
e side-channel (timing/power), basato sulle linee guida per la mitigazione degli attacchi hardware.
A differenza delle Fasi 1–2 (che trovano bug), la Fase 3 segnala un controllo di
hardening mancante o violato su una funzione critica per la sicurezza — ad esempio:
rami default-fail, decisioni di sicurezza a doppio controllo, validazione del contatore post-loop,
costanti di stato ad alta distanza di Hamming (invece di semplici 0/1), confronto di segreti a tempo costante su tutta la lunghezza,
accesso/cancellazione dei segreti con offset randomizzato, encrypt-then-verify (anti-DFA), contatori di integrità del flusso di controllo, evitare la crittografia
in spazio utente e non gestire direttamente materiale chiave grezzo
(rules/phase3_rules.json).
Poiché le ottimizzazioni del compilatore possono rimuovere le protezioni a livello di sorgente, questi controlli vanno verificati al meglio sul binario compilato — esattamente ciò che questo controllo fa. La Fase 3 è solo LLM (online), gated dai simboli e disattivata per impostazione predefinita; abilitala per scansione con la casella Phase 3 nella scheda New Scan (non viene mai eseguita in modalità offline).
Le segnalazioni sono elencate in una tabella (stato, confidenza, fase, CWE, funzione, indirizzo, titolo) con un pannello dei dettagli che mostra la spiegazione, lo scratchpad di analisi e le note di validazione. Fai doppio clic su una riga per navigare nella vista binario fino al codice.
Ogni segnalazione inizia come Untriaged. Fai clic con il tasto destro su una riga per impostarne lo stato — Mark as Real Issue, Mark as False Positive o Mark as Untriaged. Ogni cambio di stato apre una finestra di testo "Provide reason:" (la motivazione viene salvata con la segnalazione). La tabella rende lo stato evidente: i Real Issues sono verdi/grassetto e ordinati in cima, i False Positives sono grigi/barrati e ordinati in fondo, gli Untriaged stanno in mezzo con il colore della loro confidenza. Una riga di riepilogo mostra i conteggi.
Ogni scheda dei risultati ha un pulsante Export triaged (fine-tuning)… che esporta solo
le segnalazioni triagate (Real Issue + False Positive) come JSONL in formato chat OpenAI
per il fine-tuning: ogni esempio abbina il prompt originale system+user con il
verdetto corretto dall'umano come target dell'assistente (un False Positive insegna
is_vulnerable=false con la tua motivazione; un Real Issue rinforza is_vulnerable=true),
così puoi migliorare iterativamente l'accuratezza del modello sui tuoi binari.
Il contesto per singola segnalazione mostrato nel pannello dei dettagli (e usato per ricostruire i
prompt di fine-tuning) viene, per impostazione predefinita, mantenuto per intero — controllato da
vulnfanatic.storedContextChars (0 = illimitato; imposta un tetto positivo, es. 4000,
per limitare la crescita del BNDB a scapito della fedeltà del contesto).
Il pannello è a schede. La prima scheda è sempre New Scan, dove imposti:
<timestamp> <mode>, es.
2026-06-15 14:03:50 offline),quindi premi Start Scan o Scan Offline. Ogni esecuzione apre la propria scheda dei risultati e le segnalazioni vi confluiscono in tempo reale. Tutte le scansioni sono salvate nel BNDB, quindi puoi ad esempio tenere una scansione offline e aggiungerne poi una online, o confrontare esecuzioni con set di regole diversi, fianco a fianco — riappaiono come schede quando riapri il database. Chiudere una scheda elimina definitivamente quella scansione dal BNDB — per evitare incidenti viene mostrata una conferma che richiede di spuntare "I confirm that I will lose the results from forever." prima che il pulsante Delete results forever si attivi. Export current scan… scrive la scheda selezionata in Markdown/JSON.
Ogni binario aperto ha il proprio stato del pannello indipendente — le proprie schede di scansione e la scansione in corso. Avviare una scansione in un binario e passare a un altro mostra i risultati del secondo binario (e permette di analizzarlo separatamente); la scansione del primo binario continua in background ed è intatta quando torni indietro.
La cartella del pacchetto di questo plugin si chiama vulnfanatic_ng (un identificatore Python valido —
Binary Ninja importa il nome della cartella del plugin come modulo, quindi un nome con trattino
come VulnFanatic-NG non verrebbe caricato).
(Opzionale) Installa il conteggio token accurato nel Python di Binary Ninja: ``` pip install tiktoken
Symlink o copia la cartella vulnfanatic_ng nella directory dei plugin utente di Binary Ninja:
~/Library/Application Support/Binary Ninja/plugins/~/.binaryninja/plugins/%APPDATA%\Binary Ninja\plugins\Ad esempio, su macOS: ``` ln -s "$(pwd)/vulnfanatic_ng" "$HOME/Library/Application Support/Binary Ninja/plugins/vulnfanatic_ng"
Riavvia Binary Ninja (o esegui Ricarica plugin). Un'icona VF appare nella barra laterale destra.
Apri Impostazioni (l'ingranaggio / Edit ▸ Preferences ▸ Settings) e cerca
vulnfanatic. Imposta almeno:
vulnfanatic.apiProvider seleziona come vengono formate e autenticate le richieste. Il
contratto dei verdetti (e tutti i prompt delle regole) è identico tra i vari provider.
AWS Bedrock può essere usato tramite il provider
openaiattraverso il suo endpoint compatibile OpenAI, quindi non necessita di un backend dedicato.
Altre impostazioni utili: vulnfanatic.maxContextTokens (predefinito 100000),
vulnfanatic.maxResponseTokens, vulnfanatic.temperature,
vulnfanatic.reasoningEffort (off/low/medium/high; predefinito high — chiede
al modello di pensare prima di rispondere dove supportato, mappato per provider:
openai/azure reasoning_effort, anthropic pensiero adattivo + output_config.effort,
google thinkingConfig dinamico; rimosso automaticamente e ritentato se un modello lo rifiuta),
vulnfanatic.requestTimeoutSec,
vulnfanatic.callPathMaxDepth / ,
(include i corpi decompilati delle funzioni lungo
il percorso di chiamata; predefinito on) / (limite, predefinito 12),
(include anche le altre funzioni chiamate lungo il
percorso, che possono contenere i controlli di limiti/validazione; predefinito on) /
(limite, predefinito 12),
(include le definizioni di struct/union/enum; predefinito on) /
(limite, predefinito 24),
(traccia gli argomenti delle chiamate a ritroso attraverso i loro produttori
/consumatori e include quei corpi; predefinito on) /
(limite, predefinito 8),
(include il layout delle variabili di stack della funzione chiamante
quando contiene un buffer di dimensione fissa; predefinito on),
(abbina anche le chiamate pericolose inviate tramite un puntatore a funzione/vtable risolto; predefinito on — disattiva per una scansione più veloce su binari molto grandi),
(esegue la seconda passata di doppio controllo; predefinito off) /
/ /
/ (esegue la passata di validazione su
un modello separato e indipendente — vuoto = stesso modello dell'analista) /
(//; scarta i risultati al di sotto di questa soglia; predefinito
), (segnala i siti che il modello non ha potuto valutare come
lead "Unscored" con confidenza invece di scartarli; predefinito on),
(salta i siti di overflow con argomenti tutti costanti;
predefinito off), (//; quanto
ragionamento il modello scrive per ogni verdetto — la principale leva sulla velocità; predefinito ),
/
/ (abilita ogni fase; la Fase 3 è
solo online e di solito viene attivata per scansione tramite la casella New Scan piuttosto che qui),
/ ,
(codifica tiktoken per le stime dei token; ricade su
un'euristica basata sui caratteri se tiktoken non è installato),
(costruisce il contesto completo per i risultati offline così possono
essere esportati per il fine-tuning; predefinito on),
(traccia dettagliata della pipeline sulla console; predefinito off) /
(oscura tutti i dettagli identificativi del binario così il log può essere
condiviso — vedi sotto),
, (verifica i certificati HTTPS;
predefinito on) / (bundle CA per HTTPS — vedi
Troubleshooting se incontri ), e
/ /
(punta questi ai tuoi file di regole per personalizzare
rilevamenti e prompt).
Nota di sicurezza: la chiave API è memorizzata nelle impostazioni di Binary Ninja in chiaro. Preferisci l'override tramite variabile d'ambiente per le chiavi sensibili.
Imposta vulnfanatic.apiBaseUrl al valore letterale TEST per eseguire senza alcun LLM:
/tmp/vulnfanatic_ng/<binary>-<timestamp>/.Usalo per ispezionare e validare esattamente ciò che VulnFanatic-NG invierebbe al modello, e per iterare sui prompt/contesto delle regole senza spendere tempo di modello.
Attiva vulnfanatic.debugLogging per stampare una traccia dettagliata, passo dopo passo, della
pipeline di scansione (sia online che offline) sul log/console di Binary Ninja: ogni sito di chiamata,
ogni decisione di salto/eliminazione, la costruzione del contesto (solo dimensione), ogni richiesta LLM
(provider/modello/endpoint, tentativi, fallback), ogni verdetto e ogni risultato segnalato. Le chiavi API non vengono mai registrate.
Mentre la registrazione di debug è attiva, una scansione online mantiene ogni candidato nella tabella dei risultati invece di scartare quelli che non diventano problemi confermati, ciascuno etichettato con uno stato solo di debug (attenuato, ordinato in fondo):
Quindi una scansione di debug mostra una riga per ogni candidato nel totale /N, e il riepilogo riporta
separatamente i problemi rispetto ai conteggi di rifiutati/saltati/errori. Puoi fare clic con il tasto destro su una qualsiasi di queste
righe per riclassificarla come Real Issue o False Positive (il che la rende idonea per
l'esportazione per il fine-tuning). (Le scansioni offline non sono influenzate — non chiamano mai il LLM.)
Indipendentemente dalla modalità di debug, quando un modello restituisce una risposta non analizzabile — un token
fuori posto come <unused…> di Gemma, testo invece di JSON, o un messaggio vuoto (solo un
role, nessun content) — il client esegue un tentativo correttivo, richiedendo nuovamente JSON
solo con il formato di output strutturato disabilitato; se riesce, mantiene il formato disattivato
per il resto della scansione. Il client legge anche il canale di ragionamento
(reasoning_content / reasoning) quando content è vuoto, così i modelli di ragionamento che mettono
la loro risposta lì funzionano comunque.
Il caso del messaggio vuoto è comune con modelli di ragionamento come GPT-OSS / o1 serviti
tramite un'API compatibile OpenAI (es. mlx-community/gpt-oss-20b): con
response_format=json_object impostato, il canale di risposta "final" harmony viene spesso soppresso
e il server restituisce {"role": "assistant"} senza contenuto. Questi modelli possono anche bruciare
l'intero budget di output sul canale di ragionamento e venire troncati a metà pensiero,
restituendo testo senza alcun JSON. Il tentativo automatico recupera i casi legati al formato; se
il problema persiste, disattiva vulnfanatic.sendJsonResponseFormat, abbassa
vulnfanatic.reasoningEffort (così meno budget va al pensiero), e/o aumenta
vulnfanatic.maxResponseTokens. Una risposta persistente <unused…>/spazzatura invece di solito
significa che il prompt supera la finestra di contesto del modello (imposta vulnfanatic.modelContextWindow
e/o aumenta la lunghezza del contesto del server), oppure che il modello non è adatto a un output JSON
rigoroso (un modello di codice come Qwen2.5-Coder si comporta molto meglio di Gemma qui).
Fallback che preserva il recall. Quando un candidato non può ancora essere valutato dopo il tentativo,
vulnfanatic.flagUnparseableResponses (predefinito on) lo segnala comunque come
risultato "Unscored" con confidenza UNKNOWN — un valore distinto da low (il
modello non ha mai prodotto un verdetto, quindi non è un giudizio a bassa confidenza) che finisce in
fondo — mantenendo l'output parziale del modello come spiegazione, così non perdi il
sito, semplicemente lo esamini manualmente. Disattivalo per scartare invece tali siti (in tal caso
emergono solo come errori di analisi, o righe ERROR in debug).
Abilita anche vulnfanatic.debugAnonymous per rendere il log sicuro da condividere: esso
oscura tutto ciò che potrebbe identificare il file analizzato — i nomi di simboli/variabili e gli
indirizzi diventano hash con salt per esecuzione (comunque coerenti all'interno di un'esecuzione così il flusso è
seguibile), il nome del file è nascosto, il testo dei risultati è sostituito con <redacted>, l'host
dell'endpoint LLM è sottoposto a hash, e il codice decompilato / i prompt / il contesto vengono registrati solo
come dimensioni (mai il contenuto). Così puoi inviare un log di debug per segnalare un problema senza
rivelare nulla sul tuo binario.
I risultati — incluso il loro stato di falso positivo — vengono memorizzati nel database
di Binary Ninja. Vengono scritti nel .bndb quando salvi il database (e
scaricati immediatamente se un .bndb esiste già), quindi sopravvivono alla riapertura.
La scansione analizza ogni sito di chiamata corrispondente (senza limite), il che è appropriato per modelli locali. Per un endpoint hosted/a pagamento, fai attenzione al volume su binari grandi.
Entrambi i file di regole condividono un involucro con un system_prompt e un
output_schema comuni, più una lista di rules. Copia un file incluso, modifica le
funzioni/parole chiave/prompt, e punta vulnfanatic.rulesPhase1Path /
vulnfanatic.rulesPhase2Path alla tua copia. Le regole della Fase 1 corrispondono per functions (esatte)
e name_regex; le regole della Fase 2 corrispondono per name_keywords, name_regex e
string_keywords. Il prompt di ogni regola può usare il segnaposto {function}.
Le esportazioni classificate (triaged) sono pensate per essere reintrodotte direttamente nel modello. Dopo
aver classificato i risultati su diversi binari e fatto clic su Export triaged
(fine-tuning)… su ciascuno (raccogliendo i file .jsonl in un'unica cartella),
scripts/finetune_mlx.py esegue un fine-tuning LoRA MLX
su di essi.```bash
pip install mlx-lm # Apple Silicon / macOS
python scripts/finetune_mlx.py ./exports
--model mlx-community/Qwen2.5-Coder-7B-Instruct-4bit
--adapter-path ./vf-adapters --iters 800
python scripts/finetune_mlx.py ./exports --model
--fuse --fused-path ./vf-qwen-coder-vuln
Lo script accetta la **cartella training-data** come argomento posizionale e il
modello di base **`--model`** (percorso locale o ID repo MLX/HF); gli altri parametri sono opzionali:
`--adapter-path`, `--valid-split` (0.1), `--iters`, `--batch-size` (limitato automaticamente per
adattarsi a una piccola suddivisione), `--num-layers`, `--learning-rate`, `--max-seq-length`
(`0` = **adattamento automatico** all'esempio più lungo, con limite massimo di 16384; imposta un valore positivo per
forzarlo), `--fine-tune-type` (`lora`/`dora`/`full`), `--seed`, `--fuse`/`--fused-path`
e `--dry-run` (prepara i dati + stampa il comando senza addestramento). Qualunque cosa dopo un
`--` letterale viene inoltrata così com'è a `mlx_lm lora`. Lo script unisce ricorsivamente ogni
`*.jsonl` nella cartella, valida e **deduplica** gli esempi di chat, crea la
suddivisione `train.jsonl`/`valid.jsonl` che MLX si aspetta, quindi lancia `python -m mlx_lm lora`
(e `mlx_lm fuse` con `--fuse`).
Servi il risultato con un server compatibile OpenAI (`mlx_lm.server --model <path>`) e imposta `vulnfanatic.apiBaseUrl` per puntare a esso, così da eseguire la scansione con il modello ottimizzato.
> I contesti di VulnFanatic-NG sono grandi, quindi di default lo script **adatta automaticamente**
> `--max-seq-length` all'esempio più lungo (arrotondato per eccesso, con limite massimo di **16384 token**).
> Le sequenze lunghe dominano la memoria di addestramento, quindi un modello grande vicino a questo limite può
> mandare in esaurimento la memoria di un Mac più piccolo. Se i tuoi esempi superano il limite, vengono troncati — passa un
> `--max-seq-length` più alto (più memoria) o riduci `vulnfanatic.storedContextChars`
> prima dell'esportazione. Se l'addestramento viene interrotto da un segnale (es. `exit -10` / SIGBUS),
> si tratta di un crash per esaurimento della memoria: riduci `--max-seq-length`, aggiungi `-- --grad-checkpoint`, oppure usa un
> modello più piccolo.
---
## Sviluppo e test
Il plugin non ha dipendenze di terze parti richieste. I moduli puri (`rules`, `tokens`, `llm`, `findings`, `settings`, `prototypes`) sono coperti da una suite di test offline che non richiede né Binary Ninja né una connessione di rete. La suite `tests/` risiede nel repository sorgente del progetto (non è inclusa nel plugin pubblicato); eseguila da lì. Dalla directory del pacchetto puoi comunque controllare la sintassi di ogni modulo:```
python3 -m py_compile *.py ui/*.py
python3 -m unittest discover -s tests # from the source repository
I moduli che si interfacciano con Binary Ninja (context_builder, phase1, phase2) vengono importati
senza problemi anche quando Binary Ninja non è presente (il loro accesso alle API è protetto), ma richiedono un'istanza
di Binary Ninja in esecuzione per essere esercitati.
strcpy per copiare argv[1] in un
buffer di stack fisso e chiama system() sull'input). Compilare con i simboli
per esercitare anche la Fase 2.vulnfanatic.apiBaseUrl,
vulnfanatic.apiKey e vulnfanatic.model.SSL: CERTIFICATE_VERIFY_FAILED ... unable to get local issuer certificate —
il certificato dell'endpoint HTTPS è valido, ma il Python incluso in Binary Ninja non ha
un bundle di CA con cui verificarlo (comune su macOS e nei Python incorporati; lo si vede
con endpoint ospitati come AWS Bedrock, Anthropic, Google, Azure). Risolvere con una
delle seguenti opzioni, in ordine di preferenza:
pip install certifi.
VulnFanatic-NG lo rileva automaticamente.vulnfanatic.caBundlePath su un file bundle (o
directory) — ad esempio il percorso stampato da python3 -m certifi, oppure /etc/ssl/cert.pem.vulnfanatic.tlsVerify (solo per un endpoint fidato/interno
o un server locale autofirmato — questo disabilita il controllo dei certificati).HTTP 400 ... tokenizer.chat_template is not set — il modello che stai servendo
non ha un template di chat, quindi l'endpoint /chat/completions non può formattare i
messaggi. VulnFanatic-NG torna automaticamente all'endpoint /completions per
il resto della scansione quando vede questo errore, quindi la scansione continua. Per evitare del tutto
la prima richiesta fallita, impostare vulnfanatic.apiMode su completions. In alternativa,
risolverlo lato server servendo un modello che include un template di chat, o passarne uno al
proprio server — ad esempio per vLLM: --chat-template <template.jinja> (oppure usare una
variante di modello -Instruct/-Chat). Il template di chat dedicato di solito dà
risultati migliori del prompt completions appiattito.
No JSON object found ... response looks truncated — la risposta del modello è stata interrotta
prima che il JSON fosse completato. Due cause:
vulnfanatic.maxResponseTokens.maxResponseTokens. I server locali hanno spesso una finestra piccola (ollama usa di default
num_ctx=2048!). Per risolverlo, impostare vulnfanatic.modelContextWindow sulla
finestra del proprio server (ad esempio ollama num_ctx, llama.cpp -c, vLLM --max-model-len) —
VulnFanatic-NG limita quindi automaticamente il contesto inviato, così prompt + risposta ci stanno.
Mantenere anche vulnfanatic.maxResponseTokens su un valore ragionevole (≈8192, non 65535) e/o aumentare la
finestra del server. Finestre minuscole (≤8k) non riescono a contenere l'intero contesto interprocedurale;
usare un modello/server configurato per 32k+.IncompleteRead / Could not complete request ... after N attempt(s) — il
server ha accettato la richiesta ma ha chiuso la connessione prima di inviare la
risposta completa. Questo significa quasi sempre che il server del modello è morto o si è bloccato a metà generazione:
esaurimento della memoria (contesto grande + output lungo), un timeout interno/worker, o un proxy
che resetta la connessione. VulnFanatic-NG riprova automaticamente una volta e poi salta quel
sito. Controllare i log del server del modello per la causa reale; ridurre
vulnfanatic.maxContextTokens e/o vulnfanatic.maxResponseTokens, oppure dare al server più
memoria / una finestra di contesto più ampia, di solito risolve il problema.
vulnfanatic.phase2ForceEnable per controllare anche le corrispondenze basate sui nomi, oppure
vulnfanatic.phase2RequireSymbols=off. Il filtro dei simboli è un'euristica.response_format=json_object; il client
lo tollera ed estrae comunque il JSON. Disabilitare vulnfanatic.sendJsonResponseFormat
se il proprio server rifiuta apertamente il parametro.Apache-2.0 (© Martin Petran) — vedi plugin.json.
switchMAIN→ABCD→strcpy, anche le funzioni che MAIN e ABCD chiamano altrove), poiché
potrebbero contenere i controlli di limiti/validazione che condizionano il valore pericoloso
(vulnfanatic.includeCallPathSiblings, riempito finché il budget lo consente), erecv/read/getenv chiamate
nella stessa funzione).mediumhighvulnfanatic.skipConstantArgCalls (default disattivata) — salta i punti di chiamata della classe overflow
i cui argomenti sono tutte costanti a tempo di compilazione.| Impostazione | Significato |
|---|
vulnfanatic.apiProvider | Quale backend LLM chiamare: openai (predefinito), anthropic, google o azure. Vedi Backend LLM di seguito. Tutti i provider vengono raggiunti tramite la libreria standard di Python — non c'è nulla da pip install. |
vulnfanatic.apiBaseUrl | Base dell'endpoint per il provider selezionato (vedi la tabella sotto). Predefinito http://localhost:8080/v1. Imposta al valore letterale TEST per abilitare la modalità test (vedi sotto). |
vulnfanatic.apiKey | Chiave API / bearer token. Può essere vuota per i server locali. Sostituita dalle variabili d'ambiente VULNFANATIC_API_KEY o OPENAI_API_KEY. |
vulnfanatic.model | Obbligatorio (tranne in modalità test). L'identificatore del modello (per azure, il nome del deployment). |
vulnfanatic.apiMode | Solo openai: chat (predefinito, /chat/completions) vs completions (singolo prompt appiattito — per modelli base/instruct serviti senza un template di chat). |
vulnfanatic.azureApiVersion | Solo azure: il parametro di query api-version (predefinito 2024-10-21). |
| Provider | apiBaseUrl | Autenticazione | Note |
|---|
openai | il tuo server, es. http://localhost:8080/v1 | Authorization: Bearer | Chat/Completions compatibili OpenAI: llama.cpp / ollama / vLLM locali, OpenAI e l'endpoint compatibile OpenAI di AWS Bedrock. |
anthropic | vuoto → https://api.anthropic.com | x-api-key + anthropic-version | Messages API di Claude (POST <base>/v1/messages). temperature non viene inviata (i modelli Claude attuali la rifiutano). |
google | vuoto → https://generativelanguage.googleapis.com | chiave API nell'URL | Gemini generateContent (<base>/v1beta/models/<model>:generateContent). |
azure | https://<resource>.openai.azure.com | header api-key | Azure OpenAI; imposta model sul nome del deployment e azureApiVersion sulla tua versione API. |
vulnfanatic.callPathMaxPathsvulnfanatic.callPathIncludeBodiesvulnfanatic.callPathMaxBodiesvulnfanatic.includeCallPathSiblingsvulnfanatic.callPathSiblingMaxBodiesvulnfanatic.includeDataTypesvulnfanatic.maxTypeDefsvulnfanatic.includeVariableDataflowvulnfanatic.dataflowMaxFunctionsvulnfanatic.includeStackLayoutvulnfanatic.scanIndirectCallsvulnfanatic.validationPassvulnfanatic.validatorModelvulnfanatic.validatorProvidervulnfanatic.validatorBaseUrlvulnfanatic.validatorApiKeyvulnfanatic.minConfidencelowmediumhighlowvulnfanatic.flagUnparseableResponsesUNKNOWNvulnfanatic.skipConstantArgCallsvulnfanatic.verdictReasoningconcisefullnoneconcisevulnfanatic.runPhase1vulnfanatic.runPhase2vulnfanatic.runPhase3vulnfanatic.phase2RequireSymbolsvulnfanatic.phase2ForceEnablevulnfanatic.tokenizerEncodingvulnfanatic.offlineBuildContextvulnfanatic.debugLoggingvulnfanatic.debugAnonymousvulnfanatic.sendJsonResponseFormatvulnfanatic.tlsVerifyvulnfanatic.caBundlePathCERTIFICATE_VERIFY_FAILEDvulnfanatic.rulesPhase1Pathvulnfanatic.rulesPhase2Pathvulnfanatic.rulesPhase3Path