
Ghidra用バイナリコードカバレッジ可視化プラグイン
Dragon Dance は、バイナリコードカバレッジデータを可視化し操作するための Ghidra プラグインです。カバレッジデータは複数のカバレッジソースからインポートできます。現在、プラグインは Dynamorio と Intel Pin のバイナリ計測ツールをサポートしています。Dynamorio には「drcov」という独自のカバレッジ収集モジュールがあります。Intel Pin には組み込みのカバレッジコレクタモジュールはありません。このモジュール不足に対処するため、Intel Pin 用の独自のカバレッジ収集モジュールを作成する必要がありました。そこで、Intel Pin 用のカバレッジ収集モジュール ddph(Dragon Dance Pin Helper)を作成しました。それを使用できます。ddph のソースはこの リンク から参照できます。自分でコンパイルするのが面倒な場合は、Windows、macOS、Linux 向けに提供されたコンパイル済みバイナリを使用できます。

Dragon Dance は、同じセッション内で複数のカバレッジデータをインポートして使用できます。(マルチセッションもサポートしていますが、現時点ではGUIでは使用できません)。また、それらを切り替えたり、交差、差分、排他、または合計演算をすばやく適用したりできます。
Dragon Dance を使用すると、実行された命令の強度を表示できます。これにより、どの命令がどのくらいの頻度で実行されたかのヒントを得られます。また、関数グラフウィンドウでカバレッジの可視化を表示することもできます。


