
Analyseur et outil de triage binaire — entropie, classes d'octets et surfaces de Hilbert, diagrammes en points et graphes de flux de contrôle sur un modèle d'espace d'adressage partagé.
Outil de visualisation et de triage binaire : vues interactives liées (entropie, histogrammes, surfaces image/dot-plot, graphes de flux de contrôle) sur un modèle d'espace d'adressage partagé unique.
pipx install binviz && binviz serve
Ouvrez un fichier et chaque vue observe le même espace d'adressage. Sélectionnez une plage dans l'une et les autres suivent — l'objectif est de répondre à la question « qu'est-ce que cette région » en l'examinant de plusieurs manières à la fois.
binviz model analyse ELF/PE/Mach-O via LIEF en régions, symboles et un mappage offset↔adresse virtuelle, en matérialisant les lacunes et les superpositions. Une entrée malformée retombe sur un modèle brut plutôt que d'échouer.binviz triage indique à quoi ressemble le fichier et pourquoi ; dans l'interface, chaque constatation renvoie aux octets dont elle est dérivée.L'interface comprend cinq espaces de travail — Vue d'ensemble, Octets, Motifs, Code et Tout — sur la même sélection. Analyse statique uniquement : les échantillons sont analysés, jamais exécutés.




Rendu par le même code que celui utilisé par l'interface, directement depuis la CLI — régénérez avec python docs/make_plates.py.
| Un binaire statique | Le même programme, compressé avec UPX |
|---|---|
![]() | ![]() |
| Le code, les chaînes et le bourrage se séparent en territoires visibles. | La structure s'effondre en bruit uniforme — la signature de la compression. |
![]() | ![]() |
| L'entropie fenêtrée reste en bandes et faible. | Plate et élevée, jusqu'au stub de décompression. |
| Bon pas de ligne | Mauvais pas de ligne |
|---|---|
![]() | ![]() |
Mêmes octets, un seul nombre différent. C'est pourquoi le suggérateur de pas existe : un mauvais pas de ligne transforme une photographie en bruit diagonal, et vous concluez qu'il n'y a pas de photographie.
ARCHITECTURE.md explique comment c'est assemblé : ce qui est livré, la marque que chaque surface hérite, les conventions qu'un nouvel écran doit suivre, et les limitations qui sont délibérées. SECURITY.md est la posture de sécurité.
python -m venv .venv
# -c épingle aux versions exactes contre lesquelles la suite est verte ; pyproject.toml
# publie des plages, donc sans cela vous obtenez ce qui se résout aujourd'hui
.venv/Scripts/pip install -e ".[dev]" -c constraints-dev.txt # POSIX : .venv/bin/pip
# construire le corpus de vérité terrain (utilise zig cc du paquet pip ziglang ;
# nécessite UPX dans PATH, dans $UPX, ou décompressé dans corpus/tools/upx-*/)
make -C corpus # ou : python corpus/build.py
# les seuils sont mesurés, jamais codés en dur (voir ARCHITECTURE.md §2.1)
python corpus/calibrate.py # écrit corpus/calibration.json
pytest # suite fonctionnelle
pytest -m perf -s # cibles de performance 100 Mo
binviz probe corpus/out/hello_O2
binviz model corpus/out/hello_upx
binviz signal corpus/out/hello_upx --name entropy_4096 --png out.png
binviz hist corpus/out/ramp16.bin --n 2 --dtype u16le --png bigram.png
# surfaces : -p passe les paramètres de surface
binviz surface corpus/out/hello_static --name hilbert -p mode=byteclass --png h.png
binviz surface corpus/out/rgb_raw.bin --name image -p mode=rgb8 -p width=320 --png i.png
binviz surface corpus/out/repeats.bin --name dotplot -p mode=exact --png d.png
binviz stride corpus/out/bayer_raw.bin --mode bayer_RGGB_RGB_12
# code
binviz disasm corpus/out/hello_O2 --limit 20
binviz functions corpus/out/hello_static --sort size
binviz cfg corpus/out/hello_O2 --func main --dot main.dot
# le verdict, et pourquoi
binviz triage corpus/out/hello_upx
binviz serve # 127.0.0.1:8000
Il affiche une URL contenant un jeton de session — ouvrez-la. Chaque route /api exige le jeton, car « il n'écoute que sur localhost » n'est pas une défense contre une page web dans un autre onglet, qui atteint 127.0.0.1 comme n'importe quelle autre origine. SECURITY.md contient le raisonnement.
L'accès aux fichiers est confiné à --root (par défaut : le répertoire de travail), donc les chemins en dehors sont refusés.
Les quatre ont un drapeau et une variable d'environnement, et les quatre existent pour empêcher un appelant local de consommer plus que prévu. Les valeurs par défaut sont choisies pour un ordinateur portable ; augmentez-les si votre machine est plus puissante.
| Drapeau | Env | Défaut | Ce qu'il borne |
|---|---|---|---|
--max-cache BYTES | BINVIZ_MAX_CACHE | 5 Gio | Taille totale des analyses en cache. Au-delà, les entrées les moins récemment utilisées sont évincées — jamais celle en cours d'analyse ou de visualisation. |
--max-upload BYTES | BINVIZ_MAX_UPLOAD | 8 Gio | Plus grand téléversement accepté. |
--max-analyses N | — | 4 | Analyses simultanées ; au-delà, /api/open renvoie 503. |
--root DIR | — | cwd | Répertoire à partir duquel le serveur peut lire les fichiers. |
Les analyses sont mises en cache sous ~/.cache/binviz (ou $BINVIZ_CACHE), indexées par hash de contenu, donc rouvrir un binaire est instantané. Augmentez --max-cache si vous préférez en conserver davantage ; le cache peut être supprimé manuellement à tout moment — le pire des cas est que la prochaine ouverture réanalyse.
Autres drapeaux : --token pour épingler un jeton entre les redémarrages (utile avec le proxy de développement Vite, qui lit BINVIZ_TOKEN), --port, --cache et --no-auth pour la CI. --no-auth affiche une bannière indiquant ce qu'il a désactivé ; ne l'utilisez pas sur une machine partagée.
pip install "binviz[app]"
binviz app # fenêtre native ; --browser pour votre navigateur
Même serveur, même jeton, même confinement --root que binviz serve — la seule différence est ce qui l'affiche. Sans pywebview installé, binviz app ouvre votre navigateur à la place.
Il affiche l'URL sur laquelle il sert, délibérément : envelopper l'interface dans une fenêtre ne supprime pas l'écouteur réseau, cela rend seulement plus facile d'oublier qu'il y en a un. L'écouteur est authentifié dans les deux cas, et il n'y a pas de --no-auth sur binviz app.
La fenêtre expose exactement une fonction à la page — un sélecteur de fichiers natif — et rien d'autre. Voir src/binviz/app.py pour savoir pourquoi cette liste est aussi courte.
Les versions livrent une wheel et rien d'autre. Un exécutable Python figé non signé qui regroupe capstone et lief et existe pour disséquer des binaires compressés est exactement le profil sur lequel SmartScreen et les heuristiques antivirus font de faux positifs — donc au lieu d'en livrer un, le dépôt contient ce dont vous avez besoin pour le construire vous-même, ce qui contourne entièrement la signature de code.
pip install pyinstaller # 6.x
python tools/build_ui.py # construit web/ et le met en scène dans le paquet
pyinstaller packaging/binviz.spec # -> dist/binviz/
Attendez-vous à environ 100 Mo, dominés par numpy et lief. C'est un bundle onedir, pas un fichier unique auto-extractible : lancez dist/binviz/binviz.exe (ou double-cliquez dessus) pour la fenêtre de bureau, ou donnez-lui n'importe quelle sous-commande — dist/binviz/binviz.exe triage sample.exe — car la construction figée est toute la CLI, pas seulement la fenêtre.
L'étape de mise en scène n'est pas facultative. web/dist vit en dehors du paquet Python, donc l'ignorer produit une application dont la fenêtre s'ouvre sur un JSON 404 ; le spec refuse de construire plutôt que de laisser cela se produire silencieusement.
Sur macOS, la même commande produit également dist/Striate.app, marqué à partir de packaging/icons/icon.icns. Aucun des deux n'a été exécuté sur un Mac — voir ARCHITECTURE.md §5.
--root reste par défaut le répertoire de travail, donc un exécutable double-cliqué est confiné au dossier dans lequel il démarre — ce qui est généralement le dossier de l'application elle-même. Définissez le « Démarrer dans » du raccourci, ou lancez-le avec --root DIR.
Un exécutable double-cliqué demande un identifiant. Sans arguments, la construction figée exécute binviz app --auth local, ce qui est la seule différence par rapport au défaut de la wheel qui n'a pas d'écran de connexion. Les deux répondent à des questions différentes : binviz app tapé dans un terminal est déjà un acte délibéré de la part de celui qui possède la session, tandis qu'un double-clic n'établit rien — c'est le seul chemin de lancement sans terminal, sans commande tapée et sans décision de confinement derrière lui. Demander l'identifiant est la façon dont la fenêtre dit à voix haute ce que le terminal aurait dit. Exécutez binviz passwd d'abord pour en définir un, ou passez --auth none explicitement pour l'ignorer ; tout ce que vous fournissez sur la ligne de commande l'emporte toujours.
Par défaut, il n'y a pas d'écran de connexion et rien à copier : le serveur crée un jeton de session et l'injecte dans la page qu'il sert, donc ouvrir http://127.0.0.1:8000/ fonctionne simplement tandis que chaque appel API reste authentifié.
Sur une machine partagée, activez l'écran de connexion :
binviz passwd # invite ; digest scrypt, mode 0600
binviz serve --auth local
Si vous ignorez binviz passwd, la première connexion revendique l'installation — la bannière de démarrage vous en avertit, car celui qui atteint le port en premier devient le compte.
Un exécutable figé double-cliqué active --auth local pour lui-même ; voir Construction d'une application autonome pour savoir pourquoi ce défaut diffère de celui de la wheel.
L'écran de connexion n'est pas la frontière de sécurité ; la vérification du jeton sur chaque route /api l'est. Tout ce qui se trouve sur la machine peut ignorer le formulaire et appeler l'API directement, ce qui est exactement la raison pour laquelle le jeton existe. Voir SECURITY.md.
binviz ouvre des fichiers choisis par un attaquant — c'est le travail, pas un cas limite, et un outil de triage où l'analyse de logiciels malveillants compromet l'analyste est la pire défaillance possible. Les échantillons sont analysés, jamais exécutés. Ce qui est fait pour le reste :
Contre un binaire hostile
id dans chaque route /api/{id}/… doit être exactement 64 caractères hexadécimaux avant d'être utilisé pour construire un chemin.Contre un navigateur hostile — la menace que « il n'écoute que sur localhost » ne traite pas, car une page dans un autre onglet atteint 127.0.0.1 comme n'importe quelle autre origine :
/api exige un jeton. Il est créé au démarrage et injecté dans la page, donc rien n'est collé à la main et aucune route n'est laissée ouverte.--root, qui par défaut est le répertoire de travail. Les chemins en dehors sont refusés.Host et CORS étroit, donc l'origine qui a besoin d'accès est la seule qui l'obtient.La fenêtre de bureau ne supprime pas l'écouteur réseau, elle rend seulement plus facile d'oublier. Donc il n'y a pas de --no-auth sur binviz app, et le pont js_api expose exactement une méthode — pick_file(), qui ne prend aucun argument et renvoie un chemin à travers le même confinement --root. Un test échoue si une seconde méthode apparaît jamais.
Les identifiants pour --auth local sont des digests scrypt écrits en mode 0600 ; binviz ne stocke aucun mot de passe en clair.
SECURITY.md contient le modèle de menace, le raisonnement derrière chaque contrôle, ce qui n'est délibérément pas encore fait, et comment signaler une vulnérabilité en privé.
MIT — voir LICENSE.
Le corpus compile en croisé des échantillons ELF avec zig cc, donc aucune chaîne d'outils Linux n'est nécessaire sur Windows/macOS — les échantillons sont analysés, jamais exécutés.