mcpField
I
ida-domain-scripting

ida-domain-scripting

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

ida-domain-scripting について

ida-domain-scriptingは、バイナリ解析とリバースエンジニアリング向けのスキルです。ida-domainを通じてカスタムIDAPythonスクリプトを実行し、データベースは既定で読み取り専用、変更の保存には事前確認が必要です。

主な機能

  1. 01カスタムIDAPython解析スクリプト
  2. 02関数と文字列の検索
  3. 03クロスリファレンスとバイトパターンの解析
  4. 04疑似コードと制御フローの確認
  5. 05既定で読み取り専用実行

活用シーン

  1. 01バイナリ内の関数一覧の取得
  2. 02呼び出し元や文字列参照の検索
  3. 03疑似コードと制御フローの確認
  4. 04バイトパターンの検索

インストール

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

$npx skills add https://github.com/hexrayssa/claude-marketplace --skill ida-domain-scripting

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

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

API_REFERENCE.md
pyproject.toml
run.py
setup.py

詳細

重要 - パスの解決: このスキルは異なる場所にインストールできます。コマンドを実行する前に、この SKILL.md ファイルを読み込んだ場所に基づいてスキルディレクトリを特定し、以下のすべてのコマンドでそのパスを使用してください。$SKILL_DIR を特定した実際のパスに置き換えてください。

一般的なインストール先:

  • プロジェクト固有:<project>/.claude/skills/ida-domain-scripting
  • 手動でのグローバルインストール:~/.claude/skills/ida-domain-scripting

IDA Domain Scripting

汎用バイナリ解析スキルです。ご依頼のリバースエンジニアリングタスクに合わせてカスタム IDAPython コードを作成し、汎用エグゼキューターで実行します。

重要なワークフロー - 以下の手順を順番に実行してください:

  1. タイムスタンプ付きの作業ディレクトリを /tmp に作成する - スクリプトをスキルディレクトリに書き込んではいけません。必ず一意性を保つためマイクロ秒を含むタイムスタンプ付きの作業ディレクトリ /tmp/ida-domain-YYYYMMDD_HHMMSS_ffffff-<name> を作成してください(例: /tmp/ida-domain-20260109_143052_847291-list-functions)。 タイムスタンプは次の方法で生成します:datetime.now(). strftime ('%Y%m%d_%H%M%S_%f')。 以降、このディレクトリを <work_dir> として参照します。

  2. API_REFERENCE.md が存在することを確認する - $SKILL_DIR/API_REFERENCE.md が存在することを必ず確認してください。存在しない場合は、ブートストラップを実行するようユーザーに伝えてください。

  3. スキルディレクトリから実行する - 必ず次を実行してください: cd $SKILL_DIR && uv run python run.py <work_dir>/script.py -f <binary>

  4. 保存前に確認する - データベースを変更するスクリプトで --save を使う前に、必ずユーザーの明示的な確認を得てください。

仕組み

  1. 解析/抽出したい内容を説明します
  2. マイクロ秒付きのタイムスタンプを使用して、<work_dir>/script.py にカスタム IDA Domain API コードを作成します(並列実行に対応)
  3. 次のコマンドで実行します:cd $SKILL_DIR && uv run python run.py <work_dir>/script.py -f <binary>
  4. 結果がリアルタイムで表示されます
  5. スクリプトファイルは OS によって /tmp から自動的に削除されます

セットアップ(初回のみ)

cd $SKILL_DIR && uv run python setup.py

GitHub から ida-domain をクローンし、依存関係をインストールします。必要なのは一度だけです。

特定のバージョンを使用する場合:

uv run python setup.py --ref v0.1.0   # Specific release
uv run python setup.py --ref main     # Bleeding edge

要件:

  • uv パッケージマネージャー
  • git
  • IDA Pro 9.1+
  • IDA のインストール先を指す IDADIR 環境変数

実行パターン

ステップ 1:解析スクリプトを <work_dir> に書き込む

