Ghidra デコンパイラで分かること、復元できないこと
Ghidra は命令、制御フロー、呼び出し規約、シンボル、データ型を解析し、1つの関数を読みやすい疑似コードとして表現します。条件分岐、繰り返し処理、引数の利用、戻り値、呼び出し元と呼び出し先の関係を探すときに特に有効です。
ただし、元の C/C++ ソースが戻るわけではありません。コンパイル時に名前やコメント、高水準の型は失われ、式の統合、命令の並べ替え、インライン化も行われます。変数名、型、式は仮説として扱い、同じアドレスの Listing と周辺の参照でも説明できるか確認してください。
このページはデコンパイラに焦点を当てています。プロジェクト作成、ファイルの取り込み、自動解析、コードブラウザーの基本から学ぶ場合は、先に Ghidra 初心者向けチュートリアルを参照してください。
疑似コードは機械語の動作を読みやすくした地図です。元のソースを証明するものではありません。
Decompiler を開いて Listing と同期する
自動解析の完了後にコードブラウザーでプログラムを開きます。デコンパイラが表示されていなければ Window > Decompiler を選択します。リスティングまたはシンボルツリーで定義済み関数を選ぶと、その関数の疑似コードに切り替わり、選択中の命令に対応する文が強調表示されます。
闇雲にスクロールせず、固有の文字列、インポート API、エクスポート シンボル、エラー メッセージ、既知のエントリーポイントから始めます。参照をたどって呼び出し元を選び、バックグラウンド解析とデコンパイルの終了を待ってから内容を判断します。
関数が存在しないと表示された場合、逆アセンブル結果と参照が境界を裏付けるときだけ関数を定義します。プロセッサ言語やイメージベースが誤っている場合は、先に取り込み設定を修正します。
- 1
手掛かりを選ぶ
説明したい動作に結び付く文字列、シンボル、インポート、アドレスを探します。
- 2
参照をたどる
参照元の関数を開き、リスティング、シンボルツリー、デコンパイラが同じ位置を示すことを確認します。
- 3
解析完了を待つ
処理が終わってから、入力値、呼び出し、分岐、戻り値の順に関数を読みます。

Ghidra の疑似コードを過信せずに読む方法
最初に戻り値、引数、呼び出し規約から成る関数シグネチャを確認します。param_1、local_18、FUN_00401230、undefined8 などは、元のプログラムがその名前を使っていたという意味ではなく、Ghidra に十分な根拠がないことを示します。値の生成元、変化、利用先を追跡します。
次に条件、ループ、呼び出し、メモリアクセス、return までの経路を探します。呼び出し先を開いた後はナビゲーション履歴で戻り、関数の役割を決める前に呼び出し元と参照を確認します。クロスハイライトを使うと疑似コードと命令範囲を結び付けられます。
最適化によって単純な処理が複雑に見えたり、複数の低水準操作が不自然にきれいに見えたりします。分岐方向、定数、符号、ポインター演算、副作用は Listing で確かめます。
| 表示 | 考えられる意味 | 確認する内容 |
|---|---|---|
| param_1 / local_10 | 型や役割が不明な引数・ローカル | 使用箇所、スタック、呼び出し元 |
| FUN_... | 名前が未設定の関数 | 呼び出し元、文字列、インポート |
| undefined4 / undefined8 | サイズのみ判明 | レジスター、キャスト、メモリ配置 |
| goto / 不自然なループ | 復元された制御フロー | 分岐先と関数グラフ |
| 多数のキャスト | 型またはシグネチャの不一致 | 符号、ポインター、プロトタイプ |
名前、シグネチャ、データ型で出力を改善する
プロジェクト内の事実が増えるほどデコンパイル結果は読みやすくなります。関数名は、呼び出し、文字列、インポート、データフローが役割を裏付けてから変更します。変数は推測した業務名ではなく責務で命名し、コメントには疑似コードの言い換えではなく根拠や不確実性を残します。
誤った戻り値や引数は、すべての呼び出し元に不要なキャストやポインター演算を広げます。まず関数プロトタイプと呼び出し規約を直し、繰り返し現れるオフセットや定数に根拠がある場合は構造体、列挙型、配列、ポインター型を適用します。
一度に1つだけ根拠のある変更を行い、呼び出し元への影響を確認します。この手順なら、もっともらしい誤推測を早く取り消せます。
- 1
安定したシンボルを改名
見えている根拠が役割を支持するときだけ、責務が分かる名前を付けます。
- 2
プロトタイプを修正
ローカル変数より先に戻り値、引数、呼び出し規約、ポインター階層を整えます。
- 3
再利用できる型を適用
同じオフセットや定数が複数の関数で現れる場合に構造体や列挙型を作成します。
- 4
呼び出し元を再確認
新しいシグネチャが周辺の関数を明確にし、矛盾を生まないか確認します。
Listing と関数グラフで結論を検証する
Listing は、デコードされた命令とデータをアドレス単位で示す根拠です。どの比較が分岐を決めるか、値が符号付きか、呼び出しからどこへ戻るか、メモリ書き込みが検査の前後どちらで起きるかを確認します。
条件が入れ子になっている場合、早期 return やループが多い場合は関数グラフが役立ちます。真・偽のエッジと共有ブロックを追い、Decompiler に戻って各経路を短い言葉で説明します。
重要な発見には、関数アドレス、決定的な命令やブロック、関連する参照、確信度を記録します。後から型情報が変わって疑似コードの見た目が変化しても、この記録は検証に使えます。