これにより、カバレッジデータを柔軟に操作できます。データの読み込み、削除、表示、交差、差分、排他、合計演算を実行できます。次のセクションでは、スクリプティングシステムとAPIについて説明します。Alt + Enter キーを押してスクリプトを実行します。
組み込み関数は、スクリプティングシステムにインターフェースを提供するための内部カバレッジ操作の実装です。組み込み関数は、カバレッジオブジェクト変数を返すか、何も返さないことができます。組み込み関数にはエイリアスがある場合があります。
これらはパラメータとして組み込み引数(Built-in Arg)を受け入れます。パラメータは可変長です。
組み込み引数は、異なるタイプの値を保持するための参照です。組み込み引数は左から右の順序で渡されます。組み込み引数は以下の値タイプを保持できます:
変数はカバレッジオブジェクトのみを保持する役割を持ちます。組み込み関数によってロードされ、組み込み関数へのパラメータ(組み込み引数)として渡すことができます。
カバレッジオブジェクトには2つのタイプがあります。物理カバレッジオブジェクト と 論理カバレッジオブジェクト です。
物理カバレッジオブジェクトは、カバレッジファイルから直接ロードされたカバレッジオブジェクトを指します。これらはGUI上のカバレッジテーブルに表示され、GUI操作で操作できます。
論理カバレッジオブジェクトは、組み込み関数で処理され、その結果として返されたカバレッジオブジェクトを指します。これらはGUIには表示されませんが、破棄されるまで変数内に存在できます。
カバレッジオブジェクトは、両方のタイプのカバレッジオブジェクトに対して変数オブジェクトによって自動的に管理されます。例えば;``` cov1 = load("firstcoverage.out") cov2 = load("secondcov.out")
cov1 = diff(cov1,cov2)
この例では、cov1 と cov2 は変数です。また、両方の変数は物理カバレッジオブジェクトを持っています。diff 組み込み関数は両方の変数を取って、戻り値を cov1 変数に設定します。この上書き操作により、結果のカバレッジオブジェクトが変数に設定されますが、物理カバレッジオブジェクトであるため、そのカバレッジオブジェクトは削除されません。そのカバレッジデータはセッションおよびGUIテーブルに残り続けます。
前の例を次のように考えてみましょう;```
cov1 = load("first.out")
cov2 = load("second.out")
cov3 = load("third.out")
rvar = sum(cov1,cov2,cov3)
rvar = diff(rvar, cov2)
この例では、3つの物理的なカバレッジ変数がsum演算に投入され、sum演算が論理的な結果カバレッジオブジェクトを返します。次に、diff演算が論理変数と物理変数を取り、rvarという名前の変数を上書きします。
この場合、結果はrvarに設定され、以前のカバレッジ値は即座に破棄されます。これは論理オブジェクトであり、オブジェクトリークを防ぐために削除される必要があるためです。物理的なカバレッジオブジェクトを含む変数を破棄したい場合は、discard組み込み関数を呼び出す必要があります。すべての組み込み関数については後述します。
ネストされた組み込み関数呼び出しを使用して複雑なスクリプトを作成できます。次のように記述できます。
cres = diff(intersect(a, load("another.log"), c, d), sum(e,f) )
ロジックを1行ずつ記述する必要はありません。
以下のAPIドキュメントとその動作は、最終バージョンに達するまで変更される可能性があります。
clear()
| プロパティ | 説明 |
|---|---|
| 戻り値 | なし |
| 最小パラメータ数 | 0 |
| 最大パラメータ数 | 0 |
| 説明 | この組み込み関数は、表示中のカバレッジをクリアし、アクティブなカバレッジをnullに設定します。 |
| エイリアス | なし |
cwd( String : workingDirectory )
| プロパティ | 説明 |
|---|---|
| 戻り値 | なし |
| 最小パラメータ数 | 1 |
| 最大パラメータ数 | 1 |
| 説明 | 指定されたパスで現在の作業ディレクトリを設定します。 cwd以降の絶対パスを持たないすべてのインポート呼び出しでは、カバレッジファイルはアクティブな作業ディレクトリ内で検索されます。 |
| エイリアス | なし |
diff( Variable : var1, var2, ..... varN )
| プロパティ | 説明 |
|---|---|
| 戻り値 | 変数 |
| 最小パラメータ数 | 2 |
| 最大パラメータ数 | 無制限 |
| 説明 | 指定された可変長の変数に対して差分演算を適用します。そして、結果のカバレッジ変数を返します。 |
| エイリアス | なし |
discard( Variable : var1, var2, ..... varN )
| プロパティ | 説明 |
|---|---|
| 戻り値 | なし |
| 最小パラメータ数 | 1 |
| 最大パラメータ数 | 無制限 |
| 説明 | 変数(物理または論理)を破棄します。最初にカバレッジオブジェクトを破棄し、次に変数リストから変数名を登録解除します。この呼び出し後、指定されたすべての変数は未定義になります。 |
| エイリアス | del |
distinct( Variable : var1, var2, ..... varN )
| プロパティ | 説明 |
|---|---|
| 戻り値 | 変数 |
| 最小パラメータ数 | 2 |
| 最大パラメータ数 | 無制限 |
| 説明 | 指定された可変長の変数に対して排他的論理和(xor)演算を適用します。そして、結果のカバレッジ変数を返します。 |
| エイリアス | xor |
goto( Integer : offset )
| プロパティ | 説明 |
|---|---|
| 戻り値 | なし |
| 最小パラメータ数 | 1 |
| 最大パラメータ数 | 1 |
| 説明 | 指定されたオフセットによって現在のアドレス選択を位置付けます。実際のアドレス値は、オフセット値をイメージベース値に加算して計算されます。 |
| エイリアス | なし |
import( String : filePathOrCoverageName )
| プロパティ | 説明 |
|---|---|
| 戻り値 | 変数 |
| 最小パラメータ数 | 1 |
| 最大パラメータ数 | 1 |
| 説明 | 物理的なカバレッジファイルからカバレッジデータをインポートします。相対パスまたは絶対パスを取ります。または、以前に物理的にロードされたカバレッジ名。指定されたパスが絶対パスの場合、インポートはそのパスから直接ロードします。それ以外の場合は、現在の作業ディレクトリ以下を検索してロードします。どちらの場合も、インポートはカバレッジデータがすでにロードされているかどうかをそのパスを使用して確認します。すでにロードされている場合は、キャッシュされたカバレッジ変数を返します。または、指定された値が物理カバレッジの名前である場合、セッション内のカバレッジマップを検索し、存在すればカバレッジオブジェクトを返します。 |
| エイリアス | get, load |
intersect( Variable : var1, var2, ..... varN )