
Plugin BianryNinja pour identifier les vulnérabilités dans les binaires décompilés, avec des analyses programmatiques et le support LLM.
Recherche de vulnérabilités assistée par LLM pour Binary Ninja.
VulnFanatic-NG ajoute un panneau latéral qui analyse le binaire actuel et demande à un LLM — un modèle compatible OpenAI hébergé localement par défaut, ou Anthropic Claude, Google Gemini, ou Azure OpenAI (voir Backends LLM) — de juger si un code suspect est réellement vulnérable. Il fonctionne principalement à partir de la sortie du décompilateur (HLIL) de Binary Ninja, en utilisant l'assembleur si nécessaire, et ne rapporte que les problèmes confirmés avec des références cliquables vers le code.
Une analyse s'exécute en jusqu'à trois phases (la phase 3 est optionnelle et en ligne uniquement) :
Trouve les sites d'appel des fonctions dangereuses définies dans rules/phase1_rules.json — strcpy, memcpy, sprintf/chaînes de format, system, alloca, scanf, API de commande/exécution, RNG faible, la famille free/delete (use-after-free / double-free), lectures d'entrées non fiables dans des tampons fixes (recv/read/fread/ReadFile), injection SQL (sqlite3_exec/mysql_query/PQexec), vérification de certificat TLS désactivée (SSL_CTX_set_verify/curl), SSRF, et gestion inappropriée des privilèges (setuid/setresgid), la famille memset/bzero, et comparaisons avec une longueur contrôlée par l'attaquant (memcmp/strncmp → contournement d'authentification), à travers C/C++, Win32, et (au mieux) Rust FFI. La couverture inclut les variantes fortifiées _chk (FORTIFY) et Annex-K _s. Les fonctions de sortie formatée bornées (snprintf et variantes) ont leur propre règle par défaut sécurisée afin qu'un argument de taille correct ne soit pas signalé comme un débordement. Les sites d'appel sont trouvés de trois manières : appels directs aux symboles nommés ; appels acheminés via des thunks de redirection / stubs PLT (les appelants réels sont récupérés, donc une importation atteinte uniquement via un stub n'est pas manquée) ; et — sauf si vulnfanatic.scanIndirectCalls est désactivé — appels indirects envoyés via un pointeur de fonction ou une vtable que Binary Ninja a résolu en une fonction dangereuse. Pour chaque site d'appel, il construit un contexte interprocédural, centré sur le décompilateur, avec un budget de jetons (100k par défaut) :
__*_chk et les variantes vérifiées des limites *_s prennent des arguments supplémentaires en tête, décalant la position du format/taille/destination,s->buf se résolve en la taille réelle du tableau du champ plutôt qu'en la taille du pointeur de s ; les définitions de structure dans la section des types portent également des tailles en octets par champ,0x40 ou bornée à [0, 0xff]), que le modèle utilise comme vérité terrain lorsqu'il compare une taille à une capacité de tampon au lieu de deviner,vulnfanatic.includeStackLayout),if/boucle/ qui protègent l'appel),Ce contexte, ainsi qu'une invite spécifique à la règle, est envoyé au modèle, qui renvoie un verdict structuré. Les non-problèmes sont ignorés. Les invites sont optimisées pour un modèle de code local puissant (par exemple Qwen2.5-Coder) et lui demandent d'analyser l'ensemble du flux et d'émettre uniquement du JSON.
Le modèle reçoit l'instruction de favoriser le rappel — signaler les problèmes plausibles et pertinents pour la sécurité et exprimer l'incertitude via une Confiance plutôt que d'abandonner tout ce qu'il ne peut pas prouver complètement. Il montre son travail dans un bloc-notes qui cite les extraits de code textuels sur lesquels il s'est appuyé (la source d'entrée, chaque garde, la taille/longueur, le type pertinent, et le puits), qui est stocké sur la constatation afin que vous puissiez auditer le raisonnement.
Chaque constatation porte une Confiance (haute/moyenne/basse) : haute = toute la chaîne est montrée dans le contexte ; moyenne = probable, avec un ou deux liens inférés ; basse = une piste méritant un examen manuel. C'est la métrique principale (l'estimation de sévérité du modèle est un champ secondaire). Définissez vulnfanatic.minConfidence pour ignorer tout ce qui est en dessous d'un seuil.
Par défaut, VulnFanatic-NG favorise le rappel (détection des vrais problèmes). Si vous obtenez trop de faux positifs, resserrez avec l'un des éléments suivants :
vulnfanatic.validationPass (désactivé par défaut) — exécute un second passage LLM qui vérifie chaque problème signalé par rapport au même contexte (en vérifiant les extraits du bloc-notes et en retraçant le flux) et peut corriger le verdict ou la confiance. Double les appels LLM pour les candidats signalés.
vulnfanatic.validatorModel (plus validatorProvider / validatorBaseUrl / validatorApiKey) pour exécuter le second passage sur un modèle différent. Un second avis est bien plus utile venant d'un modèle indépendant — il partage moins d'angles morts et est beaucoup moins susceptible d'approuver automatiquement le premier verdict (les modèles ont tendance à préférer leurs propres réponses). Un bon modèle est une cascade : un modèle rapide comme analyste (rappel large) et votre modèle le plus fort comme valideur, qui ne s'exécute que sur les candidats signalés. Laissez le modèle de validation vide pour valider avec le modèle analyste. Le valideur doit être au moins aussi capable que l'analyste — un plus faible ajoute principalement des faux rejets. Tout sauf le fournisseur/URL de base/clé/modèle est hérité des paramètres de connexion de l'analyste ; une clé de valideur vide réutilise la clé de l'analyste ; et si le point de terminaison du valideur est inaccessible, le premier verdict est conservé (la constatation n'est jamais perdue à cause d'une panne du valideur).vulnfanatic.minConfidence (low par défaut) — augmentez à / pour ne signaler que les constatations plus fortes.Vitesse. La majeure partie de la latence par appel est le raisonnement écrit, donc vulnfanatic.verdictReasoning contrôle combien le modèle écrit :
concise (par défaut) — un bref exposé de 1 à 3 phrases, sans code textuel. Beaucoup plus rapide que full avec peu de perte de précision ; vous pouvez également réduire vulnfanatic.maxResponseTokens.full — le bloc-notes détaillé avec extraits cités (le plus vérifiable, le plus lent).none — verdict uniquement. Le plus rapide ; associez-le à un backend capable de raisonnement (vulnfanatic.reasoningEffort) afin que la réflexion interne du modèle fasse le travail. Sur un modèle local simple, none perd en précision (pas de chaîne de pensée du tout).Fonctionnalités de précision toujours actives (elles informent le modèle sans supprimer les constatations) :
_s (Annexe K) et _chk (FORTIFY) et les API à longueur bornée comme sûres sauf si l'argument de taille lui-même est erroné.Le bouton Scan Offline exécute la phase 1 sans modèle — des heuristiques purement programmatiques déclarées dans le bloc offline de chaque règle dans phase1_rules.json. Il signale les sites d'appel dangereux et élimine ceux qui sont manifestement sûrs, en attribuant une Confiance heuristique :
memcpy/memmove avec une longueur constante, un strcpy à partir d'une chaîne constante, un printf avec un format constant, un system avec une commande constante, etc. — appels dont l'argument déterminant est une constante de compilation et ne peut donc pas être contrôlé par l'attaquant. "Constant" inclut les valeurs que l'analyse d'ensemble de valeurs de Binary Ninja a fixées à un nombre en amont, pas seulement les arguments littéraux.strlen/taille, if (len < …)) a été trouvée quelque part sur le flux — y compris dans les fonctions appelées le long du chemin — donc il peut déjà être traité. (Une branche qui mentionne simplement la variable sans la comparer ne compte plus, supprimant une source de rétrogradations fallacieuses.)Les heuristiques utilisent un petit vocabulaire déclaratif dans les règles (constant_safe_args, eliminate_if_all_args_constant, format_arg_lookup, length_guard_vars, base_confidence, skip) évaluées par des prédicats Python — pas de code intégré à exec. La plupart des règles ont une définition hors ligne (débordement, chaîne de format, exécution de commande, scanf, gestion de chemin, RNG faible, analyse numérique faible, changements de privilèges, taille d'allocation, …). Seules les deux catégories qui ont vraiment besoin d'une analyse sémantique sont ignorées hors ligne et laissées au LLM : la famille free/delete (use-after-free / double-free, qui nécessite un suivi de la durée de vie des pointeurs) et la vérification TLS (le bogue est une valeur constante spécifique comme SSL_VERIFY_NONE). Le résumé hors ligne indique combien de sites ont été signalés / éliminés / ignorés (nécessitent le LLM) / échoués, afin que les comptes s'additionnent. C'est un tri rapide ; pour un jugement réel — et pour les catégories ignorées — exécutez l'analyse LLM complète.
Les constatations hors ligne construisent toujours le même contexte interprocédural complet qu'une analyse en ligne enverrait (uniquement pour les sites signalés) et le stockent, donc une fois que vous les avez triées, elles peuvent être exportées comme données de réglage fin tout comme les constatations en ligne. Désactivez avec vulnfanatic.offlineBuildContext si vous voulez une vitesse hors ligne maximale.
S'exécute uniquement lorsque le binaire semble avoir de vrais symboles / noms de variables. Localise les fonctions sensibles pour la sécurité définies dans rules/phase2_rules.json — authentification, cryptographie (incl. algorithmes faibles), vérification de signature/certificat, gestion de session/jeton, contrôle d'accès, gestion de secret/clé, validation d'entrée, comparaison de secret non en temps constant, et désérialisation non sécurisée — correspondant par nom de fonction et chaînes référencées, puis auditées par le modèle.
Un audit de durcissement du firmware contre les attaques par injection de fautes (glitching de tension/horloge/EM) et par canaux auxiliaires (temporel/consommation), basé sur des directives d'atténuation des attaques matérielles. Contrairement aux phases 1–2 (qui trouvent des bugs), la phase 3 signale un contrôle de durcissement manquant ou violé sur une fonction critique pour la sécurité — par exemple : branches d'échec par défaut, décisions de sécurité doublement vérifiées, validation de compteur après boucle, constantes d'état à distance de Hamming élevée (vs 0/1 simple), comparaison de secret en temps constant sur toute la longueur, accès/effacement de secret à décalage aléatoire, chiffrer puis vérifier (anti-DFA), compteurs d'intégrité de flux de contrôle, évitement de la cryptographie en espace utilisateur, et ne pas manipuler directement le matériel de clé brute (rules/phase3_rules.json).
Étant donné que les optimisations du compilateur peuvent supprimer les protections au niveau source, ces contrôles sont mieux vérifiés sur le binaire compilé — exactement ce que cela vérifie. La phase 3 est LLM uniquement (en ligne), gérée par symboles, et désactivée par défaut ; activez-la par analyse avec la case à cocher Phase 3 dans l'onglet Nouvelle analyse (elle ne s'exécute jamais en mode hors ligne).
Les constatations sont listées dans un tableau (statut, confiance, phase, CWE, fonction, adresse, titre) avec un volet de détails qui montre l'explication, le bloc-notes d'analyse, et les notes de validation. Double-cliquez sur une ligne pour naviguer dans la vue binaire vers le code.
Chaque constatation commence Non triée. Cliquez avec le bouton droit sur une ligne pour définir son statut — Marquer comme vrai problème, Marquer comme faux positif, ou Marquer comme non trié. Chaque changement de statut affiche une zone de texte "Fournir une raison :" (la raison est stockée avec la constatation). Le tableau rend le statut évident : les vrais problèmes sont verts/gras et triés en haut, les faux positifs sont gris/barrés et triés en bas, les non triés se situent entre les deux avec leur couleur de confiance. Une ligne de résumé montre les comptes.
Chaque onglet de résultat a un bouton Exporter les triés (réglage fin)… qui exporte uniquement les constatations triées (vrai problème + faux positif) au format JSONL de chat OpenAI pour le réglage fin : chaque exemple associe l'invite système+utilisateur d'origine avec le verdict corrigé par l'humain comme cible de l'assistant (un faux positif enseigne is_vulnerable=false avec votre raison ; un vrai problème renforce is_vulnerable=true), afin que vous puissiez améliorer itérativement la précision du modèle sur vos binaires.
Le contexte par constatation affiché dans le volet de détails (et utilisé pour reconstruire les invites de réglage fin) est, par défaut, conservé en entier — contrôlé par vulnfanatic.storedContextChars (0 = illimité ; définissez un plafond positif, par exemple 4000, pour limiter la croissance du BNDB au prix de la fidélité du contexte).
Le panneau est à onglets. Le premier onglet est toujours Nouvelle analyse, où vous définissez :
<timestamp> <mode>, ex. 2026-06-15 14:03:50 offline),puis appuyez sur Démarrer l'analyse ou Analyser hors ligne. Chaque exécution ouvre son propre onglet de résultat et les constatations y sont diffusées en direct. Toutes les analyses sont stockées dans le BNDB, vous pouvez donc par exemple conserver une analyse hors ligne et ajouter plus tard une analyse en ligne, ou comparer des exécutions avec différents ensembles de règles, côte à côte — elles réapparaissent sous forme d'onglets lorsque vous rouvrez la base de données. La fermeture d'un onglet supprime définitivement cette analyse du BNDB — pour éviter les accidents, une confirmation apparaît nécessitant de cocher "Je confirme que je perdrai les résultats de pour toujours." avant que le bouton Supprimer les résultats pour toujours ne s'active. Exporter l'analyse en cours… écrit l'onglet sélectionné en Markdown/JSON.
Chaque binaire ouvert a son propre état de panneau indépendant — ses propres onglets d'analyse et analyse en cours. Démarrer une analyse dans un binaire et passer à un autre affiche les résultats du deuxième binaire (et vous permet de l'analyser séparément) ; l'analyse du premier binaire continue de s'exécuter en arrière-plan et reste intacte lorsque vous revenez.
Le dossier du package de ce plugin est nommé vulnfanatic_ng (un identifiant Python valide — Binary Ninja importe le nom du dossier du plugin en tant que module, donc un nom avec trait d'union comme VulnFanatic-NG ne se chargerait pas).
(Optionnel) Installez un comptage de jetons précis dans le Python de Binary Ninja : ``` pip install tiktoken
Créez un lien symbolique ou copiez le dossier vulnfanatic_ng dans votre répertoire de plugins utilisateur de Binary Ninja :
~/Library/Application Support/Binary Ninja/plugins/~/.binaryninja/plugins/%APPDATA%\Binary Ninja\plugins\Par exemple, sur macOS : ``` ln -s "$(pwd)/vulnfanatic_ng" "$HOME/Library/Application Support/Binary Ninja/plugins/vulnfanatic_ng"
Redémarrez Binary Ninja (ou exécutez Recharger les plugins). Une icône VF apparaît dans la barre latérale droite.
Ouvrez Paramètres (l'icône engrenage / Édition ▸ Préférences ▸ Paramètres) et recherchez
vulnfanatic. Définissez au minimum :
vulnfanatic.apiProvider sélectionne la façon dont les requêtes sont formées et authentifiées. Le contrat de verdict (et toutes les règles d'invite) sont identiques d'un fournisseur à l'autre.
AWS Bedrock peut être utilisé via le fournisseur
openaigrâce à son point de terminaison compatible OpenAI, il n'a donc pas besoin d'un backend dédié.
Autres réglages utiles : vulnfanatic.maxContextTokens (par défaut 100000),
vulnfanatic.maxResponseTokens, vulnfanatic.temperature,
vulnfanatic.reasoningEffort (off/low/medium/high ; défaut high — demande
au modèle de réfléchir avant de répondre là où c'est pris en charge, mappé par
fournisseur : openai/azure reasoning_effort, anthropic pensée adaptative +
output_config.effort, google thinkingConfig dynamique ; automatiquement enlevé et
retenté si un modèle le rejette), vulnfanatic.requestTimeoutSec,
vulnfanatic.callPathMaxDepth / ,
(inclure les corps décompilés des fonctions le long du
chemin d'appel ; activé par défaut) / (plafond, 12 par
défaut), (inclure également les autres fonctions appelées
le long du chemin, qui peuvent contenir les vérifications de bornes/validation ; activé par
défaut) / (plafond, 12 par défaut),
(inclure les définitions de struct/union/enum ; activé par
défaut) / (plafond, 24 par défaut),
(retracer les arguments d'appel à travers leurs
producteurs/consommateurs et inclure ces corps ; activé par défaut) /
(plafond, 8 par défaut),
(inclure la disposition des variables de pile de la fonction
appelante quand elle a un tampon de taille fixe ; activé par défaut),
(également faire correspondre les appels dangereux distribués
via un pointeur de fonction/table virtuelle résolu ; activé par défaut — désactivez pour une
analyse plus rapide sur les très gros binaires),
(exécuter la seconde passe de double-vérification ; désactivé par
défaut) / / /
/ (exécuter la passe de validation
sur un modèle séparé et indépendant ; vide = même modèle que l'analyste) /
(// ; ignorer les résultats en dessous de ce
seuil ; défaut ), (signaler les sites que le
modèle n'a pas pu noter comme des pistes « Non notées » à confiance au lieu de les
ignorer ; activé par défaut), (ignorer les sites d'appel de
débordement à arguments entièrement constants ; désactivé par défaut),
(// ; quantité de raisonnement que le modèle
écrit par verdict — le principal levier de vitesse ; défaut ),
/ / (activer chaque
phase ; la Phase 3 est exclusivement en ligne et généralement basculée par analyse via la case
à cocher Nouvelle Analyse plutôt qu'ici),
/ ,
(encodage tiktoken pour les estimations de jetons ; utilise une
heuristique de caractères si tiktoken n'est pas installé),
(construire le contexte complet pour les résultats hors ligne
afin de pouvoir les exporter pour un réglage fin ; activé par défaut),
(trace détaillée du pipeline dans la console ; désactivé par défaut) /
(occulter tous les détails identifiant le binaire afin que le
journal puisse être partagé — voir ci-dessous),
, (vérifier les certificats HTTPS ;
activé par défaut) / (paquet d'AC pour HTTPS — voir
Dépannage si vous rencontrez ), et
/ /
(pointez ces chemins vers vos propres fichiers de règles pour
personnaliser les détections et les invites).
Remarque de sécurité : la clé API est stockée en texte clair dans les paramètres de Binary Ninja. Préférez la surcharge par variable d'environnement pour les clés sensibles.
Mettez vulnfanatic.apiBaseUrl à la valeur littérale TEST pour exécuter sans aucun LLM :
/tmp/vulnfanatic_ng/<binaire>-<horodatage>/.Utilisez ceci pour inspecter et valider exactement ce que VulnFanatic-NG enverrait au modèle, et pour itérer sur les invites de règles/contexte sans dépenser de temps modèle.
Activez vulnfanatic.debugLogging pour imprimer une trace détaillée, étape par étape, du
pipeline d'analyse (en ligne et hors ligne) dans le journal/console de Binary Ninja : chaque
site d'appel, chaque décision de saut/élimination, construction du contexte (taille seulement),
chaque requête LLM (fournisseur/modèle/endpoint, tentatives, replis), chaque verdict, et chaque
résultat rapporté. Les clés API ne sont jamais journalisées.
Lorsque le débogage est actif, une analyse en ligne garde chaque candidat dans le tableau des résultats au lieu de supprimer ceux qui ne deviennent pas des problèmes confirmés, chacun étiqueté avec un statut de débogage uniquement (grisé, trié en bas) :
Ainsi, une analyse de débogage montre une ligne par candidat dans le total /N, et le résumé
rapporte les problèmes vs. les comptes rejetés/ignorés/erreur séparément. Vous pouvez faire un
clic droit sur n'importe laquelle de ces lignes pour la reclasser comme Problème Réel ou Faux
Positif (ce qui la rend éligible à l'exportation pour réglage fin). (Les analyses hors ligne
ne sont pas affectées — elles n'appellent jamais le LLM.)
Indépendamment du mode débogage, lorsqu'un modèle renvoie une réponse impossible à analyser —
un jeton erroné comme <unused…> de Gemma, du texte au lieu de JSON, ou un message vide
(uniquement un role, pas de content) — le client fait une tentative corrective,
redemandant du JSON uniquement avec le format de sortie structurée désactivé ; si cela réussit,
il garde le format désactivé pour le reste de l'analyse. Le client lit également le canal de
raisonnement (reasoning_content / reasoning) lorsque content est vide, de sorte que les
modèles de raisonnement qui placent leur réponse là fonctionnent encore.
Le cas du message vide est courant avec les modèles de raisonnement comme GPT-OSS / o1
servis via une API compatible OpenAI (par ex. mlx-community/gpt-oss-20b) : avec
response_format=json_object défini, le canal de réponse « finale » harmonieux est souvent
supprimé et le serveur renvoie {"role": "assistant"} sans contenu. Ces modèles peuvent aussi
brûler tout leur budget de sortie sur le canal de raisonnement et être tronqués en pleine
pensée, renvoyant du texte sans aucun JSON. La tentative automatique récupère les cas liés
au format ; si cela persiste, désactivez vulnfanatic.sendJsonResponseFormat,
abaissez vulnfanatic.reasoningEffort (afin que moins de budget aille à la réflexion),
et/ou augmentez vulnfanatic.maxResponseTokens. Une réponse persistante avec
<unused…>/du bruit signifie plutôt que l'invite dépasse la fenêtre de contexte du modèle
(définissez vulnfanatic.modelContextWindow et/ou augmentez la longueur de contexte du
serveur), ou que le modèle est un mauvais choix pour une sortie JSON stricte (un modèle de
code comme Qwen2.5-Coder se comporte bien mieux ici que Gemma).
Repli préservant le rappel. Lorsqu'un candidat ne peut toujours pas être noté après la
tentative, vulnfanatic.flagUnparseableResponses (par défaut activé) le rapporte quand
même comme un résultat « Non noté » avec une confiance UNKNOWN — une valeur
distincte de low (le modèle n'a jamais produit de verdict, ce n'est donc pas un jugement
à faible confiance) qui se trie en bas — gardant la sortie partielle du modèle comme
explication, de sorte que vous ne perdiez pas le site, vous le révisez simplement
manuellement. Désactivez-le pour supprimer ces sites à la place (ils apparaissent alors
uniquement comme des erreurs d'analyse, ou des lignes d'erreur de débogage).
Activez également vulnfanatic.debugAnonymous pour rendre le journal sûr à partager :
il occulte tout ce qui pourrait identifier le fichier analysé — les noms de symboles/variables
et les adresses deviennent des hachages salés par exécution (toujours cohérents au sein d'une
exécution pour que le flux soit suivable), le nom du fichier est masqué, le texte des résultats
est remplacé par <redacted>, l'hôte de l'endpoint LLM est haché, et le code décompilé / les
invites / le contexte sont journalisés uniquement par taille (jamais le contenu). Ainsi, vous
pouvez envoyer un journal de débogage pour signaler un problème sans divulguer quoi que ce soit
sur votre binaire.
Les résultats — y compris leur statut de faux positif — sont stockés dans la base de données
Binary Ninja. Ils sont écrits dans le .bndb lorsque vous sauvegardez la base de données (et
vidés immédiatement si un .bndb existe déjà), donc ils survivent à une réouverture.
L'analyse examine tous les sites d'appel correspondants (pas de limite), ce qui est approprié pour les modèles locaux. Pour un point de terminaison hébergé/payant, soyez attentif au volume sur les gros binaires.
Les deux fichiers de règles partagent une enveloppe avec une system_prompt partagée et un
output_schema, plus une liste de rules. Copiez un fichier fourni, modifiez les
fonctions/mots-clés/invites, et pointez vulnfanatic.rulesPhase1Path /
vulnfanatic.rulesPhase2Path vers votre copie. Les règles de Phase 1 correspondent par
functions (exactement) et name_regex ; les règles de Phase 2 correspondent par
name_keywords, name_regex, et string_keywords. L'prompt de chaque règle peut utiliser
le paramètre {function}.
Les exportations triées sont conçues pour être réinjectées directement dans le modèle. Après
avoir trié les résultats de plusieurs binaires et cliqué sur Exporter les résultats
triés (réglage fin)… sur chacun (collectant les fichiers .jsonl dans un dossier),
scripts/finetune_mlx.py exécute un réglage fin LoRA MLX
sur eux.```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
Le script prend le **dossier training-data** comme argument positionnel et le base **`--model`** (chemin local ou identifiant de dépôt MLX/HF) ; les autres paramètres sont optionnels : `--adapter-path`, `--valid-split` (0,1), `--iters`, `--batch-size` (auto-clampé pour s'adapter à une petite division), `--num-layers`, `--learning-rate`, `--max-seq-length` (`0` = **auto-ajustement** à l'exemple le plus long, plafonné à 16384 ; définir une valeur positive pour forcer), `--fine-tune-type` (`lora`/`dora`/`full`), `--seed`, `--fuse`/`--fused-path`, et `--dry-run` (préparer les données + afficher la commande sans entraînement). Tout ce qui suit un `--` littéral est transmis textuellement à `mlx_lm lora`. Il fusionne récursivement tous les `*.jsonl` du dossier, valide et **dédoublonne** les exemples de chat, crée la division `train.jsonl`/`valid.jsonl` attendue par MLX, puis lance `python -m mlx_lm lora` (et `mlx_lm fuse` avec `--fuse`).
Servez le résultat avec un serveur compatible OpenAI (`mlx_lm.server --model <path>`) et pointez `vulnfanatic.apiBaseUrl` vers celui-ci pour scanner avec votre modèle affiné.
> Les contextes de VulnFanatic-NG sont grands, donc par défaut le script **auto-ajuste** `--max-seq-length` à votre exemple le plus long (arrondi au supérieur, plafonné à **16384 tokens**). Les longues séquences dominent la mémoire d'entraînement, donc un grand modèle proche de ce plafond peut épuiser la mémoire d'un Mac plus petit. Si vos exemples dépassent le plafond, ils sont tronqués — passez un `--max-seq-length` plus élevé (plus de mémoire) ou réduisez `vulnfanatic.storedContextChars` avant l'exportation. Si l'entraînement est tué par un signal (par exemple `exit -10` / SIGBUS), il s'agit d'un crash par manque de mémoire : réduisez `--max-seq-length`, ajoutez `-- --grad-checkpoint`, ou utilisez un modèle plus petit.
---
## Développement et tests
Le plugin n'a aucune dépendance tierce requise. Les modules purs (`rules`, `tokens`, `llm`, `findings`, `settings`, `prototypes`) sont couverts par une suite de tests hors ligne qui n'a besoin ni de Binary Ninja ni d'un réseau. La suite `tests/` se trouve dans le dépôt source du projet (elle n'est pas incluse dans le plugin publié) ; exécutez-la à partir de là. Depuis le répertoire du package, vous pouvez toujours vérifier la syntaxe de chaque module :```
python3 -m py_compile *.py ui/*.py
python3 -m unittest discover -s tests # from the source repository
Les modules destinés à Binary Ninja (context_builder, phase1, phase2) s'importent proprement sans Binary Ninja (leur accès à l'API est protégé) mais nécessitent un Binary Ninja en cours d'exécution pour être utilisés.
strcpy de argv[1] dans un tampon de pile fixe et appelle system() sur l'entrée). Compilez avec les symboles pour également tester la Phase 2.vulnfanatic.apiBaseUrl, vulnfanatic.apiKey et vulnfanatic.model.SSL: CERTIFICATE_VERIFY_FAILED ... unable to get local issuer certificate — le certificat du point de terminaison HTTPS est correct, mais le Python intégré de Binary Ninja n'a pas de bundle CA pour le vérifier (courant sur macOS et dans les Pythons embarqués ; vous verrez cela avec des points de terminaison hébergés comme AWS Bedrock, Anthropic, Google, Azure). Corrigez avec l'une des solutions suivantes, par ordre de préférence :
pip install certifi. VulnFanatic-NG le détecte automatiquement.vulnfanatic.caBundlePath sur un fichier bundle (ou un répertoire) — par exemple le chemin affiché par python3 -m certifi, ou /etc/ssl/cert.pem.vulnfanatic.tlsVerify (uniquement pour un point de terminaison interne de confiance ou un serveur local auto-signé — cela désactive la vérification du certificat).HTTP 400 ... tokenizer.chat_template is not set — le modèle que vous servez n'a pas de modèle de chat, donc le point de terminaison /chat/completions ne peut pas formater les messages. VulnFanatic-NG bascule automatiquement vers le point de terminaison /completions pour le reste de l'analyse lorsqu'il voit cette erreur, donc l'analyse continue. Pour éviter complètement la première requête échouée, définissez vulnfanatic.apiMode sur completions. Sinon, corrigez-le côté serveur en servant un modèle qui fournit un modèle de chat, ou transmettez-en un à votre serveur — par exemple pour vLLM : --chat-template <template.jinja> (ou utilisez une variante de modèle -Instruct/-Chat). Le modèle de chat dédié donne généralement de meilleurs résultats que l'invite de complétions aplatie.
No JSON object found ... response looks truncated — la réponse du modèle a été coupée avant la fin du JSON. Deux causes :
vulnfanatic.maxResponseTokens.maxResponseTokens. Les serveurs locaux ont souvent une petite fenêtre (ollama par défaut num_ctx=2048 !). Corrigez en définissant vulnfanatic.modelContextWindow sur la fenêtre de votre serveur (par exemple ollama num_ctx, llama.cpp -c, vLLM --max-model-len) — VulnFanatic-NG limite alors automatiquement le contexte envoyé pour que l'invite + la réponse tiennent. Gardez également vulnfanatic.maxResponseTokens raisonnable (≈8192, pas 65535) et/ou augmentez la fenêtre du serveur. Les petites fenêtres (≤8k) ne peuvent pas contenir tout le contexte inter-procédural ; utilisez un modèle/serveur configuré pour 32k+.IncompleteRead / Could not complete request ... after N attempt(s) — le serveur a accepté la requête mais a fermé la connexion avant d'envoyer la réponse complète. Cela signifie presque toujours que le serveur de modèle est mort ou a calé en cours de génération : manque de mémoire (grand contexte + sortie longue), un délai d'attente interne/worker, ou un proxy réinitialisant la connexion. VulnFanatic-NG réessaie une fois automatiquement puis ignore ce site. Vérifiez les journaux du serveur de modèle pour la cause réelle ; réduire vulnfanatic.maxContextTokens et/ou vulnfanatic.maxResponseTokens, ou donner plus de mémoire / une plus grande fenêtre de contexte au serveur, résout généralement le problème.
vulnfanatic.phase2ForceEnable pour également auditer les correspondances basées sur les noms, ou vulnfanatic.phase2RequireSymbols=off. La barrière des symboles est une heuristique.response_format=json_object ; le client le tolère et extrait toujours le JSON. Désactivez vulnfanatic.sendJsonResponseFormat si votre serveur rejette le paramètre carrément.Apache-2.0 (© Martin Petran) — voir plugin.json.
switchMAIN→ABCD→strcpy, également les fonctions que MAIN et ABCD appellent ailleurs), car elles peuvent contenir les vérifications de limites/validation qui contrôlent la valeur dangereuse (vulnfanatic.includeCallPathSiblings, rempli tant que le budget le permet), etrecv/read/getenv appelées dans la même fonction).mediumhighvulnfanatic.skipConstantArgCalls (désactivé par défaut) — ignore les sites d'appel de classe débordement dont les arguments sont tous des constantes de compilation.| Réglage | Signification |
|---|
vulnfanatic.apiProvider | Le backend LLM à appeler : openai (par défaut), anthropic, google ou azure. Voir Backends LLM ci-dessous. Tous les fournisseurs sont atteints via la bibliothèque standard Python — rien à pip install. |
vulnfanatic.apiBaseUrl | Base de l'endpoint pour le fournisseur sélectionné (voir le tableau ci-dessous). Par défaut http://localhost:8080/v1. Mettez la valeur littérale TEST pour activer le mode test (voir ci-dessous). |
vulnfanatic.apiKey | Clé API / jeton d'accès. Peut être vide pour les serveurs locaux. Surchargé par les variables d'environnement VULNFANATIC_API_KEY ou OPENAI_API_KEY. |
vulnfanatic.model | Obligatoire (sauf en mode test). L'identifiant du modèle (pour azure, le nom de déploiement). |
vulnfanatic.apiMode | openai uniquement : chat (par défaut, /chat/completions) vs completions (une seule invite aplatie — pour les modèles de base/instruct servis sans modèle de chat). |
vulnfanatic.azureApiVersion | azure uniquement : le paramètre de requête api-version (par défaut 2024-10-21). |
| Fournisseur | apiBaseUrl | Auth | Notes |
|---|
openai | votre serveur, p. ex. http://localhost:8080/v1 | Authorization: Bearer | Chat/Complétions compatible OpenAI : local llama.cpp / ollama / vLLM, OpenAI, et le point de terminaison compatible OpenAI d'AWS Bedrock. |
anthropic | vide → https://api.anthropic.com | x-api-key + anthropic-version | API Messages de Claude (POST <base>/v1/messages). temperature n'est pas envoyé (les modèles Claude actuels le rejettent). |
google | vide → https://generativelanguage.googleapis.com | Clé API dans l'URL | Gemini generateContent (<base>/v1beta/models/<model>:generateContent). |
azure | https://<resource>.openai.azure.com | En-tête api-key | Azure OpenAI ; définissez model sur le nom de déploiement et azureApiVersion sur votre version d'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