Creuto is now an OpenAI Select Partner Read More
Can an agent reverse engineer legacy system logic you can ship? A Sept 2026 study found 4.9% of outputs pass every test and still drop behaviour.

In a benchmark published on 4 September 2026, 4.9% of decompiler outputs that built cleanly and passed every test shipped with their corpus still behaved differently from the original code. If you are deciding whether to reverse engineer legacy system logic with an agent, that is the number to plan around. The output compiles, the suite goes green, and some behaviour is quietly gone.
That is not an argument against doing it. Agent-driven reverse engineering is genuinely useful on a system you own and can no longer read. It is an argument about what the output is: a lead worth chasing, not a specification worth signing.
The situation is ordinary and it keeps happening. A company runs something important — a pricing engine, a dispatch scheduler, a payroll calculation — whose vendor has dissolved, whose author left in 2014, and whose source tree nobody can find. What exists is a running executable and a set of people who know roughly what it does.
Replacing it means first answering a question nobody in the building can answer: what does it actually do, including the parts that are wrong and that the business now depends on being wrong. That is the discovery phase, and on an undocumented system it is usually the longest and least predictable part of a legacy application modernization programme.
So the pitch lands hard. If an agent can read the binary and hand back readable C or Java, discovery stops being archaeology.
Take it at full strength before taking it apart.
The tooling is real and it is not a demo. REA, an MCP layer that lets a coding agent drive existing reverse-engineering engines, describes itself as "one MCP for reverse engineering across binaries, applications, and runtime behavior"; native analysis runs through an existing Hopper, Ghidra or IDA installation, and Android packages go through headless JADX. The repository was created on 14 April 2026 and, as of 21 October 2026, the GitHub API reports 355,039 stars on it. It is published under an MIT licence by a single anonymous account; we have no information about who maintains it.
The capability underneath it is also real. Traditional decompilers emit pseudocode that often will not compile, littered with placeholder types such as undefined4 and _DWORD and synthetic names such as uVar1 and DAT_*. An LLM reading that output produces clean, idiomatic C instead. In the benchmark's own numbers, the strongest refinement model lifted Ghidra's build rate on 291 real library functions from 75% to 90%.
And for discovery specifically, the artefact does not need to be perfect to be valuable. A readable reconstruction of a 400-line settlement routine tells you which tables it touches, which constants it carries, which branches exist. A week of that beats a month of reading disassembly. We think that part of the claim holds.
The paper is "When LLM Decompilers Recompile More and Preserve Less" (arXiv:2609.05370, 4 September 2026), by authors at Syracuse University and CrowdStrike. It is not an argument that decompiled code looks bad. It accepts that the code looks good and asks whether it still does the same thing.
The method matters for how much you should trust the result. Rather than relying on hand-written tests, the authors build a comparison oracle per function: synthesise a driver, fuzz the original with AFL++ to grow an input corpus, then run the decompiled version on exactly the same inputs and compare return values plus the bytes written to writable globals. Three outcomes: Matched, Divergence, or — on vulnerable code only — Crash Absence, where a crash the original is known to produce silently stops happening.
Across eight systems in nine configurations, of 12,133 candidates that passed every shipped test, 4.9% diverged anyway, and 77% of those did it by changing an output with no crash at all. For one system the figure reached 13%. Replaying candidates through the released suites, those suites missed between 3% and 45% of the behavioural divergence depending on the corpus.
On real code the trade-off is sharper. On 291 scored functions drawn from 132 libraries across 106 repositories with no released function-level tests, the refinement model that lifted Ghidra's build rate from 75% to 90% saw its Matched rate fall from 74% to 62%. The 28-point gap is 23 points of changed observable state and 5 points of newly introduced crashes. Per function, the front end alone matched 77 that the refiner missed; the refiner alone matched 42. Recompilability ranked the refiner higher. Behavioural agreement ranked the plain decompiler higher.
One sentence in the method section deserves to be read twice: because the comparison only covers generated inputs and a bounded view of state, the Matched rate is an upper bound on real agreement, while Divergence is a lower bound. The true drop is at least this bad.
This is the part that should change how you treat the output.
When a conventional decompiler cannot resolve something, it says so in the code. You get DAT_0041a0 and undefined4, and 43% of raw Ghidra's recompilation failures name exactly such a retained artefact. The unknown is annoying, and it is visible.
Turning *(_DWORD*)(a1+40) into idiomatic C requires the model to supply a field name, a type and sometimes a function that simply are not present in the binary. Measured across systems, LLM rewriters removed 40–98% of that placeholder vocabulary. What replaces it is a guess rendered in the same confident style as the parts it got right.
The association with wrong behaviour is strong. Among a given system's compiled outputs, functions containing an introduced field, type or callee diverged 53% of the time against 20% for invention-free functions on the library track, and 59% against 31% on the vulnerability track. The authors are careful that this is association, not proven causation — harder functions invite both — but the mechanism is legible in the diffs.
The benchmark's worked example is worth keeping in mind as a template for your own code. An ExeBench function mapping an index into six-column bands ships ten input/output pairs. Every argument in those ten sits between 0 and 124, so the narrower final band is never exercised and nothing overflows. Two different LLM decompilers recompiled it and passed all ten — then matched only 70 and 66 of 100 fuzzed inputs respectively. Raw Ghidra and Hex-Rays matched all 100.
On vulnerable code the same rewriting became a security property. Of 287 CVE-grounded functions, one refinement model lost the reference crash in 25 cases, 8.7% of the track, with a 95% confidence interval of 6.0% to 12.5%. Raw Ghidra lost none. The vulnerability did not get fixed; it got papered over, in code that builds and reads well.
If recovered logic can pass every test you have and still be wrong, then the tests you have are the problem, and the recovered source cannot be the thing you sign off.
The discipline that fits is the one the benchmark effectively reinvented: do not assert what the system should do, record what it does. Drive the old binary with real and generated inputs, capture its outputs as the expected values — bugs and all — and make that corpus the acceptance criteria for the replacement. We have written up how to put characterization tests on legacy code before refactoring in more detail.
Two practical consequences follow, and both are cheap to adopt.
| Artefact | What it is good for | What it must never be |
|---|---|---|
| Agent-recovered source | Finding the tables, constants, branches and integrations to ask about | The specification the rewrite is tested against |
| Characterization test corpus | The contract: observed inputs and observed outputs of the live system | A substitute for asking the business which behaviours are intentional |
| Recovered code marked "unknown" | A ranked list of what to investigate next | Something to clean up before review |
First, treat every unresolved placeholder as an asset. A reconstruction that still contains undefined4 is more honest than one that has been smoothed into plausible names, and the smoothing is where the divergence came from. Resist the instinct to tidy it.
Second, generate inputs rather than choosing them. The ten hand-picked pairs in that worked example were not unlucky; they were representative. Human-chosen cases cluster in the range where the code is obviously right, which is exactly where behaviour is already preserved. Our own write-up of AI refactoring across 300K lines runs into the same wall from the other direction.
Several common situations make agent reverse engineering a waste of a discovery budget, and two make it actively risky.
Where it does fit, it fits well: a system you own, a replacement you intend to behave identically, and a team willing to treat recovered code as a question list. The sequencing advice in our piece on how to modernise legacy systems without breaking your business does not change because an agent is doing the reading.
Keep these separate, because the tooling does not.
Reverse engineering a system your company owns, to replace it, is the case this post is about. Inspecting a competitor's shipped product is a different question with a different answer, and the answer depends on your jurisdiction, your licence terms and your purpose. REA's own README advertises the second use case directly, which tells you how easily the line gets crossed by default.
We are engineers, not lawyers, and we are not going to summarise exemption law for you — we looked, and the ground is thinner and more in flux than confident blog posts suggest. The operational rule is simple: if the artefact is not yours, your counsel decides before your agent starts, not after.
We should be precise, because this is a field where vendors imply experience they do not have.
Creuto has not used REA, Ghidra, IDA or any agentic reverse-engineering tool in client work. We have no field data on how these systems perform on a real legacy estate, and the numbers above are the benchmark authors', not ours.
What we have done is the discovery and replacement work this question sits inside: unifying four departments onto one platform in a custom ERP build, replacing payroll processing with a platform that runs it five times faster across 13+ modules, and taking a 100+ dealership sales training platform to market in 20 weeks. Our credibility here is about what to do with an uncertain specification, not about binary analysis.
So the next decision is not which reverse-engineering tool to adopt. It is whether you can drive your old system hard enough to record what it does. If you can, the agent is a useful accelerator on top of a contract you already hold. If you cannot, build that capability first — and if you want a second pair of eyes on whether your legacy estate is observable enough to replace safely, talk to us about the discovery phase before the rewrite is scoped.
An agent can reverse engineer legacy system binaries into readable source quickly, and that genuinely shortens discovery. A September 2026 benchmark found 4.9% of outputs that passed every shipped test still behaved differently from the original, so treat the result as a lead to investigate rather than a specification.
No. On 291 real library functions the refinement model that raised Ghidra's build rate from 75% to 90% saw behavioural agreement with the original fall from 74% to 62%. Recompilability and correctness came apart, so the recovered source should not be what the replacement is tested against.
Record what the system does rather than what it should do. Drive the running binary with real and generated inputs, capture the outputs as expected values including the bugs, and make that corpus the acceptance criteria. Agent-recovered source then tells you which inputs and integrations are worth probing.
Characterization tests assert a system's observed current behaviour instead of its intended behaviour. They matter because recovered logic can compile and pass every hand-written test while silently dropping a branch, so the observed-behaviour corpus becomes the contract the rewrite must satisfy.
Ghidra exposes what it cannot resolve as visible placeholders such as undefined4 and DAT_ names. LLM rewriters remove 40 to 98 percent of that vocabulary and must invent a field, type or callee instead. Functions containing such inventions diverged 53% of the time against 20% for invention-free ones.
Skip it when the source still exists somewhere, when the business wants a different process rather than the same one, when the important behaviour lives in scheduled jobs and integrations outside the binary, or when you cannot drive the old system safely enough to build a characterization corpus.
Reverse engineering a system your own company owns in order to replace it is a different question from inspecting a competitor's shipped product, and the second depends on jurisdiction, licence terms and purpose. Creuto are engineers, not lawyers, so have counsel decide the second case before any analysis starts.
Ready to take the first step towards unlocking opportunities, realizing goals, and embracing innovation? We're here and eager to connect.