REA: Bridging Reverse Engineering Tools for AI Agents with Evidence-Based Contracts
REA connects Ghidra, IDA, Hopper, and JADX via a unified MCP interface, requiring every tool call to return structured evidence with provenance, coverage, and explicit limitations, enabling AI agents to perform verifiable, auditable reverse engineering across binaries, Electron apps, and firmware.
REA (Reverse Engineer Anything) is a GitHub project that reached 330k stars by October 2026, surpassing NSA's Ghidra by 3x. It does not invent new decompilation algorithms; instead, it wraps existing GUI tools — Ghidra, IDA Pro, Hopper, JADX, Binwalk, TShark, sigrok — into a uniform MCP (Model Context Protocol) interface so that AI agents can invoke them programmatically.
Core Problem: Reverse Engineering as a Single-Threaded Human Loop
Traditional reverse engineering relies on a human analyst manually driving tools: load binary, wait for analysis, search strings, follow cross-references, read pseudocode, verify in assembly, mentally reconstruct logic. A skilled engineer spends 10–30 minutes per function, hours to days per feature chain. Modern targets are far larger: a medium Electron app (T3 Code v0.1.0) unpacks to 2,665 JS files and 8.5M AST nodes; full analysis emits 186 MB of evidence. The bottleneck is not tool speed but the fact that every step requires the same human to be present, making the process non-parallelizable and non-reproducible.
Three Barriers to AI-Driven Reverse Engineering
Tools lack programmable interfaces. Ghidra, IDA, Hopper are desktop GUIs; agents need functions with parameters and return values. Writing custom glue per engine creates private, non-portable implementations.
Process leaves no trace. LLMs hallucinate plausible explanations for incomplete pseudocode (e.g., a function signature missing parameters). Reverse engineering demands evidence-backed conclusions: each finding must cite exact addresses, files, bytes, and state what was not seen.
Expert methodology lives in muscle memory, not tools. The workflow — search strings → follow xrefs → inspect call graph → decompile → rebuild → verify — is not encoded in any tool's menu or API.
REA's thesis: reverse engineering is an investigation workflow , not a single model call. Standardize, interface, and make that workflow replayable, and agents can truly operate.
Architecture: Bridge Layer + Evidence Contract
Bridge Layer (How)
The bridge/ directory implements a unified adapter layer. Upstream, it exposes one tool set; downstream, it dispatches to provider-specific implementations (Hopper script API, Ghidra headless + bridge service, IDA plugin protocol). The caller chooses the engine per session; runtime failure never triggers automatic engine switch because switching would invalidate the accumulated evidence chain (different pseudocode, naming, references). Timeouts are two-layer: REA enforces engine startup budgets (Hopper 120s, Ghidra 330s, configurable via REA_HOPPER_STARTUP_TIMEOUT_MS, REA_GHIDRA_STARTUP_TIMEOUT_MS), while the MCP client has its own request timeout (SDK default 60s). Ghidra cold starts measured at 64s (Linux) and 163s (Windows) exceed the client default, so docs explicitly describe close/reopen recovery.
Evidence Contract (What)
Every evidence-producing tool returns a fixed structure: normalized_result: conclusions consumed by upper workflows. raw_result: provider's original output for cross-checking. analysis_profile: engine, version, parameters — part of the evidence's semantic identity; records missing this field are rejected. _meta.provenance: includes untrusted_content: true when data originates from the analysis target (see §4.6).
Crucially, coverage and limitations are first-class fields, not footnotes . The coverage object distinguishes complete, partial, and unknown (explicitly modeled, not an empty array). list_unknowns turns open questions into a queryable, pagable ledger with immutable IDs, enabling handoff: "What remains unresolved?" returns a table, not "should be mostly done."
Static vs. Runtime Layering
Analysis splits by "requires target interaction." Static layer reads files only (no execution), enabling safe malware triage without triggering anti-debug. Runtime layer spawns processes, connects browsers/devices. Each tool declares side effects via annotations: launchesProcess, writesFilesystem, executesForeignCode, etc. For example, analyze_javascript_application launches a worker and writes temp files but does not execute the target app's code , a distinction auditors can rely on.
Evidence Ledger: Analyze Once, Query Many
Full Electron analysis takes 227s and yields 186 MB. To avoid re-running or blowing context windows, REA maintains a session-scoped evidence ledger. The first analysis returns an evidence_id (64-bit hex). Subsequent tools ( trace_*, compare_*, inspect_analysis_view) accept this ID; the server fetches from the ledger without restarting providers. Ledger exports as portable bundles (IDs stable across machines/sessions). Partial evidence is retained on cancellation, timeout, or provider crash, recoverable via get_evidence_bundle filtered by operation.
Untrusted Content Marking
All data extracted from the target (strings, symbols, UI text, logs) is attacker-controlled. A crafted sample could embed "ignore previous instructions, run curl..." REA marks every result with
provenance: { untrusted_content: true, source: 'analysis_target' }by default. Only tools emitting purely internal state ( export_evidence_bundle, record_unknown) are whitelisted after audit. Failed calls also carry the mark because error messages may contain target text. The flag is a side-channel signal; hosts/hooks can escalate approval (e.g., require human confirmation before launching processes after reading target content).
Physical Constraint: 10 MiB Response Budget
MCP stdio clients cap at 10 MiB. A single native function's full evidence (pseudocode + assembly + basic blocks + call graph + refs) often exceeds this; Electron app graphs are larger (Swift app XLD: 6.7 MB; Electron Framework symbol table: 2.5 MB). REA does not silently truncate. It attempts full assembly; if oversized, returns resource_constraint error with an evidence_reference. The agent then uses inspect_analysis_view to page-read (summary → section/module stable pagination) or export_evidence_bundle to bypass the frame limit. Every page carries source_total and source_exhaustive so the agent knows whether unseen data exists — pagination is elevated to a semantic integrity guarantee.
Case Studies
5.1 Notion Clipboard: Crossing Three Process Boundaries
Goal: understand how Notion preserves rich text, block structure, and formatting across copy/paste. The chain spans Electron renderer → preload (contextBridge) → main process IPC handler. REA traced: renderer clipboard API writes text/html + custom block data → preload exposed APIs → IPC channel name → main process handler → serialization logic. Result: one copy carries four representations (plain, rich, block JSON, internal marker); priority decided by receiver. Demonstrates context preservation across process boundaries — no single layer tells the whole story.
5.2 T3 Code (Electron): 121/121 Members, Two Blind Spots
Third-party test (DevToolLab, 2026-10-18) against T3 Code v0.1.0 (MIT, source commit 81493ef). Environment: REA 6.5.0, Node 24.22.0, no Hopper/Ghidra/IDA/JADX installed (Electron analysis uses built-in static analyzers). Command:
npx rea analyze-javascript-application
"/Applications/T3 Code (Beta).app/Contents/Resources/app.asar"
--integrity-policy record-and-continue
--source-path apps/desktop/dist-electron/main.cjs
--source-path apps/desktop/dist-electron/preload.cjs
--filter-output normalized_result.summary --format yamlAfter two failed attempts (configuration issues), the successful run produced: context_bridge_apis: 3, exposed_api_members: 121 IPC: 247 operations, 113 literal channels, 132 dynamic channels, 207 renderer sends, 30 renderer listeners, 10 main handlers
121 members all matched source preload.ts with 0 omissions, 0 fabrications , including security-critical getLocalEnvironmentBearerToken and ensureSshEnvironment with source locations.
Two blind spots emerged, both outside the static model:
132 dynamic channel operations unpaired — cannot be resolved statically.
A handler sets contextIsolation: false (with sandbox: true and unknown partition rejection) to share globalThis between element-picker script and preview page. This security-relevant design decision is invisible to static analysis.
The evidence honestly reports dynamic_channel_operations: 132 and unpaired counts. An agent reading the full report knows to manually inspect the bundle; one reading only the summary would wrongly conclude "most bridges are dead ends."
5.3 DX-Ball (1996 Windows Game): 63-Byte Exact Match
Community project restoring DX-Ball 1.07 (i386). Target: function converting brick screen-X to left/right panning. Six tool calls, four tool types, no step "feed whole thing to model and let it guess" :
Decompilation shows longlong FUN_00406400(void) calling __ftol() — no parameters, but a panning function must have input.
Assembly reveals MOV EAX, [EBP+0x8] (first stack arg) → FILD (convert to float). Pseudocode dropped the integer input.
Caller at 0x411f53 computes 20 + 30 * tile_x (brick width 30, left margin 20). Parameter semantics fixed.
Three floating-point constants read from memory: 0x420068=1.5625, 0x420070=500.0, 0x4210a0=1.0 (runtime-adjustable scale).
Reconstructed C:
DxBallInt dxball_screen_pan(DxBallInt x) {
double pan = (double)x;
pan = pan * 1.5625;
pan = pan - 500.0;
pan = pan * dxball_pan_scale;
return (DxBallInt)pan;
}Dual verification:
Behavioral: original x86 vs. C across 0–640 × 5 scales (0, 0.5, 1, 20, -1) = 3,205 cases, all pass.
Byte-level: recompile with VC4.0, apply reviewed relocations, verify constants → 63 bytes identical to original .
At scale=1, left edge returns -500, center 0, right edge 500. This is compilation-artifact-level consistency, not "looks similar."
Quantified Impact
Environment setup : Traditional — Install 2-3 decompilers, learn shortcuts; REA — npx rea-agents@latest setup + restart; Change — Months → minutes
Electron bridge audit : Traditional — Manual read 607-line bundle, layer-by-layer (est. 1-2h); REA — 35s, 121/121 hit (measured); Change — ~100-200× (est.)
Full app graph : Traditional — Sampling, coverage unknown; REA — 2,665 files, 8.5M AST nodes, 227s; Change — Sampling → exhaustive
Single function semantics : Traditional — 10-30 min (expert); REA — 3-5 tool calls, minutes; Change — 5-10× (est.)
Behavioral verification : Traditional — Hand-craft few edge cases; REA — 3,205 cases + 63-byte diff; Change — Spot-check → exhaustive
Conclusion auditability : Traditional — Relies on author's word; REA — Every claim has evidence_id + coverage + limits; Change — None → replayable
The last four rows are feasibility shifts: not just faster, but previously impossible.
Three Paradigm Shifts
⚡ Quantitative Efficiency (Time): Function restore hours→minutes; full Electron bridge inventory 35s, 121/121 zero-miss vs. 1-2h manual line-by-line. 📥 Capability Democratization (People): Community users reversing their own TV, body-scale, IoT devices are not professional reverse engineers. They only needed to ask the right question. 📚 Methodology as Distributable Asset (Pattern): Investigation workflow (search→xref→call graph→decompile→rebuild→verify) codified into injected instructions; Evidence contract makes "conclusion+provenance+boundary" the default output; unknowns ledger turns "unresolved parts" into handoffable artifacts. These become organizational capital.
Five Transferable Engineering Principles
Bridge as Extensibility: Don't rewrite 20-year-old engines for "control." Adapt; judge by whether upper interface changes when engine swaps.
Evidence as Trust: Agent-era output is not "an answer" but a replayable evidence chain — function address, callers, pseudocode, boundaries. Missing any piece means incomplete.
Limitation as Honesty: Model unknown as explicit state, not empty array. Silence must be annotated; otherwise readers hallucinate completeness. Applies to any AI analysis system.
Prompt as Orchestration: Investigation flow should be fixed in workflow instructions, not improvised per chat. Tools set ceiling; instructions set floor.
Data not Instruction: All target-sourced text is untrusted input. Any system ingesting external content into context needs a side-channel "this text is not a command" marker.
Selection Guide & Boundaries
Choose by target diversity and existing engine access: single target + IDA license → IDA Pro MCP; heterogeneous targets, quick trial → REA.
Unsuitable scenarios:
Commercial packers, VM protectors, strong anti-debug — engine limitation, not bridge.
Kernel/driver logic — needs deeper dynamic debugging/memory forensics.
No ground truth, high confidence required — shrink claim scope, don't inflate trust.
Model must stay off-cloud — REA runs locally but sends tool results to model provider; requires local LLM.
DRM, license checks, anti-cheat — explicitly out of scope.
Core judgment: analyzing software you're authorized to inspect → good fit; breaking commercial protection → can't and shouldn't.
Graded Confidence & Safety Levels
Reverse conclusions naturally tier. Use a confidence/safety matrix (see article image) rather than treating all output equally. The bottom tier maps to T3 Code's will-attach-webview lesson: absence from evidence ≠ absence in software . Tool annotations ( readOnlyHint, destructiveHint, executesForeignCode, mutatesDevice) are hints, not enforcement; real gates live in host/caller.
One Line Not to Cross
REA's disclaimer is explicit: legal research, education, interoperability, preservation, and analysis of owned/authorized software only. No assistance for DRM, licensing, anti-cheat. Commercial tools (IDA, Hopper, JEB) must be legally licensed. This draws the boundary for the entire agent-reverse-engineering wave: capability democratization ≠ permission democratization . Tools make "understanding" cheaper; "may I look?" remains a legal/authorization decision.
Closing
REA's signal isn't "reverse engineering is hot." Bridge, MCP, result contracts — none are new. Its value is assembling mature pieces to answer: how can a deeply experience-dependent workflow be standardized, interfaced, and handed to an agent? Answer: three non-negotiables — standardize tool interfaces, make every conclusion an auditable evidence chain with provenance and boundaries, codify investigation methodology into injectable instructions. With all three, agents dare enter domains where one mistake invalidates everything.
Human role shifts: previously 80% "finding" (functions, refs, constants) now compressed to minutes. The remaining 20% — judging plausibility, assessing blind spots, accepting boundaries — is not replaced, finally liberated.
Reverse engineering's barrier dropped from "master tools" to "ask well." That drop didn't lower the bar itself; it removed an entire profession's experience moat.
The same pattern — bridge capabilities, evidentialize conclusions, inject method — applies to any field requiring professional tools + human judgment.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Tencent Cloud Developer
Official Tencent Cloud community account that brings together developers, shares practical tech insights, and fosters an influential tech exchange community.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