デコンパイル結果が不自然・不完全になる原因
出力が悪い場合は、解析に必要な事実が欠けている可能性があります。デコンパイラの障害と判断する前に、プロセッサ言語、コンパイラ仕様、メモリマップ、イメージベース、関数境界、シグネチャ、アナライザー結果を確認します。
難読化、パック処理、手書きアセンブリ、間接呼び出し、例外、強い最適化、自己書き換え、未対応機能は復元精度を下げます。プログラム全体をきれいなソースに戻そうとせず、1つの分岐、1つのデータ構造、1つの呼び出し元に問いを絞ります。
| 症状 | 主な原因 | 次の確認 |
|---|---|---|
| 関数がない | 境界が未定義 | 参照と逆アセンブル |
| 命令が意味不明 | 言語またはベースが誤り | 取り込み設定とメモリマップ |
| キャストが多い | シグネチャまたは型が誤り | プロトタイプ、符号、ポインター |
| 呼び出しが欠ける | 間接フローまたは解析不足 | XRefs、呼び出し位置、アナライザー |
| 疑似コードが極端に複雑 | 最適化または難読化 | 範囲を分けて関数グラフを確認 |
20分で繰り返せるデコンパイラ練習手順
自作プログラム、オープンソースのバイナリ、学習用 CTF、または解析許可のあるファイルを使用します。隔離した環境に取り込み、自動解析を実行し、成功・失敗メッセージを1つ探して参照をたどり、判断を行う関数を自分の言葉で説明します。
根拠のあるシンボルだけを改名し、シグネチャか型を1つ修正します。主要条件を Listing と比較し、分岐が複雑なら関数グラフを使います。最後に結論を1文で書き、裏付けるアドレスを残します。手作業が安定してから PyGhidra による自動化へ進みます。
画面と機能の詳細は Ghidra 公式 Decompiler ヘルプで確認できます。現行版は Ghidra インストール ガイドに従って導入し、更新前にプロジェクトをバックアップしてください。
- 0〜5分:信頼できる文字列、インポート、シンボル、アドレスを探す。
- 5〜10分:入力、呼び出し、条件、書き込み、戻り値を読む。
- 10〜15分:根拠に基づいて名前、シグネチャ、型を1つ改善する。
- 15〜20分:決定経路を検証し、アドレスと結論を記録する。
Ghidra デコンパイラのよくある質問
Ghidra は元のソースコードを復元できますか?
できません。機械語と解析情報から C 言語風の疑似コードを生成します。元の名前、コメント、型、正確な構造は通常失われています。
Decompiler ウィンドウはどう開きますか?
CodeBrowser でプログラムを開き、非表示なら Window > Decompiler を選び、Listing または Symbol Tree で定義済み関数を選択します。
undefined8 や多数のキャストが表示されるのはなぜですか?
格納サイズは分かっても型の根拠が不足しているか、関数シグネチャが誤っています。呼び出し元、レジスター、符号、ポインター階層、繰り返しオフセットを確認します。
Ghidra は C++ をデコンパイルできますか?
C++ から生成されたネイティブコードを解析できますが、テンプレート、クラス、例外、インライン化、最適化、削除されたシンボルにより元のソースとの違いが大きくなります。
Decompiler と Listing のどちらを信頼すべきですか?
両方を使います。Decompiler は動作を素早く理解するために使い、Listing は分岐、呼び出し、定数、メモリアクセス、副作用をアドレス単位で検証するために使います。