Herramientas para extraer grafos de flujo de control (CFG) de binarios compilados utilizando Ghidra en modo headless.
- Ghidra instalado localmente. Puedes indicar la
ubicación mediante la variable de entorno
GHIDRA_INSTALL_DIRo con el argumento--ghidra-installdel script. - Python 3.10 o superior para ejecutar el script
extract_cfg.py.
python extract_cfg.py --ghidra-install /ruta/a/ghidra \
--output-dir cfgs \
/ruta/al/binario1 /ruta/al/binario2Para cada binario analizado se generará un archivo *.cfg.<formato> en el
directorio indicado con --output-dir. El contenido incluye la información
básica del programa junto con la lista de bloques, las aristas del CFG y la
secuencia de instrucciones de cada bloque para la función de entrada
seleccionada. El formato por defecto es GraphML, pero también se puede
exportar a JSON.
-
--keep-project: conserva el proyecto temporal de Ghidra creado durante el análisis. -
--overwrite: permite sobreescribir archivos de salida existentes. -
--temp-dir: base utilizada para crear los directorios temporales de extracción de ZIPs y proyectos de Ghidra. Por defecto apunta a/tmp, pero puedes redirigirla a un disco con más espacio o a un SSD más rápido. -
--script: ruta personalizada a un post-script de Ghidra. Por defecto se utilizaghidra_scripts/export_cfg.pyincluido en este repositorio. -
--language-id: fuerza el language/processor de Ghidra (por ejemplo,x86:LE:32:default) cuando la detección automática no funciona. -
--format: elige el formato de salida (jsonographml). Por defecto se exporta en GraphML. -
--entry-address: indica manualmente la dirección de la función de entrada cuando no exista una función llamadamainque pueda detectarse automáticamente. -
--workers: número de análisis concurrentes a ejecutar. Por defecto el script utiliza tantos workers como núcleos de CPU detectados en la máquina (valor devuelto poros.cpu_count()). Establece--workers 1para comportamiento secuencial. Ten en cuenta que cada worker lanza su propia instancia deanalyzeHeadlessy puede consumir memoria y CPU significativamente. -
--zip-password: contraseña(s) a probar al extraer archivos ZIP cifrados. Puede pasarse varias veces para intentar múltiples contraseñas en orden. Si no se encuentra una contraseña, el script intentará la contraseña por defectoinfectedy, si está disponible, usará herramientas del sistema como7zounzippara soportar distintos esquemas de cifrado. -
--timeout: límite (en segundos) para cada análisis de Ghidra. Si un binario supera ese tiempo, el proceso se aborta para ese archivo concreto y el resto del lote continúa.
El script ahora puede ejecutar múltiples análisis de Ghidra en paralelo. Cada
análisis crea su propio directorio de proyecto temporal y ejecuta
analyzeHeadless sobre un binario. Ejecutar muchos workers simultáneos puede
consumir mucha memoria y CPU; ajusta --workers según la capacidad de tu
máquina. Un buen punto de partida es usar el número de núcleos físicos o
reducir el valor si observas alta contención.
Analizar todos los archivos en un directorio con tantos workers como CPUs:
python extract_cfg.py --input-dir /ruta/a/inputs --output-dir cfgsForzar 4 análisis concurrentes y conservar los proyectos temporales para diagnóstico:
python extract_cfg.py --input-dir /ruta/a/inputs --output-dir cfgs --workers 4 --keep-projectAnalizar un archivo ZIP cifrado probando varias contraseñas y exportando en formato JSON:
python extract_cfg.py --input-dir /ruta/a/inputs --output-dir cfgs --zip-password secret1 --zip-password secret2 --format jsonEnviar los temporales a un disco dedicado (por ejemplo /mnt/ssd/tmp):
python extract_cfg.py --input-dir /ruta/a/inputs --output-dir cfgs --temp-dir /mnt/ssd/tmpAnalizar todas las funciones en cada binario (no sólo main):
python extract_cfg.py --input-dir /ruta/a/inputs --output-dir cfgs --all-functionsEjecutar secuencialmente (útil para depuración o entornos con pocos recursos):
python extract_cfg.py --input-dir /ruta/a/inputs --output-dir cfgs --workers 1El archivo ghidra_scripts/export_cfg.py es un script de Ghidra (Jython) que se
encarga de localizar la función main (o la dirección indicada con
--entry-address), recorrer sus bloques y generar el grafo de flujo de control
incluyendo las instrucciones de cada bloque. Actualmente admite los formatos
JSON y GraphML y se ejecuta automáticamente mediante la opción -postScript del
comando analyzeHeadless de Ghidra.