
Plugin visualizador de cobertura de código binario para Ghidra
Dragon Dance es un plugin para Ghidra para visualizar y manipular los datos de cobertura de código binario. Los datos de cobertura pueden importarse de múltiples fuentes de cobertura. Por ahora, el plugin es compatible con las herramientas de instrumentación binaria Dynamorio e Intel Pin. Dynamorio tiene su propio módulo de recolección de cobertura llamado "drcov". Intel Pin no proporciona un módulo de recolección de cobertura incorporado. Para manejar la falta de dicho módulo, tuve que escribir mi propio módulo de recolección de cobertura para Intel Pin. Así que escribí un módulo de recolección de cobertura para Intel Pin llamado ddph (Dragon Dance Pin Helper). Así que puedes usarlo. Puedes ver el código fuente de ddph en este enlace. Si eres demasiado perezoso para compilarlo por tu cuenta, puedes usar los binarios compilados que proporcioné para Windows, macOS y Linux.

Dragon Dance puede importar y usar múltiples datos de cobertura en la misma sesión. (También admite múltiples sesiones, pero por ahora eso no es usable desde la GUI). Y puedes cambiar entre ellas o aplicar operaciones de intersection, difference, distinct o sum entre ellas rápidamente.
Dragon Dance te permite ver la intensidad de las instrucciones ejecutadas. Así que puedes obtener una pista sobre qué instrucciones se ejecutan con qué frecuencia. También puedes ver la visualización de cobertura en la ventana del grafo de funciones.

Dragon Dance también admite su propio sistema de scripting.

Te permite una forma flexible de jugar con los datos de cobertura. Puedes realizar operaciones de load, delete, show, intersect, diff, distinct, sum sobre ellos. La siguiente sección contendrá el sistema de scripting y la API. Presiona las teclas Alt + Enter para ejecutar el script.
Las funciones incorporadas son implementaciones de las operaciones internas de cobertura para proporcionar una interfaz al sistema de scripting. Una función incorporada puede devolver una variable de objeto de cobertura o nada. Las funciones incorporadas pueden tener alias.
Aceptan un Built-in Arg como parámetro. Los parámetros pueden tener longitud variable.
Built-in Arg es una referencia para contener diferentes tipos de valor. Los Built-in Args se pasan en orden de izquierda a derecha. Built-in Arg puede contener los siguientes tipos de valor:
Las variables son responsables de contener únicamente el objeto de cobertura. Pueden ser cargadas por funciones incorporadas. Pueden pasarse como un parámetro (Built-in Arg) a las Funciones Incorporadas.
Hay dos tipos de objeto de cobertura.
Physical Coverage Object y Logical Coverage Object
Physical Coverage Object apunta a un objeto de cobertura que se carga directamente desde el archivo de cobertura. Son visibles en la tabla de cobertura que está en la GUI. Por lo tanto, puedes interactuar con ellos mediante las operaciones de la GUI.
Logical Coverage Object apunta a un objeto de cobertura que ha sido procesado en una función incorporada y devuelto como resultado. No son visibles en la GUI, pero pueden vivir en una Variable hasta que sean destruidos.
El objeto de cobertura es mantenido automáticamente por el objeto Variable para ambos tipos de objeto de cobertura. Por ejemplo;``` cov1 = load("firstcoverage.out") cov2 = load("secondcov.out")
cov1 = diff(cov1,cov2)
En este ejemplo, cov1 y cov2 son variables. Y ambas variables tienen un objeto de cobertura física. La función incorporada diff toma ambas variables y asigna el valor de retorno a la variable cov1. Esa operación de sobrescritura asignará el objeto de cobertura resultante a la variable, pero no elimina el objeto de cobertura porque es un objeto de cobertura física. Esos datos de cobertura permanecerán en la sesión y también en la tabla GUI. Pensemos en el ejemplo anterior de esta manera;```
cov1 = load("first.out")
cov2 = load("second.out")
cov3 = load("third.out")
rvar = sum(cov1,cov2,cov3)
rvar = diff(rvar, cov2)
En este ejemplo, tres variables de cobertura física entran en una operación de suma y la operación de suma devuelve un objeto de cobertura de resultado lógico. Luego, la operación de diferencia toma una variable lógica y una física y sobrescribe la variable llamada rvar.
En este caso, el resultado se asignará a rvar y su valor de cobertura anterior se destruirá inmediatamente. Debido a que era un objeto lógico y debe eliminarse para evitar fugas de objetos. Si desea destruir una variable que contenía un objeto de cobertura física, debe llamar al integrado discard para hacerlo. Todos los integrados se detallarán a continuación.
Puede escribir scripts complejos utilizando llamadas integradas anidadas, puede escribir algo como:
cres = diff(intersect(a, load("another.log"), c, d), sum(e,f) )
no tiene que escribir la lógica línea por línea.
Los siguientes documentos de API y sus comportamientos pueden cambiar hasta que se alcance la versión final.
clear()
| Propiedad | Descripción |
|---|---|
| Valor de retorno | Ninguno |
| Número mínimo de parámetros | 0 |
| Número máximo de parámetros | 0 |
| Descripción | Este integrado limpia la cobertura que se está visualizando y establece la cobertura activa en nulo. |
| Alias | Ninguno |
cwd( String : workingDirectory )
| Propiedad | Descripción |
|---|---|
| Valor de retorno | Ninguno |
| Número mínimo de parámetros | 1 |
| Número máximo de parámetros | 1 |
| Descripción | Establece el directorio de trabajo actual con la ruta dada. Todas las llamadas de importación sin ruta absoluta después de cwd buscarán los archivos de cobertura en el directorio de trabajo activo. |
| Alias | Ninguno |
diff( Variable : var1, var2, ..... varN )