
Visualizador binario y herramienta de triaje: superficies de entropía, clases de bytes y Hilbert, diagramas de puntos y grafos de flujo de control sobre un modelo compartido de espacio de direcciones.
Visualizador y herramienta de triaje de binarios: vistas interactivas vinculadas (entropía, histogramas, superficies de imagen/dot-plot, grafos de flujo de control) sobre un único modelo de espacio de direcciones compartido.
pipx install binviz && binviz serve
Abre un archivo y cada vista observa el mismo espacio de direcciones. Selecciona un rango en una y el resto lo sigue: la idea es responder "¿qué es esta región?" mirándola de varias formas a la vez.
binviz model analiza ELF/PE/Mach-O mediante LIEF en regiones, símbolos y un mapeo offset↔dirección virtual, materializando huecos y superposiciones. La entrada malformada cae en un modelo crudo en lugar de fallar.binviz triage dice cómo se ve el archivo y por qué; en la interfaz, cada hallazgo enlaza con los bytes de los que se derivó.La interfaz tiene cinco espacios de trabajo — Overview, Bytes, Patterns, Code y All — sobre la misma selección. Solo análisis estático: las muestras se analizan, nunca se ejecutan.




Renderizadas por el mismo código que usa la interfaz, directamente desde la CLI — regenera con python docs/make_plates.py.
| Un binario estático | El mismo programa, empaquetado con UPX |
|---|---|
![]() | ![]() |
| Código, cadenas y relleno se separan en territorios visibles. | La estructura colapsa en ruido uniforme — la firma del empaquetado. |
![]() | ![]() |
| La entropía por ventanas se mantiene en bandas y baja. | Plana y alta, hasta el stub de desempaquetado. |
| Stride de fila correcto | Stride de fila incorrecto |
|---|---|
![]() | ![]() |
Los mismos bytes, un número diferente. Por eso existe el sugeridor de stride: el stride de fila incorrecto convierte una fotografía en ruido diagonal, y concluyes que no hay fotografía.
ARCHITECTURE.md es cómo está ensamblado: qué se distribuye, la marca que hereda cada superficie, las convenciones que debe seguir una nueva pantalla y las limitaciones que son deliberadas. SECURITY.md es la postura de seguridad.
python -m venv .venv
# -c fija las versiones exactas contra las que la suite está en verde; pyproject.toml
# publica rangos, así que sin él obtienes lo que se resuelva hoy
.venv/Scripts/pip install -e ".[dev]" -c constraints-dev.txt # POSIX: .venv/bin/pip
# construye el corpus de referencia (usa zig cc del paquete pip de ziglang;
# necesita UPX en PATH, en $UPX, o descomprimido en corpus/tools/upx-*/)
make -C corpus # o: python corpus/build.py
# los umbrales se miden, nunca se codifican (ver ARCHITECTURE.md §2.1)
python corpus/calibrate.py # escribe corpus/calibration.json
pytest # suite funcional
pytest -m perf -s # objetivos de rendimiento de 100 MB
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
# superficies: -p pasa parámetros de superficie
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
# código
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
# el veredicto, y por qué
binviz triage corpus/out/hello_upx
binviz serve # 127.0.0.1:8000
Imprime una URL que contiene un token de sesión — ábrela. Cada ruta /api requiere el token, porque "solo escucha en localhost" no es una defensa contra una página web en otra pestaña, que llega a 127.0.0.1 igual que cualquier otro origen. SECURITY.md tiene el razonamiento.
El acceso a archivos está confinado a --root (por defecto: el directorio de trabajo), por lo que las rutas fuera de él se rechazan.
Los cuatro tienen una bandera y una variable de entorno, y los cuatro existen para evitar que un llamador local consuma más de lo que pretendías. Los valores por defecto están elegidos para un portátil; súbelos si tu máquina es más grande.
| Bandera | Env | Por defecto | Qué limita |
|---|---|---|---|
--max-cache BYTES | BINVIZ_MAX_CACHE | 5 GiB | Tamaño total de los análisis en caché. Más allá de esto, se expulsan las entradas menos usadas recientemente — nunca una que se esté analizando o viendo. |
--max-upload BYTES | BINVIZ_MAX_UPLOAD | 8 GiB | Mayor subida aceptada. |
--max-analyses N | — | 4 | Análisis simultáneos; más allá, /api/open devuelve 503. |
--root DIR | — | cwd | Directorio del que el servidor puede leer archivos. |
Los análisis se guardan en caché bajo ~/.cache/binviz (o $BINVIZ_CACHE), con clave por hash de contenido, por lo que reabrir un binario es instantáneo. Sube --max-cache si prefieres conservar más; la caché es segura de borrar a mano en cualquier momento — el peor caso es que la próxima apertura reanalice.
Otras banderas: --token para fijar un token entre reinicios (útil con el proxy de desarrollo de Vite, que lee BINVIZ_TOKEN), --port, --cache y --no-auth para CI. --no-auth imprime un banner que te dice qué ha desactivado; no lo uses en una máquina compartida.
pip install "binviz[app]"
binviz app # ventana nativa; --browser para tu navegador
Mismo servidor, mismo token, mismo confinamiento --root que binviz serve — la única diferencia es qué lo muestra. Sin pywebview instalado, binviz app abre tu navegador en su lugar.
Imprime la URL en la que está sirviendo, deliberadamente: envolver la interfaz en una ventana no elimina el listener de red, solo hace más fácil olvidar que existe. El listener está autenticado de cualquier manera, y no hay --no-auth en binviz app.
La ventana expone exactamente una función a la página — un selector de archivos nativo — y nada más. Ver src/binviz/app.py para saber por qué esa lista es tan corta.
Las versiones distribuyen una wheel y nada más. Un ejecutable Python congelado sin firmar que incluye capstone y lief y existe para diseccionar binarios empaquetados es exactamente el perfil sobre el que SmartScreen y las heurísticas de AV dan falsos positivos — así que en lugar de distribuir uno, el repositorio lleva lo que necesitas para construirlo tú mismo, lo que evita por completo la firma de código.
pip install pyinstaller # 6.x
python tools/build_ui.py # construye web/ y lo prepara en el paquete
pyinstaller packaging/binviz.spec # -> dist/binviz/
Espera ~100 MB, dominados por numpy y lief. Es un paquete onedir, no un único archivo autoextraíble: lanza dist/binviz/binviz.exe (o haz doble clic) para la ventana de escritorio, o dale cualquier subcomando — dist/binviz/binviz.exe triage sample.exe — porque la compilación congelada es toda la CLI, no solo la ventana.
El paso de preparación no es opcional. web/dist vive fuera del paquete Python, así que omitirlo produce una aplicación cuya ventana se abre en un JSON 404; el spec se niega a construir en lugar de dejar que eso ocurra en silencio.
En macOS el mismo comando también produce dist/Striate.app, con la marca de packaging/icons/icon.icns. Ninguno se ha ejecutado en un Mac — ver ARCHITECTURE.md §5.
--root sigue teniendo como valor por defecto el directorio de trabajo, por lo que un ejecutable con doble clic está confinado a la carpeta en la que se inicia — que suele ser la propia carpeta de la aplicación. Configura el "Iniciar en" del acceso directo, o lánzalo con --root DIR.
Un ejecutable con doble clic pide una credencial. Sin argumentos, la compilación congelada ejecuta binviz app --auth local, que es la única diferencia con el valor por defecto de la wheel de no tener pantalla de inicio de sesión. Las dos responden a preguntas diferentes: binviz app escrito en una terminal ya es un acto deliberado de quien posee la sesión, mientras que un doble clic no establece nada — es la única vía de lanzamiento sin terminal, sin comando escrito y sin decisión de confinamiento detrás. Pedir la credencial es cómo la ventana dice en voz alta lo que la terminal habría dicho. Ejecuta binviz passwd primero para establecer una, o pasa --auth none explícitamente para omitirla; cualquier cosa que suministres en la línea de comandos sigue ganando.
Por defecto no hay pantalla de inicio de sesión ni nada que copiar: el servidor acuña un token de sesión y lo inyecta en la página que sirve, por lo que abrir http://127.0.0.1:8000/ simplemente funciona mientras cada llamada API sigue autenticada.
En una máquina compartida, activa la pantalla de inicio de sesión:
binviz passwd # solicita; digest scrypt, modo 0600
binviz serve --auth local
Si omites binviz passwd, el primer inicio de sesión reclama la instalación — el banner de arranque advierte de eso, porque quien llegue primero al puerto se convierte en la cuenta.
Un ejecutable congelado con doble clic activa --auth local por sí mismo; ver Construir una aplicación independiente para saber por qué ese valor por defecto difiere del de la wheel.
La pantalla de inicio de sesión no es el límite de seguridad; la comprobación del token en cada ruta /api lo es. Cualquier cosa en la máquina puede omitir el formulario y llamar a la API directamente, que es exactamente por qué existe el token. Ver SECURITY.md.
binviz abre archivos que un atacante eligió — ese es el trabajo, no un caso límite, y una herramienta de triaje donde analizar malware compromete al analista es el peor fallo disponible. Las muestras se analizan, nunca se ejecutan. Qué se hace con el resto:
Contra un binario hostil
id en cada ruta /api/{id}/… debe ser exactamente 64 caracteres hexadecimales antes de usarse para construir una ruta.Contra un navegador hostil — la amenaza que "solo escucha en localhost" no aborda, porque una página en otra pestaña llega a 127.0.0.1 como cualquier otro origen:
/api requiere un token. Se acuña al inicio y se inyecta en la página, por lo que nada se pega a mano y ninguna ruta queda abierta.--root, que tiene como valor por defecto el directorio de trabajo. Las rutas fuera de él se rechazan.Host y CORS estrecho, por lo que el origen que necesita acceso es el único que lo obtiene.La ventana de escritorio no elimina el listener de red, solo hace más fácil olvidarlo. Así que no hay --no-auth en binviz app, y el puente js_api expone exactamente un método — pick_file(), que no toma argumentos y devuelve una ruta a través del mismo confinamiento --root. Una prueba falla si alguna vez aparece un segundo método.
Las credenciales para --auth local son digests scrypt escritos en modo 0600; binviz no almacena contraseñas en texto plano.
SECURITY.md tiene el modelo de amenazas, el razonamiento detrás de cada control, lo que deliberadamente aún no se hace y cómo informar de una vulnerabilidad de forma privada.
MIT — ver LICENSE.
El corpus compila de forma cruzada muestras ELF con zig cc, por lo que no se necesita una cadena de herramientas Linux en Windows/macOS — las muestras se analizan, nunca se ejecutan.