rev-struct について
rev-structは、関数のメモリアクセスと呼び出し関係からデータ構造の配置を推定するリバースエンジニアリング用スキルです。IDA Pro MCPでの照会と、エクスポート済みコードの解析に対応します。
主な機能
- 01フィールドのオフセットとアクセス型の収集
- 02呼び出し元と呼び出し先の追跡
- 03フィールド型と構造体サイズの推定
- 04情報を統合した構造体分析
活用シーン
- 01対象関数から構造体を復元
- 02関数間でのフィールド受け渡しを調査
MCP 対応
IDA Pro MCPが接続されている場合はIDAを直接照会し、未接続の場合はIDA-NO-MCPのエクスポートデータを解析します。
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ p4nda0s/ reverse-skills --skill rev-structインストール後、Claude Code で/rev-structを入力して読み込まれたか確認します。
詳細
rev-struct - 構造体の復元
関数とその呼び出しチェーンにおけるメモリアクセスパターンを分析し、データ構造の定義を復元します。
事前確認
利用可能な IDA アクセス方法を確認します:
オプション A — IDA Pro MCP(接続されている場合は推奨):
IDA Pro MCP サーバーが接続されているか確認します(アクティブな ida-pro または同等の MCP 接続を探します)。接続されている場合は、MCP ツール経由で IDA に直接問い合わせることができ、エクスポート済みファイルは不要です。MCP を使って分析を進めてください。
オプション B — IDA-NO-MCP のエクスポートデータ: MCP が接続されていない場合は、現在のディレクトリに IDA-NO-MCP のエクスポートデータがあるか確認します:
decompile/ディレクトリが存在するか確認します- その中に
.cファイルがあるか確認します
MCP とエクスポートデータのどちらも利用できない場合は、ユーザーに次のように問い合わせてください:
No IDA access method detected. Choose one of the following:
Option A — IDA Pro MCP (recommended):
Connect the IDA Pro MCP server so Claude can query IDA directly.
Option B — IDA-NO-MCP export:
1. Download plugin: https://github.com/P4nda0s/IDA-NO-MCP
2. Copy INP.py to IDA plugins directory
3. Press Ctrl-Shift-E in IDA to export
4. Open the exported directory with Claude Code
エクスポートディレクトリの構成
./
├── decompile/ # Decompiled C code directory
│ ├── 0x401000.c # One file per function, named by hex address
│ ├── 0x401234.c
│ └── ...
├── decompile_failed.txt # Failed decompilation list
├── decompile_skipped.txt # Skipped functions list
├── strings.txt # String table (address, length, type, content)
├── imports.txt # Import table (address:function_name)
├── exports.txt # Export table (address:function_name)
└── memory/ # Memory hexdump (1MB chunks)
関数ファイルの形式(decompile/*.c)
各 .c ファイルには、関数のメタデータコメントと逆コンパイルされたコードが含まれています:
/*
* func-name: sub_401000
* func-address: 0x401000
* callers: 0x402000, 0x403000 // List of functions that call this function
* callees: 0x404000, 0x405000 // List of functions called by this function
*/
int __fastcall sub_401000(int a1, int a2)
{
// Decompiled code...
}
構造体の復元手順
ステップ 1:対象関数を読む
- ユーザーが指定したアドレスに基づき、
decompile/<address>.cを読みます - 関数のメタデータを解析し、呼び出し元と呼び出し先の一覧を抽出します
- 関数内のポインタ引数を特定します(構造体ポインタの可能性があります)
ステップ 2:メモリアクセスパターンを収集する
対象関数内で次のパターンを探します:
直接オフセットアクセス:
*(a1 + 0x10) // offset 0x10
*(_DWORD *)(a1 + 8) // offset 0x8, DWORD type
*(_QWORD *)(a1 + 0x20) // offset 0x20, QWORD type
*(_BYTE *)(a1 + 4) // offset 0x4, BYTE type
配列アクセス:
*(a1 + 8 * i) // array, element size 8 bytes
a1[i] // array access
ネストした構造体:
*(*a1 + 0x10) // first field of struct pointed by a1 is a pointer
レコード形式:
offset=0x00, size=8, access=read/write, type=QWORD
offset=0x08, size=4, access=read, type=DWORD
...
ステップ 3:呼び出し元をたどって分析する
各呼び出し元の関数を読み、次の点を分析します:
-
引数の受け渡し:呼び出し時に何が渡されていますか?
sub_401000(v1); // v1 might be a struct pointer sub_401000(&v2); // v2 is a struct sub_401000(malloc(64)); // struct size is ~64 bytes -
呼び出し前後の処理:
v1 = malloc(0x40); // allocate 0x40 bytes *v1 = 0; // offset 0x00 initialization *(v1 + 8) = callback; // offset 0x08 is a function pointer sub_401000(v1); -
オフセットアクセスをさらに収集します
ステップ 4:呼び出し先をたどって分析する
各呼び出し先の関数を読み、次の点を分析します:
-
引数の使用方法:
// In callee int callee(void *a1) { return *(a1 + 0x18); // accesses offset 0x18 } -
他の関数への受け渡し:
another_func(a1 + 0x20); // offset 0x20 might be a nested struct
ステップ 5:集約して推定する
- すべてのオフセット情報を統合し、オフセット順に並べます
- 構造体のサイズを計算します:max(offset) + last_field_size
- フィールドの型を推定します:
- 関数ポインタとして呼び出される → 関数ポインタ
strlen/printfに渡される → 文字列ポインタ- 定数と比較される → 列挙型/フラグ
- インクリメント/デクリメント操作 → カウンター/インデックス
- 一般的なパターンを特定します:
- オフセット 0 が関数ポインタテーブル → vtable(C++ オブジェクト)
- next/prev ポインタ → リンクリストノード
- refcount フィールド → 参照カウント方式のオブジェクト
出力形式
/*
* Structure Recovery Analysis
* Source function: <func_address>
* Analysis scope: <number of callers/callees analyzed>
*
* Functions using this struct:
* - 0x401000 (initialization)
* - 0x401100 (field access)
* - 0x401200 (destruction)
*/
// Estimated size: 0x48 bytes
// Confidence: High / Medium / Low
struct suggested_name {
/* 0x00 */ void *vtable; // vtable pointer, called: (*(*this))()
/* 0x08 */ int refcount; // reference count, has ++/-- operations
/* 0x0C */ int flags; // flags, AND with 0x1, 0x2
/* 0x10 */ char *name; // string, passed to strlen/printf
/* 0x18 */ void *data; // data pointer
/* 0x20 */ size_t size; // size field
/* 0x28 */ struct node *next; // linked list next pointer
/* 0x30 */ struct node *prev; // linked list prev pointer
/* 0x38 */ callback_fn handler; // callback function
/* 0x40 */ void *user_data; // user data
};
// Field access examples:
// 0x401000: *(this + 0x08) += 1; // refcount++
// 0x401100: printf("%s", *(this + 0x10)); // print name