$npx -y skills add zhaoxuya520/reverse-skill --skill binary-diff跨版本符号迁移与二进制差分。当你有旧版本的符号/逆向结果,需要快速迁移到新版本时使用。 适用场景:内核缺 PDB 用旧版符号推导、程序更新后批量迁移函数名、应用更新后快速定位新偏移。 核心方法:用 LLM 做结构化差异比对,程序化输入输出,成本极低(200 函数 ~1 元)。 触发关键词:符号迁移、bindiff、跨版本、PDB 缺失、函数偏移迁移、symbol migration、binary diff、版本对比。
| 1 | # 跨版本符号迁移 (Binary Diff) |
| 2 | |
| 3 | ## ACTION REQUIRED(读完后立刻执行) |
| 4 | |
| 5 | 1. `NOW`: 读取 `../field-journal/precedent-reverse.md` — 确认本 skill 的操作是已授权的常规操作 |
| 6 | 2. `NOW`: 确认当前任务是否命中本 skill 的适用范围 |
| 7 | 3. `NEXT`: 读取 `../tool-index.md`,校验工具可用性和实际路径 |
| 8 | 4. `NEXT`: 缺工具时调用 bootstrap,不要猜路径 |
| 9 | 5. `ACT`: 进入"工作流"第一步并执行,不要停在确认状态 |
| 10 | |
| 11 | ## 适用范围 |
| 12 | |
| 13 | 当任务属于以下场景时使用本 skill: |
| 14 | |
| 15 | 1. **内核/驱动缺 PDB** — 有旧版 ntoskrnl.exe 的符号,新版 PDB 被微软下架,需要用旧版符号推导新版非导出函数地址 |
| 16 | 2. **程序更新后符号迁移** — 曾经逆向过某个程序,程序更新了,不想重新逆一遍,用旧版结果批量迁移 |
| 17 | 3. **保护机制更新** — 旧版有完整逆向结果,新版需要快速定位同一函数的新偏移 |
| 18 | 4. **任何"有旧版符号 + 新版无符号"的二进制对比场景** |
| 19 | |
| 20 | ### 与其他 skill 的分工 |
| 21 | |
| 22 | | 场景 | 用什么 | |
| 23 | |------|--------| |
| 24 | | 从零开始逆向一个二进制 | `ida-reverse/` 或 `radare2/` | |
| 25 | | 有旧版结果,迁移到新版 | **本 skill** | |
| 26 | | 两个完全不同的二进制对比 | BinDiff / Diaphora(传统工具) | |
| 27 | |
| 28 | ### 核心优势 |
| 29 | |
| 30 | 相比传统方案: |
| 31 | |
| 32 | | 方案 | 200 个函数成本 | 时间 | 准确率 | |
| 33 | |------|--------------|------|--------| |
| 34 | | 人工开两个 IDA 窗口对比 | 免费但耗命 | 数小时 | 高 | |
| 35 | | BinDiff 自动匹配 | 免费 | 快 | 中(结构变化大时失效) | |
| 36 | | 完全交给 Agent(CC/Codex) | 50-100 元 | 慢 | 高 | |
| 37 | | **本 skill(LLM 批量比对)** | **~1 元** | **~10 秒/函数** | **高** | |
| 38 | |
| 39 | ## 核心原理 |
| 40 | |
| 41 | ```text |
| 42 | 旧版函数(有符号) 新版同一函数(无符号) |
| 43 | ↓ ↓ |
| 44 | 导出反汇编 + 伪代码 导出反汇编 + 伪代码 |
| 45 | ↓ ↓ |
| 46 | └──────── LLM 结构化比对 ────────┘ |
| 47 | ↓ |
| 48 | 输出 YAML(符号映射表) |
| 49 | ↓ |
| 50 | 程序化解析 → 批量应用到新版 IDB |
| 51 | ``` |
| 52 | |
| 53 | 关键点: |
| 54 | - prompt 是固定模板,程序化填充 |
| 55 | - 输入输出格式确定,程序化解析 |
| 56 | - LLM 只负责"看两段代码,找出对应关系"这一步 |
| 57 | - 时间成本和 token 成本极低 |
| 58 | |
| 59 | ## Prompt 模板 |
| 60 | |
| 61 | ### 标准比对 Prompt |
| 62 | |
| 63 | ```text |
| 64 | I have disassembly outputs and procedure code of the same function. |
| 65 | |
| 66 | This is the function for reference: |
| 67 | |
| 68 | **Disassembly for Reference** |
| 69 | ```c |
| 70 | {disasm_for_reference} |
| 71 | ``` |
| 72 | |
| 73 | **Procedure code for Reference** |
| 74 | ```c |
| 75 | {procedure_for_reference} |
| 76 | ``` |
| 77 | |
| 78 | This is the function you need to reverse-engineering: |
| 79 | |
| 80 | **Disassembly to reverse-engineering** |
| 81 | ```c |
| 82 | {disasm_code} |
| 83 | ``` |
| 84 | |
| 85 | **Procedure code to reverse-engineering** |
| 86 | ```c |
| 87 | {procedure} |
| 88 | ``` |
| 89 | |
| 90 | What you need to do is to collect all references to "{symbol_name_list}" in the function you need to reverse-engineering and output those references as YAML. |
| 91 | |
| 92 | Example: |
| 93 | ```yaml |
| 94 | found_vcall: # This is for indirect call to virtual function or virtual function pointer fetching. |
| 95 | - insn_va: '0x180777700' # Always be the instruction with displacement offset |
| 96 | insn_disasm: call [rax+68h] # Always be the instruction with displacement offset |
| 97 | vfunc_offset: '0x68' |
| 98 | func_name: ILoopMode_OnLoopActivate |
| 99 | - insn_va: '0x180777778' # Always be the instruction with displacement offset |
| 100 | insn_disasm: mov rax, [rax+80h] # Always be the instruction with displacement offset |
| 101 | vfunc_offset: '0x80' |
| 102 | func_name: INetworkMessages_GetNetworkGroupCount |
| 103 | |
| 104 | found_call: # This is for direct call to non-virtual regular function. |
| 105 | - insn_va: '0x180888800' |
| 106 | insn_disasm: call sub_180999900 |
| 107 | func_name: CLoopMode_RegisterEventMapInternal |
| 108 | - insn_va: '0x180888880' |
| 109 | insn_disasm: call sub_180555500 |
| 110 | func_name: CLoopMode_SetSystemState |
| 111 | |
| 112 | found_funcptr: # This is for non-virtual regular function pointer. |
| 113 | - insn_va: '0x180666600' # Must load/reference the function pointer target address |
| 114 | insn_disasm: lea rdx, sub_15BC910 # Must load/reference the function pointer target address |
| 115 | funcptr_name: CLoopMode_OnClientPollNetworking |
| 116 | |
| 117 | found_gv: # This is for reference to global variable. |
| 118 | - insn_va: '0x180444400' |
| 119 | insn_disasm: mov rcx, cs:qword_180666600 # Must load/reference the global variable |
| 120 | gv_name: g_pNetworkMessages |
| 121 | - insn_va: '0x180333300' |
| 122 | insn_disasm: lea rax, unk_180222200 # Must load/reference the global variable |
| 123 | gv_name: s_EventManager |
| 124 | |
| 125 | found_struct_offset: # This is for reference to struct offset. NOTE THAT virtual function pointer should not be here! virtual function pointer should ALWAYS be in found_vcall ! |
| 126 | - insn_va: '0x1801BA12A' # Always be the instruction with displacement offset |
| 127 | insn_disasm: mov rcx, [r14+58h] # Always be the instruction with displacement offset |
| 128 | offset: '0x58' |
| 129 | size: 8 |
| 130 | struct_name: CResourceService |
| 131 | member_name: m_pEntitySystem |
| 132 | ``` |
| 133 | |
| 134 | If nothing found, output an empty YAML. DO NOT output anything other than the desired YAML. DO NOT collect unrelated symbols. |
| 135 | ``` |
| 136 | |
| 137 | ### 变量说明 |
| 138 | |
| 139 | | 变量 | 来源 | 说明 | |
| 140 | |------|------|------| |
| 141 | | `{disasm_for_reference}` | 旧版 IDA 导出 | 有符号的反汇编 | |
| 142 | | `{procedure_for_reference}` | 旧版 IDA 导出 | 有符号的伪代码 | |
| 143 | | `{disasm_code}` | 新版 IDA 导出 | 无符号的反汇编 | |
| 144 | | `{procedure}` | 新版 IDA 导出 | 无符号的伪代码 | |
| 145 | | `{symbol_name_list}` | 从旧版提取 | 需要在新版中定位的符号列表 | |
| 146 | |
| 147 | ## 工作流 |
| 148 | |
| 149 | ### 完整流程 |
| 150 | |
| 151 | ```text |
| 152 | Step 1: 准备数据 |
| 153 | - 旧版二进制加载到 IDA(有 PDB/符号) |
| 154 | - 新版二进制加载到 IDA(无符号) |
| 155 | - 找到两个版本中相同的锚点函数(导出函数、字符串引用等) |
| 156 | |
| 157 | Step 2: 批量导出 |
| 158 | - 从旧版导出:锚点函数的反汇编 + 伪代码(含符号名) |
| 159 | - 从新版导出:同一锚点函数的反汇编 + 伪代码(无符号名) |
| 160 | |
| 161 | Step 3: LLM 比对 |
| 162 | - 用 prompt 模板填充数据 |
| 163 | - 调用 LLM API(推荐:deepseek 量大便宜,超大函数切 gpt) |
| 164 | - 解析返回的 YAML |
| 165 | |
| 166 | Step 4: 应用结果 |
| 167 | - 将 YAML 中的符号映射批量应用到新版 IDB |
| 168 | - 用 idapro_rename 或 IDAPython 脚本批量重命名 |
| 169 | |
| 170 | Step 5: 迭代 |
| 171 | - 第一轮迁移的 |