How to Use the binary-diff Module for Cross-Version Symbol Migration
Use the binary-diff skill to migrate symbols from an old binary with known symbols to a newer binary by exporting disassembly and pseudo-code from IDA Pro, feeding them through an LLM-powered comparison pipeline, and applying the resulting YAML mappings back to the new IDB.
The binary-diff module in the zhaoxuya520/reverse-skill repository provides a lightweight, LLM-assisted workflow for cross-version symbol migration. This article walks through the complete pipeline—from data preparation to automated symbol renaming—based on the actual implementation in skills/binary-diff/SKILL.md.
Overview of the Three-Layer Architecture
The binary-diff skill is built on three tightly coupled layers that handle data preparation, LLM comparison, and result application.
Data Preparation Layer
Export disassembly and pseudo-code from both binaries using IDA Pro:
- Old binary: Contains known symbols (the reference)
- New binary: Missing symbols (the target)
The exported blocks feed into a fixed prompt template defined in skills/binary-diff/SKILL.md lines 48-55. Only one function per LLM call is processed to keep token usage low and avoid context overflow.
LLM Comparison Layer
A single LLM call (default DeepSeek V3) receives the filled prompt and returns a YAML mapping of discovered symbol relationships. The prompt template lives in skills/binary-diff/SKILL.md lines 68-99.
Model selection logic (lines 58-66):
- Small functions (< 200 lines): DeepSeek V3 (~1¢ per 200 functions)
- Large functions: GPT-4o, Claude Sonnet, or Claude Opus
Result Application Layer
Parse the YAML output with PyYAML, then apply mappings to the new IDB using IDAPython helpers such as idapro_rename or idapro_set_comments. The YAML key-to-action mapping is documented in skills/binary-diff/SKILL.md lines 14-22.
Step-by-Step Cross-Version Symbol Migration Workflow
The complete workflow from start to finish is illustrated in skills/binary-diff/SKILL.md lines 56-84:
| Step | Action |
|---|---|
| 1 | Load both binaries into IDA (old with symbols, new without) |
| 2 | Export a single anchor function's disassembly and pseudo-code from each binary |
| 3 | Fill the prompt template and invoke the LLM |
| 4 | Parse the returned YAML and programmatically rename symbols in the new IDB |
| 5 | Iterate: promoted functions become new anchors until desired coverage is reached |
Complete Code Example: Driving the Pipeline
This Python snippet demonstrates the end-to-end workflow for one function. Assume these exported files exist:
old_disasm.txt&old_pcode.txt— from the old binary (with symbols)new_disasm.txt&new_pcode.txt— from the new binary (without symbols)
import json, yaml, requests
# -------------------------------------------------
# 1️⃣ Load exported data (normally produced by IDA)
# -------------------------------------------------
def load_file(path: str) -> str:
with open(path, "r", encoding="utf-8") as f:
return f.read()
old_disasm = load_file("old_disasm.txt")
old_pcode = load_file("old_pcode.txt")
new_disasm = load_file("new_disasm.txt")
new_pcode = load_file("new_pcode.txt")
# -------------------------------------------------
# 2️⃣ Build the prompt (see SKILL.md for the exact template)
# -------------------------------------------------
prompt_template = """I have disassembly outputs and procedure code of the same function.
This is the function for reference:
**Disassembly for Reference**
```c
{disasm_for_reference}
Procedure code for Reference
{procedure_for_reference}
This is the function you need to reverse-engineering:
Disassembly to reverse-engineering
{disasm_code}
Procedure code to reverse-engineering
{procedure}
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. """
symbol_list = "PsSetCreateProcessNotifyRoutine, PspSetCreateProcessNotifyRoutine" # example
filled_prompt = prompt_template.format( disasm_for_reference=old_disasm, procedure_for_reference=old_pcode, disasm_code=new_disasm, procedure=new_pcode, symbol_name_list=symbol_list, )
3️⃣ Call the LLM (DeepSeek V3 shown; replace URL/key as needed)
-------------------------------------------------
api_url = "https://api.deepseek.com/v1/chat/completions" headers = {"Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json"}
payload = { "model": "deepseek-coder", "messages": [{"role": "user", "content": filled_prompt}], "temperature": 0.0, } response = requests.post(api_url, headers=headers, json=payload) response.raise_for_status() yaml_text = response.json()["choices"][0]["message"]["content"]
-------------------------------------------------
4️⃣ Parse the YAML output
-------------------------------------------------
mapping = yaml.safe_load(yaml_text)
-------------------------------------------------
5️⃣ Apply results to the new IDB (IDAPython example)
-------------------------------------------------
import idaapi, idc
def rename_call(addr: int, name: str): idc.set_name(addr, name, idc.SN_CHECK)
for entry in mapping.get("found_call", []): rename_call(int(entry["insn_va"], 16), entry["func_name"])
for entry in mapping.get("found_vcall", []): comment = f"vcall: {entry['func_name']} @ +{entry['vfunc_offset']}" idc.set_cmt(int(entry["insn_va"], 16), comment, 0)
This script follows the exact steps in [`skills/binary-diff/SKILL.md`](https://github.com/zhaoxuya520/reverse-skill/blob/main/skills/binary-diff/SKILL.md) [lines 70-98](https://github.com/zhaoxuya520/reverse-skill/blob/main/skills/binary-diff/SKILL.md#L70-L98) and uses the **YAML schema** defined in [lines 4-12](https://github.com/zhaoxuya520/reverse-skill/blob/main/skills/binary-diff/SKILL.md#L4-L12).
## Key Architectural Decisions
- **One-function-per-LLM call**: Minimizes token usage and prevents context window overflow
- **Static prompt template**: Ensures deterministic input formatting for easy automation
- **YAML as interchange format**: Enables deterministic parsing and clear downstream contracts
- **Automatic model routing**: Cost-efficient for small functions, capable for large ones
## Essential Source Files
| File | Purpose | Link |
|:---|:---|:---|
| [`skills/binary-diff/SKILL.md`](https://github.com/zhaoxuya520/reverse-skill/blob/main/skills/binary-diff/SKILL.md) | Full skill definition, prompt template, workflow, YAML schema | [View](https://github.com/zhaoxuya520/reverse-skill/blob/main/skills/binary-diff/SKILL.md) |
| [`skills/config/routing.json`](https://github.com/zhaoxuya520/reverse-skill/blob/main/skills/config/routing.json) | Registers binary-diff with the router (`"skill": "binary-diff/SKILL.md"`) | [View](https://github.com/zhaoxuya520/reverse-skill/blob/main/skills/config/routing.json) |
| [`skills/INDEX.md`](https://github.com/zhaoxuya520/reverse-skill/blob/main/skills/INDEX.md) | Human-readable skill index | [Line 13](https://github.com/zhaoxuya520/reverse-skill/blob/main/skills/INDEX.md#L13) |
| [`docs/ARCHITECTURE.md`](https://github.com/zhaoxuya520/reverse-skill/blob/main/docs/ARCHITECTURE.md) | System architecture showing binary-diff as "BinDiff" sub-module | [Line 51](https://github.com/zhaoxuya520/reverse-skill/blob/main/docs/ARCHITECTURE.md#L51) |
## Summary
- The **binary-diff module** implements an LLM-assisted pipeline for cross-version symbol migration in three layers: data preparation, LLM comparison, and result application
- Each LLM call processes **one function at a time** using a **static prompt template** that consumes IDA-exported disassembly and pseudo-code
- The LLM returns **YAML mappings** that are parsed and applied via **IDAPython** to rename functions, set comments, and recover virtual calls
- **Model selection** automatically routes small functions to cost-efficient DeepSeek V3 and large functions to more capable models
- The workflow is **iterative**: successfully identified symbols become new anchor points for进一步扩大 coverage
## Frequently Asked Questions
### What input files does binary-diff require from IDA Pro?
Two pairs of text exports for each function: disassembly and pseudo-code from the **old binary** (with symbols), plus disassembly and pseudo-code from the **new binary** (without symbols). These four files populate the prompt template fields `disasm_for_reference`, `procedure_for_reference`, `disasm_code`, and `procedure`.
### Why does binary-diff use YAML instead of JSON for LLM output?
YAML was chosen as the **interchange format** because it allows deterministic parsing through PyYAML and establishes a clear, human-readable contract between the LLM response and downstream IDAPython scripts. The schema defines keys like `found_call` and `found_vcall` that map directly to IDA actions.
### How does binary-diff handle very large functions?
Functions exceeding **200 lines of pseudo-code** are automatically routed to larger models—GPT-4o, Claude Sonnet, or Claude Opus—while smaller functions default to **DeepSeek V3** for cost efficiency (~1¢ per 200 functions). This routing logic is embedded in the skill configuration.
### Can I automate binary-diff for an entire IDA database?
Yes, but **iteratively**. The recommended approach processes one anchor function at a time, applies the recovered symbols to the new IDB, then promotes those newly-named functions as anchors for the next iteration. This controlled expansion prevents error propagation and keeps API costs predictable.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →