mcpField
R
re-ghidra

re-ghidra

github.com/dslsdzcセキュリティ20658 回インストール2 週間前に更新
リポジトリ

re-ghidra について

re-ghidraは、リバースエンジニア向けのGhidra静的解析ワークフローです。GUI操作とヘッドレス処理に対応し、スクリプト、逆コンパイル、型復元に加え、結果の検証と元サンプルの保全も扱います。

主な機能

  1. 01GUIでの移動、クロスリファレンス、逆コンパイル
  2. 02ヘッドレス取り込みと一括解析
  3. 03ラベル付けやバイト操作のスクリプト
  4. 04型と構造体の復元
  5. 05逆コンパイル結果の出力と検証

活用シーン

  1. 01PE、ELF、Mach-Oサンプルの一括解析
  2. 02関数呼び出しと参照関係の追跡
  3. 03ラベル付けや復号ループのエミュレーション
  4. 04関数境界と逆コンパイル結果の確認

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/dslsdzc/rev-skills --skill re-ghidra

インストール後、Claude Code で/re-ghidraを入力して読み込まれたか確認します。

同梱ファイルreferences/commands.mdreferences/gotchas.md

詳細

Ghidra リバースエンジニアリングワークフロー

使用する場合/使用しない場合

  • 使用する:逆コンパイルと詳細な静的解析が必要な場合;ヘッドレスでの一括処理;スクリプトによる自動ラベル付け/復号ループ;PE/ELF/Mach-O をすべてサポート
  • 使用しない:メモリが 4GB 未満の場合(起動時から動作が重いため、[[re-radare2]] に切り替え);素早い初期調査だけが必要な場合([[re-triage]] を使用)
  • 使用しない:IDA のワークフローがすでにあり、対象が明確な場合(RE_DECOMPILER セッション変数に従って選択)

ツールの準備

[[re-analyze/platform-tips]] を参照してください。Ghidra は静的解析の主力です(サンドボックス不要)。メモリの少ない環境では、各プラットフォームの経験に応じて [[re-radare2]] に切り替えてください。ヘッドレスでの一括処理はリモート環境に適しています。

Ghidra(公式インストール、Java 21 が必要)
  • ダウンロード:GitHub の NationalSecurityAgency/ghidra releases からダウンロードし、解凍すれば使用できます(インストール不要)
  • JDK 21(Ghidra 11.3+ で必要):
    • Linux:apt install openjdk-21-jdk / dnf install java-21-openjdk / pacman -S jdk21-openjdk
    • macOS:brew install openjdk@21 または brew install --cask temurin
    • Windows:choco install temurin21(または Oracle JDK 21)
  • 起動:./ghidraRun(GUI)/ ./support/analyzeHeadless(ヘッドレス)
  • 確認:java -version(21+ が必要);./support/analyzeHeadless -help で正常に出力されること
  • バージョン:現在のメインラインは 12.x(確認済みの基準バージョンは 12.1.4)です。インストール時は公式 Releases の Latest を基準にしてください。公式リリースの実行には JDK 21 のみが必要です。Ghidra 自体をソースからビルドするには JDK 25 + Gradle 9.1+ が必要です。11.x → 12.x ではスクリプト API に互換性を損なう変更があるため、スクリプトを作成する際は対象バージョンの javadoc を確認してください。詳細は [[gotchas]] を参照してください。
ghidra-bridge(Python によるリモート制御)
  • 全プラットフォーム:pip install ghidra-bridge
  • 前提条件:Ghidra GUI の Script Manager で ghidra_bridge_server.py を実行します
  • 確認:python3 -c "import ghidra_bridge; print(ghidra_bridge.__version__)"