# <work_dir>/script.py
for func in db.functions:
    name = db.functions.get_name(func)
    print(f"{name}: 0x{func.start_ea:08X}")

ステップ 2:スキルディレクトリから実行する

cd $SKILL_DIR && uv run python run.py <work_dir>/script.py -f /path/to/binary

ステップ 3:結果を確認する

スクリプトは Database.open() の定型コードで自動的にラップされます。すべてのエンティティにアクセスするには、db 変数を使用できます。

よくあるパターン

すべての関数を一覧表示する
# <work_dir>/script.py
for func in db.functions:
    name = db.functions.get_name(func)
    size = func.end_ea - func.start_ea
    print(f"{name}: 0x{func.start_ea:08X} - 0x{func.end_ea:08X} ({size} bytes)")
名前で関数を検索する
# <work_dir>/script.py
func = db.functions.get_function_by_name("main")
if func:
    print(f"Found main at 0x{func.start_ea:08X}")

    # Get callers
    callers = db.functions.get_callers(func)
    print(f"Called by {len(callers)} functions:")
    for caller in callers:
        print(f"  - {db.functions.get_name(caller)}")
else:
    print("main not found")
文字列を検索する
# <work_dir>/script.py
import re

# Find all strings
for s in db.strings:
    print(f"0x{s.address:08X}: {s}")

# Find URLs
url_pattern = re.compile(r"https?://[\w./]+", re.IGNORECASE)
for s in db.strings:
    try:
        content = str(s)
        if url_pattern.search(content):
            print(f"URL found: {content}")
    except:
        pass
クロスリファレンスを解析する
# <work_dir>/script.py
# Get xrefs TO an address
target = 0x00401000
print(f"References TO 0x{target:08X}:")
for xref in db.xrefs.to_ea(target):
    print(f"  From 0x{xref.from_ea:08X} (type: {xref.type.name})")

# Get xrefs FROM an address
print(f"References FROM 0x{target:08X}:")
for xref in db.xrefs.from_ea(target):
    print(f"  To 0x{xref.to_ea:08X} (type: {xref.type.name})")
関数を逆コンパイルする
# <work_dir>/script.py
func = db.functions.get_function_by_name("main")
if func:
    try:
        lines = db.functions.get_pseudocode(func)
        print("\n".join(lines))
    except RuntimeError as e:
        print(f"Decompilation failed: {e}")
関数の複雑度を解析する
# <work_dir>/script.py
complex_funcs = []
for func in db.functions:
    flowchart = db.functions.get_flowchart(func)
    if flowchart:
        block_count = len(flowchart)
        edge_count = sum(b.count_successors() for b in flowchart)
        cyclomatic = edge_count - block_count + 2

        if cyclomatic > 10:
            name = db.functions.get_name(func)
            complex_funcs.append((name, func.start_ea, cyclomatic))

complex_funcs.sort(key=lambda x: x[2], reverse=True)
print("Most complex functions:")
for name, addr, cc in complex_funcs[:10]:
    print(f"  {name}: complexity={cc} at 0x{addr:08X}")
バイトパターンを検索する
# <work_dir>/script.py
# Search for NOP sled
pattern = b"\x90\x90\x90\x90"
results = db.bytes.find_binary_sequence(pattern)
for addr in results:
    print(f"Found NOP sled at 0x{addr:08X}")

# Search for x64 function prologue
prologue = b"\x55\x48\x89\xE5"  # push rbp; mov rbp, rsp
for addr in db.bytes.find_binary_sequence(prologue):
    print(f"Prologue at 0x{addr:08X}")
JSON にエクスポートする
# <work_dir>/script.py
import json
from pathlib import Path

functions = []
for func in db.functions:
    name = db.functions.get_name(func)
    functions.append({
        "name": name,
        "start": f"0x{func.start_ea:08X}",
        "end": f"0x{func.end_ea:08X}",
        "size": func.end_ea - func.start_ea,
    })

output = {"module": db.module, "functions": functions}
Path("/tmp/functions.json").write_text(json.dumps(output, indent=2))
print(f"Exported {len(functions)} functions to /tmp/functions.json")

