Binary-Analysis LLM Copilot — Studying ReCopilot & a Lightweight RAG Baseline
A study of ReCopilot (Chen et al., 2025) — an expert LLM for binary analysis — together with my own independent, lightweight retrieval-augmented (RAG) reimplementation for function-name recovery.
Motivation
Binary analysis sits at the heart of cybersecurity work — from malware detection to vulnerability discovery — yet it remains one of the most labor-intensive tasks in the field. When source code is compiled and its debug symbols are stripped, all the meaningful context that makes code readable vanishes: function names become sub_1909, variables become a1 and v3, and data structures lose their identity. Decompilers like IDA Pro and Ghidra lift machine code back into C-like pseudo-code, but they cannot recover these lost symbols.
This is my day-to-day domain (automotive ECU reverse engineering), so I studied the current state of the art for applying LLMs to it — ReCopilot — in depth, and then built my own lightweight baseline to understand how much of the job is achievable without the heavy machinery ReCopilot uses.
Part 1 — Background: How ReCopilot Works (Chen et al., 2025)
The following summarizes the published ReCopilot system. It is their contribution, not mine; I include it because my baseline builds on its central idea.
The Core Problem: Semantic Gap in Decompiled Code
When a binary is stripped, debug symbols are removed. What remains is decompiled pseudo-code full of placeholder names. A real AES encryption function that reads clearly in source as AES_CBC_encrypt_buffer — with named structs (AES_ctx) and typed fields (RoundKey, Iv) — becomes sub_1909 with arguments a1, a2, a3 after stripping and decompilation, leaving analysts to reconstruct intent from offsets and arithmetic alone.
ReCopilot targets three levels of representation: clean source code, decompiled pseudo-code with symbols, and the hard case — stripped pseudo-code with only generic placeholders and raw offsets.
Dataset Construction
A major part of the ReCopilot work is a large-scale dataset built from scratch, since no adequate public one existed. Three pipelines collect binary functions at scale: compile-from-scratch (open-source packages compiled with controlled flags, functions extracted via DWARF), off-the-shelf artifacts (release + debug + source packages from Ubuntu/Debian), and CompileAgent (an LLM-driven build agent for ad-hoc GitHub projects). In total, over 100 million binary functions from 11,000+ projects, then sanitized and MinHash-deduplicated.
Each pretraining sample pairs three views of the same function — stripped pseudo-code, symbolized pseudo-code, and source with a natural-language comment — with the segments randomly shuffled to force bidirectional learning. The final pretraining corpus is 36 billion tokens.
For task fine-tuning, ReCopilot uses a generator–discriminator framework to synthesize Chain-of-Thought examples: a Generator writes reasoning without seeing ground truth; a Discriminator judges it for correctness and consistency. Passing examples become SFT data; failed-then-fixed ones become DPO chosen/rejected pairs. The final SFT set covers 14 binary-analysis tasks (name recovery, signature/variable/struct recovery, algorithm identification, summarization, decompilation improvement, and more).
Training Strategy
ReCopilot is trained in three stages on top of Qwen2.5-Coder-7B: Continued Pretraining (CPT) to inject binary-domain knowledge, Supervised Fine-Tuning (SFT) to follow structured instructions and emit JSON with CoT reasoning, and Direct Preference Optimization (DPO) to improve format compliance and reasoning coherence.
Context Enhancement
ReCopilot’s most transferable idea — and the one my baseline borrows — is that a single function rarely tells the whole story, so it augments the model with static-analysis context at inference time: a bidirectional call-graph traversal selects informative caller/callee functions (ranked by an informativeness score over names, string density, and callee names), and a custom data-flow engine injects alias annotations directly into the prompt.
ReCopilot’s Reported Results
On a from-scratch, full-binary benchmark (six tasks; leakage-free private test data), ReCopilot reportedly outperforms baseline tools by ~13% on average, and its 7B expert model reaches performance comparable to far larger general models (e.g. DeepSeek-V3, 671B) — supporting the thesis that domain-specific training beats raw scale for this task. Ablations credit CPT, DPO (format compliance), and data-flow context (struct tasks) as the main contributors.
Part 2 — My Contribution: A Lightweight RAG Baseline
Everything below is my own work: github.com/Emad-Mahmodi/binary-rag-copilot.
ReCopilot answers “how good can an LLM get at binary analysis if you train one properly?” I wanted the complementary question:
How much of function-name recovery is achievable with the context idea alone — no training, just retrieval + prompting of an off-the-shelf model?
That question needs a baseline, so I built one.
Method
symbol-bearing binary
│ objdump / llvm-objdump (tool-independent PLT→GOT→symbol resolution)
▼
per-function context ── callees ── callers ── disassembly ← RETRIEVAL
▼
hide the real name → build a context-augmented prompt ← AUGMENT
▼
LLM backend proposes a name (mock | OpenAI-compatible | Ollama) ← GENERATE
▼
score vs. the real name — exact / token-F1 / semantic-hit ← EVALUATE
Ground truth is free: a symbol-bearing binary already knows each function’s real name. I hide it, ask the pipeline to recover it from context, and score the guess. The call-context extraction reuses the call-graph tooling from my GPU graph-analytics project, and the disassembly parser resolves PLT calls to real symbols across both GNU objdump and LLVM llvm-objdump.
src/rag/, src/llm/, src/eval/). How it differs from ReCopilot
| ReCopilot (Chen et al.) | My baseline | |
|---|---|---|
| Core idea | LLM + static-analysis context | same idea |
| How the model is built | CPT + SFT + DPO on 36B tokens | no training — retrieval + prompting |
| Compute to reproduce | multi-GPU, weeks, private data | a laptop; default backend needs no GPU |
| Tasks | 14 | function-name recovery (extensible) |
| Runs offline, no API key | — | yes (mock backend) |
| Ceiling on quality | high (purpose-built model) | bounded by the general LLM plugged in |
Honest positioning: ReCopilot is the stronger system; mine is the cheap, fully-reproducible baseline that isolates how far context + prompting alone can go. Its pipeline can even serve ReCopilot’s own base model (Qwen2.5-Coder via Ollama) to measure exactly that.
Results (proof-of-concept)
Five methods scored on the same functions of a small symbol-bearing demo binary. The default backend is a transparent call-pattern heuristic — not an LLM — serving as an honest lower bound any real model should beat:
| Method | token-F1 | semantic-hit |
|---|---|---|
| majority-callee | 0.00 | 0.00 |
| heuristic (calls) | 0.36 | 0.60 |
| nearest-neighbor (RAG retrieval) | 0.00 | 0.00 |
| llm (mock lower-bound) | 0.36 | 0.60 |
| llm (Qwen2.5-Coder, Ollama) | plug in to fill | plug in to fill |
experiments/compare_methods.py in binary-rag-copilot. The call-pattern heuristic recovers 60% of names semantically; the retrieval baseline collapses under domain mismatch — motivating the LLM row. Example recoveries from call context alone: read_whole_file → read_file, print_banner → print_message, compare_names → compare_strings. Run it yourself: python experiments/run_name_recovery.py --binary examples/demo — the full command set is in the repo README.
Work in Progress
Three extensions are actively underway to turn this proof-of-concept into a meaningful study:
- Plug in a real LLM. Wiring Qwen2.5-Coder (ReCopilot’s own base family) through Ollama on my local NVIDIA T600 GPU, to fill the LLM row of the comparison table with a genuine number — so the claim becomes concrete: “context + prompting alone reaches X% semantic accuracy, versus the 60% call-pattern lower bound.”
- Add a second task. Extending the pipeline from function-name recovery to a second ReCopilot task — variable-type inference or one-line function summarization — moving from one task to two on the same context-retrieval backbone.
- Evaluate on a larger corpus. Running the study over many symbol-bearing binaries instead of the demo pair, so the metrics become statistically meaningful rather than illustrative. The harness already accepts multiple corpus/test binaries (
--corpus a b c --test d).
Progress is tracked in the repository roadmap.
Attribution & Reference
The system studied in Part 1 is not my work. Full credit to its authors:
ReCopilot: Reverse Engineering Copilot in Binary Analysis
Guoqiang Chen, Huiqi Sun, Daguang Liu, Zhiqi Wang, Qiang Wang, Bin Yin, Lu Liu, Lingyun Ying
QI-ANXIN Technology Research Institute, Beijing, China
arXiv:2505.16366 — May 2025 · project code
My own independent baseline (Part 2): github.com/Emad-Mahmodi/binary-rag-copilot. All figures above are reproduced from the ReCopilot paper for the purpose of study and are credited accordingly.