mcpField
R
rev-struct

rev-struct

github.com/p4nda0s开发2.3k1.9k 次安装25 周前更新
代码仓库

关于 rev-struct

rev-struct 是用于逆向分析的技能,通过函数内存访问和调用链推断数据结构布局。它可借助 IDA Pro MCP 查询,也支持分析导出的反编译文件。

主要功能

  1. 01收集字段偏移和访问类型
  2. 02追踪调用者与被调用者
  3. 03推断字段类型和结构大小
  4. 04汇总证据生成结构分析

适用场景

  1. 01根据目标函数重建数据结构
  2. 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 导出数据:

  1. 检查是否存在 decompile/ 目录
  2. 检查其中是否有 .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:读取目标函数
  1. 根据用户提供的地址,读取 decompile/<address>.c
  2. 解析函数元数据,提取调用者和被调用者列表
  3. 识别函数中的指针参数(可能是结构体指针)
步骤 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:遍历调用者进行分析

读取每个调用者函数并分析:

  1. 参数传递:调用时传入了什么?

    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
    
  2. 调用前后的操作:

    v1 = malloc(0x40);     // allocate 0x40 bytes
    *v1 = 0;               // offset 0x00 initialization
    *(v1 + 8) = callback;  // offset 0x08 is a function pointer
    sub_401000(v1);
    
  3. 收集更多偏移访问

步骤 4:遍历被调用者进行分析

读取每个被调用者函数并分析:

  1. 参数的使用方式:

    // In callee
    int callee(void *a1) {
        return *(a1 + 0x18);  // accesses offset 0x18
    }
    
  2. 传递给其他函数:

    another_func(a1 + 0x20);  // offset 0x20 might be a nested struct
    
步骤 5:汇总并推断
  1. 合并所有偏移信息,并按偏移排序
  2. 计算结构体大小:max(offset) + last_field_size
  3. 推断字段类型:
    • 作为函数指针调用 → 函数指针
    • 传递给 strlen/printf → 字符串指针
    • 与常量比较 → 枚举/标志
    • 执行递增/递减操作 → 计数器/索引
  4. 识别常见模式:
    • 偏移 0 是函数指针表 → 虚函数表(C++ 对象)
    • next/prev 指针 → 链表节点
    • 引用计数字段 → 引用计数对象

输出格式

/*
 * 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

评论

支持 Markdown