インライン実行(簡単なタスク)

簡単な単発タスクでは、ファイルを作成せずにコードをインラインで実行できます。

# Quick function count
cd $SKILL_DIR && uv run python run.py -c "print(f'Functions: {len(db.functions)}')" -f binary

# Get binary info
cd $SKILL_DIR && uv run python run.py -c "print(f'{db.module}: {db.architecture} {db.bitness}-bit')" -f binary

インライン実行とファイルの使い分け:

  • インライン:簡単な単発タスク(関数の数を数える、バイナリ情報を取得する、シンボルの有無を確認する)
  • ファイル:複雑な解析、複数の手順を含むタスク、ユーザーが再実行する可能性のあるタスク

高度な使い方

IDA Domain API の包括的なドキュメントについては、API_REFERENCE.md を参照してください。

  • データベースのプロパティとメタデータ
  • 関数の列挙と解析
  • 文字列の検出と検索
  • クロスリファレンスのクエリ
  • バイトパターンの照合
  • 制御フロー解析
  • 逆コンパイル(Hex-Rays)
  • 型情報
  • コメントと名前

ヒント

  • デフォルトは読み取り専用です - 変更を永続化する場合にのみ --save を使用してください(必ず事前にユーザーに確認してください!)
  • タイムアウト - デフォルトは 30 分です。長時間の解析には --timeout 0 を使用してください
  • ラップなしモード - スクリプトに Database.open() がすでに含まれている場合は --no-wrap を使用してください
  • エラー処理 - 逆コンパイルと文字列操作には、必ず try-except を使用してください
  • None の確認 - get_function_by_name() などの関数は、見つからない場合に None を返します

トラブルシューティング

エラーが発生した場合: まず、$SKILL_DIR/ida-domain/ida_domain/ 内でメソッドシグネチャを検索し、ida-domain のソースコードを確認してください。 API がドキュメントの記載や想定と異なる場合があります。

仮想環境が見つからない場合:

cd $SKILL_DIR && uv run python setup.py

IDA SDK の読み込みに失敗する/IDADIR エラーが発生する場合:

export IDADIR=/path/to/ida

スクリプトがタイムアウトする場合:

cd $SKILL_DIR && uv run python run.py --timeout 3600 ...  # 1 hour
cd $SKILL_DIR && uv run python run.py --timeout 0 ...     # No timeout

AttributeError: 'Xrefs' has no attribute 'get_xrefs_to': db.xrefs.get_xrefs_to(addr) ではなく、db.xrefs.to_ea(addr) を使用してください。

func_t オブジェクトで AttributeError が発生する場合: func オブジェクトではなく、db.functions のメソッドを呼び出してください。

# Wrong: func.get_callers()
# Right: db.functions.get_callers(func)

文字列の読み取り時に UnicodeDecodeError が発生する場合:

for s in db.strings:
    try:
        content = str(s)
    except:
        continue  # Skip problematic strings

使用例

User: "How many functions are in this binary?"

Claude: I'll count the functions. Let me analyze the binary...
[Writes: <work_dir>/script.py]
[Runs: cd $SKILL_DIR && uv run python run.py <work_dir>/script.py -f binary]
[Output: Functions: 250]

The binary contains 250 functions.
User: "Find all functions that call malloc"

Claude: I'll find all callers of malloc...
[Writes: <work_dir>/script.py]
[Runs: cd $SKILL_DIR && uv run python run.py <work_dir>/script.py -f binary]
[Output: malloc called by 15 functions: sub_401000, sub_402000, ...]

Found 15 functions that call malloc:
- sub_401000 at 0x00401000
- sub_402000 at 0x00402000
...
User: "Decompile the main function and save it"

Claude: I'll decompile main and save the output...
[Writes: <work_dir>/script.py]
[Runs: cd $SKILL_DIR && uv run python run.py <work_dir>/script.py -f binary]
[Output: Saved to /tmp/main.c]

Done! The decompiled code is saved to /tmp/main.c

コメント