操作手順

  1. analyzeHeadless によるヘッドレスインポート+解析:

    $GHIDRA/support/analyzeHeadless /tmp/proj sample_proj \
      -import ./sample.bin -deleteProject -log /tmp/ghidra.log
    

    プロジェクトを作成するだけで対話操作を行わない場合は -overwrite を追加します。複数のサンプルを一括処理するにはループで呼び出します。ログは -log で確認します。解析完了の目安は、例外がなく、プロジェクトを再度インポートできることです。

    • -process モード(インポート済みプロジェクト内のファイルに対してスクリプト/解析を再実行する場合に使用します。-import との併用はできません):
      $GHIDRA/support/analyzeHeadless /tmp/proj sample_proj \
        -process -postScript MyScript.java -scriptPath /tmp/scripts
      
    • シンボル/文字列/単一関数の逆コンパイルだけを行う場合は -noanalysis を追加します(自動解析をスキップし、数秒で完了します)。読み取り専用で再確認する場合は -readOnly を追加します。すべてのパラメーターの一覧は [[commands]] を参照してください。
  2. GUI:ナビゲーション/クロスリファレンス/逆コンパイル:

    • File > Import File → サンプルを選択 → Analyze(左下の進捗表示が完了するまで待ちます)
    • 移動:Go To(G)にアドレスを入力します。エントリーポイントは Program Trees で entry と表示されます
    • クロスリファレンス:関数/変数にカーソルを置いて R を押します(References ウィンドウ)。または右クリック > References > Show References To を選択します
    • 逆コンパイル:Listing で Ctrl+E を押します(Decompiler ウィンドウ。既定のショートカットはバージョン/keymap によって異なる場合があるため、Help > Key Bindings を確認してください)。または右クリック > Decompile Function を選択します。逆コンパイルビューからコピーできます
    • 関数グラフ:関数上で F を押すと、分岐/ループ構造を確認できます(Function Graph)。Decompiler と連動してナビゲーションできます
    • アンダースコア付きアドレスの違い:Listing には VA(ImageBase を含む)が表示されます。スクリプトでは、一般的に getAddressFactory().getDefaultAddressSpace().getAddress("0x401000") を使用します
  3. 名前変更+型伝播によるラベル付け:

    • 関数名の変更:Listing で L を押します。変数名の変更:Decompiler で L を押します
    • 型の設定:変数を右クリック > Set Data Type(y)を選択します。例:char *、DWORD、int (*)(int)
    • 構造体の定義:Data Type Manager > 新しい Structure を作成します。Decompiler で参照すると、型伝播によって逆コンパイルの品質が自動的に向上します
    • 既知のライブラリ関数にラベルを付ける:右クリック > Set Data Type + f(Function signature)を選択すると、後続の呼び出し箇所で引数の意味を把握しやすくなります
  4. Python スクリプト(自動ラベル付け、復号ループのシミュレーション):

    # @category Analysis  — 放 GhidraScripts 目录,Script Manager 中 Run
    from ghidra.program.model.listing import CodeUnit
    fm = currentProgram.getFunctionManager()
    for f in fm.getFunctions(True):
        body = f.getBody()
        if body.getNumAddresses() > 10000:
            print("large:", f.getName(), hex(body.getMaxAddress().getOffset()))
    

    復号ループ:XOR ループを特定した後、スクリプトでパッチを適用するか、直接計算します。

    from ghidra.program.model.mem import *
    fm = currentProgram.getFunctionManager()
    f = fm.getFunctionAt(currentAddress)
    # 示例: 从 0x403000 起 0x100 字节异或 0x55
    addr = currentProgram.getAddressFactory().getDefaultAddressSpace().getAddress("0x403000")
    for i in range(0x100):
        b = getByte(addr.add(i)) ^ 0x55
        setByte(addr.add(i), b)
    
    • バイトを書き換える前にコピーを作成してください:setByte は現在の Program に直接書き込みます(保存すると元のファイルが変更されます)。悪意のあるサンプルを分析する場合は、必ず事前に Program をコピーする(File > Save As で別名保存する)か、一時コピーに対して操作してください。証拠保全の連鎖を損なうため、元のサンプルに直接パッチを適用することは禁止です。 ヘッドレスでの一括処理:analyzeHeadless ... -postScript MyScript.java -scriptPath <dir>
  5. 逆コンパイルした C のエクスポート:

    • File > Export Program → 形式で C/C++ を選択し、逆コンパイルツリー全体をエクスポートします
    • または Decompiler ウィンドウで関数ごとに Copy してノートに貼り付けます
    • エクスポートされるのは逆コンパイル結果であり、元のソースコードが復元されるわけではありません:変数名/型の推定は誤っている可能性があります(名前を変更すると改善します)。元の実装を示すものではありません。閲覧の補助としてのみ使用し、重要なロジックは必ず逆アセンブル結果/Listing と照合して検証してください。
    • エクスポート後の確認:C では、シンボルのない関数名がコメント(関数アドレス)として保持されます。元の Listing と照合してください。

関数分析のコンテキストチェックリスト

各関数を分析する前に、情報を収集してください([[re-analyze/analysis-contract]] のコンテキストチェックリストを参照):xrefs(その関数を参照する関数/その関数が参照する関数)、対象関数が参照する文字列、caller/callee のシグネチャ、名前付きシンボルテーブル、復元済みの struct。一度にすべてそろえてから分析し、xrefs を何度も確認するのを避けてください。各関数につき、追加の証拠を能動的に求めるツール呼び出しは 8 回以内にしてください。

単一関数の詳細分析の順序

