
Plugin zur Visualisierung der Binärcode-Abdeckung für Ghidra
Dragon Dance ist ein Plugin für Ghidra, mit dem Binärcode-Coverage-Daten visualisiert und manipuliert werden können. Coverage-Daten können aus mehreren Coverage-Quellen importiert werden. Derzeit unterstützt das Plugin die binären Instrumentierungswerkzeuge Dynamorio und Intel Pin. Dynamorio hat ein eigenes Coverage-Erfassungsmodul namens "drcov". Intel Pin bietet kein integriertes Coverage-Erfassungsmodul. Um diese Situation zu bewältigen, musste ich ein eigenes Coverage-Erfassungsmodul für Intel Pin schreiben. Also habe ich ein Coverage-Erfassungsmodul für Intel Pin namens ddph (Dragon Dance Pin Helper) geschrieben. Sie können das verwenden. Den Quellcode von ddph finden Sie unter diesem Link. Wenn Sie zu faul sind, selbst zu kompilieren, können Sie die von mir bereitgestellten kompilierten Binärdateien für Windows, macOS und Linux verwenden.

Dragon Dance kann mehrere Coverage-Daten in derselben Sitzung importieren und verwenden. (Es unterstützt auch mehrere Sitzungen, aber derzeit ist das über die GUI nicht nutzbar). Sie können zwischen ihnen wechseln oder schnell Schnittmenge, Differenz, Unterscheidung oder Summenoperationen miteinander durchführen.
Dragon Dance ermöglicht es Ihnen, die Intensität der ausgeführten Anweisungen anzuzeigen. So erhalten Sie einen Hinweis darauf, welche Anweisungen wie oft ausgeführt werden. Sie können die Coverage-Visualisierung auch im Funktionsgraphenfenster anzeigen.

Dragon Dance unterstützt auch ein eigenes Skriptsystem.

Es bietet Ihnen eine flexible Möglichkeit, mit den Coverage-Daten zu spielen. Sie können sie laden, löschen, anzeigen, Schnittmenge, Differenz, Unterscheidung und Summenoperationen darauf anwenden. Der folgende Abschnitt enthält das Skriptsystem und die API. Drücken Sie die Tasten Alt + Enter, um das Skript auszuführen.
Eingebaute Funktionen sind Implementierungen der internen Coverage-Operationen, um eine Schnittstelle zum Skriptsystem bereitzustellen. Eine eingebaute Funktion kann ein Coverage-Objektvariable oder nichts zurückgeben. Eingebaute Funktionen können Aliase haben.
Sie akzeptieren Built-in Arg als Parameter. Parameter können eine variable Länge haben.
Built-in Arg ist ein Verweis, um verschiedene Werttypen zu halten. Built-in Args werden in der Reihenfolge von links nach rechts übergeben. Built-in Arg kann die folgenden Werttypen halten:
Variablen sind dafür zuständig, nur das Coverage-Objekt zu halten. Sie können durch eingebaute Funktionen geladen werden. Sie können als Parameter (Built-in Arg) an die eingebauten Funktionen übergeben werden.
Es gibt zwei Arten von Coverage-Objekten.
Physikalisches Coverage-Objekt und Logisches Coverage-Objekt
Physikalisches Coverage-Objekt zeigt auf ein Coverage-Objekt, das direkt aus der Coverage-Datei geladen wurde. Sie sind in der Coverage-Tabelle sichtbar, die sich in der GUI befindet. Sie können also über die GUI-Operationen mit ihnen interagieren.
Logisches Coverage-Objekt zeigt auf ein Coverage-Objekt, das in einer eingebauten Funktion verarbeitet und als Ergebnis daraus zurückgegeben wurde. Sie sind nicht in der GUI sichtbar, können aber in einer Variable leben, bis sie zerstört werden.
Das Coverage-Objekt wird automatisch vom Variable-Objekt für beide Arten von Coverage-Objekten verwaltet. Zum Beispiel;``` cov1 = load("firstcoverage.out") cov2 = load("secondcov.out")
cov1 = diff(cov1,cov2)
In diesem Beispiel sind cov1 und cov2 Variablen. Und beide Variablen haben physische Coverage-Objekte. Die eingebaute diff-Funktion nimmt beide Variablen und setzt den Rückgabewert auf die Variable cov1. Diese Überschreibungsoperation setzt das Ergebnis-Coverage-Objekt auf die Variable, löscht jedoch nicht das Coverage-Objekt, da es sich um ein physisches Coverage-Objekt handelt. Diese Coverage-Daten bleiben in der Sitzung und auch in der GUI-Tabelle erhalten.
Betrachten wir das vorherige Beispiel wie folgt;```
cov1 = load("first.out")
cov2 = load("second.out")
cov3 = load("third.out")
rvar = sum(cov1,cov2,cov3)
rvar = diff(rvar, cov2)
In diesem Beispiel fließen drei physikalische Coverage-Variablen in eine Summenoperation ein, und die Summenoperation gibt ein logisches Coverage-Ergebnisobjekt zurück. Dann nimmt die Diff-Operation eine logische und eine physikalische Variable auf und überschreibt die Variable namens rvar.
In diesem Fall wird das Ergebnis auf rvar gesetzt und der vorherige Coverage-Wert sofort zerstört. Da es sich um ein logisches Objekt handelte, sollte es gelöscht werden, um Objektlecks zu vermeiden. Wenn Sie eine Variable zerstören möchten, die ein physikalisches Coverage-Objekt enthält, müssen Sie den eingebauten Befehl discard aufrufen. Alle integrierten Funktionen werden unten detailliert beschrieben.
Sie können komplexe Skripte mit verschachtelten Aufrufen integrierter Funktionen schreiben, etwa so:
cres = diff(intersect(a, load("another.log"), c, d), sum(e,f) )
Sie müssen die Logik nicht Zeile für Zeile schreiben.
Die folgenden API-Dokumentationen und ihr Verhalten können sich bis zur endgültigen Version ändern.
clear()
| Eigenschaft | Beschreibung |
|---|---|
| Rückgabewert | None |
| Minimale Parameteranzahl | 0 |
| Maximale Parameteranzahl | 0 |
| Beschreibung | Diese eingebaute Funktion löscht die aktuell angezeigte Coverage und setzt die aktive Coverage auf null. |
| Aliase | None |
cwd( String : workingDirectory )
| Eigenschaft | Beschreibung |
|---|---|
| Rückgabewert | None |
| Minimale Parameteranzahl | 1 |
| Maximale Parameteranzahl | 1 |
| Beschreibung | Setzt das aktuelle Arbeitsverzeichnis auf den angegebenen Pfad. Alle Importaufrufe ohne absoluten Pfad nach dem cwd suchen die Coverage-Dateien im aktiven Arbeitsverzeichnis. |
| Aliase | None |
diff( Variable : var1, var2, ..... varN )