[[re-analyze/analysis-contract]] の「単一関数の詳細分析の順序」に従って、5 つのステップ(types → constants → vtables → identity → decompilation)を進めてください(ステップを飛ばしたり、先に逆コンパイルしてから逆算したりしてはいけません)。Ghidra での対応する操作:型には Type Manager / Apply Function Signature を使用します。仮想関数テーブルには vtable 分析を使用します。シンボル/定数の証拠は、readelf / strings / objdump でエクスポートして補助情報として利用できます。

分野横断の連携

  • [[re-address-space]]:Ghidra のベースアドレスと実行時アドレスの換算(load bias)

  • [[re-binary-core]]:ワークフローの第 5 ステップで既定の逆コンパイラー

  • [[re-malware]]:悪意のあるサンプルの詳細分析(難読化スクリプトによるラベル付け)

  • [[re-ctf]]:リバースエンジニアリング問題の主力

  • [[re-firmware]]:ファームウェア ELF コンポーネントの逆コンパイル

  • [[re-mobile]]:App の .so ライブラリ分析

  • [[re-format-pe]] / [[re-format-elf]] / [[re-format-macho]] と組み合わせて構造を読み取ります。メモリの少ない環境では [[re-radare2]] を使用してください

常见坑与陷阱

  • 自动分析漏掉混淆代码:花指令/乱序代码段可能未被反汇编——手动选中段按 C(code)强制标记,必要时修复函数边界(右键 > Create Function)

  • Java 版本不匹配启动失败:报 UnsupportedClassVersionError → 确认 java -version 为 21+,JAVA_HOME 指向正确 JDK

  • 内存 <4GB 卡顿:分析大二进制内存耗尽 → 换 [[re-radare2]] 或减小分析范围(-analysisTimeoutPerFile)

  • headless 默认分析选项与 GUI 有差异(缺少部分可选项)→ 用 -postScript 显式执行分析脚本保证一致

  • 大文件自动分析卡死:现象——导入大二进制后自动分析长时间不结束/界面卡死;原因——大文件卡死诱因=间接调用爆炸/大型 C++ RTTI/混淆控制流/大量数据段;对策——先降低自动分析范围(限制/关闭间接调用与 RTTI 分析选项),优先定位入口/字符串/交叉引用再逐步展开,见 [[re-analyze/platform-tips]] 静态优先原则

  • 函数边界异常 → 检查反编译假象:现象——反编译视图里函数被错误拆分/合并、多出假参数或栈变量错乱、函数体看着像垃圾数据,照此分析得出荒谬逻辑;原因——手写汇编、混淆代码、尾调用(tail call 使相邻函数被错误合并)、无 frame pointer(不用 rbp/ebp 使帧推断失真)会让 decompiler 的边界与帧推断出错;对策——先核对 Listing 汇编与真实字节,按 C/Create Function 手工修正边界,尾调用与无 frame pointer 的函数以汇编语义为准、不完全相信反编译输出(见 [[re-binary-core]] 分析方法论 R4)

  • 内置脚本解释器是 Jython 2.7,不是 Python 3:现象——脚本一跑就报 SyntaxError(f-string/海象运算符)或 ImportError(找不到 pip 安装的三方库);原因——Ghidra 内置 Jython 2.7,是 Python 2 语法与标准库,不支持 Python 3 语法,也无法 import pip 装的包;对策——脚本按 Python 2 兼容语法写(不用 f-string、用 xrange),需要现代 Python 能力(numpy 等)时改用 ghidra-bridge 让外部 Python 3 解释器驱动分析(见工具准备)

  • 脚本/扩展选型失当 → 自动化维护成本失控:现象——一次性批处理逻辑越写越复杂、每次手动触发很烦,或需要常驻自动化却反复手动点脚本;原因——Script(脚本:轻量单文件、手动触发、适合一次性/简单重复任务)与 Extension(扩展:可注册菜单/面板/事件监听、随工程加载自动执行、ZIP 打包团队分发)的边界没分清;对策——简单重复任务用脚本即用即走;需要 UI 集成、外部服务接入、加载时自动执行或团队标准化分发时才做扩展

  • 脚本 API 跨版本不兼容:现象——headless 脚本编译失败(skipping 且报 getPermissions()/getExecute() 类方法不存在);原因——Ghidra 版本间 MemoryBlock 等 API 变更(12.x 为 isExecute(),不同版本方法名不同);对策——写脚本前先查当前版本 javadoc(小验证脚本),编译失败先怀疑 API 差异而非业务逻辑

  • 全量分析太慢就 -noanalysis:只做符号表/字符串/单函数反编译时,analyzeHeadless -noanalysis 导入后脚本可直接用——符号(含 JNI 导出)与字符串扫描不依赖 auto-analysis,秒级完成

  • 命令速查(headless 参数族 / GUI 快捷键族 / 脚本 API 族)见 [[commands]];版本差异、无头批处理与脚本 API 的更多坑见 [[gotchas]]

コメント