Retargetable Headless Executable Analyzer
Reverse engineering for AI agents: an agent asks a concrete question about a program, RHEXA answers it across several analysis techniques and backs every finding with evidence. Deep static analysis is handled by the Rhexa Engine, an independently developed, purely headless derivative of Ghidra that is built into RHEXA.
Overview
RHEXA is one product built from two technology stacks in a single repository. The agent layer talks to AI agents, the engine analyses machine code. Both are connected through a versioned contract and can be built, tested and shipped independently.
One analysis tool
Static binary analysis has exactly one deep analyser: the Rhexa Engine. Hopper, IDA, JEB, Cutter, Rizin and objdump are replaced step by step as soon as the engine demonstrably covers the capability in use.
Evidence, not claims
Every answer carries the artefact identity, engine and contract version, parameters and location. Observation, inference, hypothesis and open question stay separate; missing coverage is stated openly.
Headless and independent
The engine needs no user interface. It is built, tested and shipped in the repository and does not follow Ghidra by merging; security fixes are adopted individually and traceably.
Starting point
RHEXA does not start from scratch. It brings together two mature open source projects whose strengths complement each other, but each was built for a different purpose.
REA – the agent layer
"Reverse Engineer Anything" is an MCP server with a command line through which AI
agents examine native programs, web and Electron applications, .NET, Android,
firmware, WebAssembly and more. Imported at commit efbc486.
- 207 tools in the MCP catalogue, about 300,000 lines of production and 186,000 lines of test code
- Several deep analysers side by side: Ghidra, Hopper and IDA, plus objdump, Rizin, Cutter and JEB
- Ghidra had to be installed separately; the bridge was compiled as a script with the Java compiler on every start
- No reproducible proof that a change actually improves analyses
- The Linux runs against real Ghidra were not part of CI and had silently outdated expectations
Ghidra – the analysis engine
The software reverse engineering framework with one of the best freely available decompilers, processor models for dozens of architectures and extensive analysis modules. Imported as an unmodified source snapshot without Git history.
- About 2.28 million lines of Java in 12,837 files, plus native C++ code for the decompiler and Sleigh
- Built as a desktop tool: about 830,000 lines of Swing user interface with 240 plugins
- Multi-user server, debugger, version control, graph and diff views that automated analysis does not need
- Java 21 as the minimum version, build designed for Gradle 8.5
- 153 known vulnerability findings in bundled third-party libraries, mostly in the server part
Why a separate derivative?
An AI agent does not need windows, it needs fast answers backed by evidence. Running headless, RHEXA uses only about 19 % of the engine classes. The rest costs start-up time, enlarges the attack surface and makes further development harder. With its own lean engine in the same repository, analysis and agent layer can be improved together, tested together and shipped as one product.
RHEXA is an independent project. It is not affiliated with the authors of REA or the National Security Agency and is neither supported nor endorsed by them. A name of its own is necessary because the Apache licence grants no rights to the name "Ghidra" and "REA" belongs to the original.
How it works
How RHEXA answers a question such as "Which function checks the licence key, and against which constant?"
Ask
The agent formulates a concrete analysis question and opens the target with
open_binary. RHEXA determines format, architecture and the matching
analysis path.
Analyse
The Rhexa Engine imports the program headless, recognises functions, references and data types and decompiles on demand. The target file itself is never modified.
Look selectively
Instead of loading whole inventories, the agent calls only the tools it needs: strings, procedures, pseudocode, memory contents. Tool schemas are loaded on demand.
Answer with evidence
Every result is recorded with its provenance in the evidence ledger. The answer names address, constant and location; what is unknown is marked as unknown.
Add runtime data
Where static analysis is not enough, RHEXA observes processes, browsers or Frida sessions and links the runtime evidence to the static model.
Measure
A reproducible benchmark checks every change for quality, tokens, cost, CPU and memory. An improvement that loses evidence does not count.
What is already better
Every change is a separate, traceable commit with a rationale and verification.
| Area | Before | Now |
|---|---|---|
| Test coverage of the agent layer | 90.8 % lines / 82.0 % branches | 97.1 % / 91.3 % |
| Dependencies | partly outdated | all npm packages and CI actions on the latest stable release |
| Vulnerability checks | no baseline | npm: 690 packages, 0 findings · engine: regular OWASP scan |
| Vulnerability findings in the engine distribution | 153 (17 critical) | 12 (0 critical) |
| Java and build | Java 21, Gradle 8.5+, more than 2,000 Gradle warnings | Java 25 (LTS), Gradle 9.8.1 with a verified checksum, legacy cleaned up |
| Engine scope | complete desktop application with server and debugger | server, 28 modules and about 1,450 GUI source files removed; GUI removal in progress |
| Proof of improvements | none | task benchmark with baseline, comparison with tolerance |
| Agent missteps before opening a target | 7 per benchmark run | 0, median tokens −11 % |
| Verification runs against the engine | not in CI, partly with outdated expectations | 13 of 19 green against the self-build, dedicated engine CI |
Changes compared with REA
- Much broader test coverageCoverage raised by 6 and 9 percentage points, thresholds raised accordingly.
- All dependencies currentnpm packages and GitHub Actions on the latest stable release, minimum Node.js version raised.
- Vulnerability scanningnpm audit and OSV-Scanner with a time-limited allowance list.
- Session lifecycle bug fixedReopening the same target started the engine early and could miss a changed source file. The bug exists in the original.
- Reproducible task benchmarkFive analysis tasks with an answer key, an isolated agent, measurement of quality, tokens, cost, CPU and memory.
- Better agent guidanceA hint in the server instructions removed all calls made before opening a target.
- Verification scripts correctedThree outdated expectations in the Ghidra runs (MIPS attributes, rejection of truncated ELF files, CET jump instructions) that are also present in the original.
Changes compared with Ghidra 12.1.4
- Ghidra Server removedMulti-user server including its service wrapper and outdated networking library removed.
- Modern toolchainJava 25 as minimum version and bytecode target, Gradle 9.8.1, Gradle 10 legacy cleaned up in 32 build scripts.
- GUI removal, wave 128 modules without relevance for headless analysis removed, including the debugger complex and diff and graph views; verified with verification runs, unit and integration tests.
- Dedicated engine CIBuild, unit tests, coverage and vulnerability scanning run separately from the agent layer.
- Safety net for the rebuild128 headless integration test classes with 1,832 tests, plus more than 8,000 unit tests, the agent layer's verification runs and the benchmark.
Measurements
| Measurement | Result |
|---|---|
| Task benchmark (baseline) | 30 of 30 runs successful, no false claim |
| Task benchmark after the GUI removal | 30 of 30 runs successful, no false claim, cost as in the baseline (10.68 vs. 10.59 USD) |
| Task benchmark with compact result delivery (package B) | 30 of 30 runs successful, no false claim; tool responses −30%, 4.12 instead of 4.87 million tokens (−15.5%), 10.46 instead of 10.68 USD |
| Agent layer verification runs against the engine | 13 of 19 passed, none fails because of the engine; 6 need macOS, Windows or newer compilers |
| Engine unit tests (without UI) | 7,001 cases, 0 failures |
| Headless integration tests | 429 tests, 0 failures |
Start-up analyzeHeadless (small ELF, no analysis, median) | Ghidra 12.1.4: 4.81 s · RHEXA engine: 4.12 s (−14 %) |
| Engine classes loaded headless | 3,878 of 19,996 |
Roadmap
Two tracks run in parallel: the agent layer (TypeScript) and the engine (Java/C++). Gates separate the phases. A gate only passes if the benchmark loses no evidence and needs no more tokens. Time frames are planning ranges for a deliberately narrow first scope, not commitments.
Phases at a glance
- Self-build on Java 25 and Gradle 9.8.1, tests and coverage baseline
- Vulnerability baselines for both stacks, Ghidra Server removed
- Task benchmark with baseline, engine CI, session lifecycle bug fixed
- ✓ Upfront: Ghidra Server removed (vulnerability findings 153 → 12)
- ✓ Wave 1: 28 modules without headless relevance removed (debugger, emulation, ByteViewer, diff and graph views)
- ✓ Wave 2: about 1,450 unreachable source files and more than 200 GUI tests removed
- ✓ Wave 3: 69 UI-free classes moved from the window modules into the UI-free base module
- ✓ Wave 4: gateways decoupled: options and help references, colours and icons, task execution, prompts, script dialogs
- ✓ Wave 5: edges from the headless core into the UI cut, window, help and theme frameworks and the tool layer deleted; the engine is headless only and starts 14 % faster
- Rename to RHEXA including engine branding (done)
- Bridge to the engine as a real, tested engine module (done)
- One shared, versioned contract checked by both stacks (done)
- Leaner, task-oriented result delivery (done: tool responses −30%)
rhexa engine installwith verified release archives per platform- Shorter start-up (class archive, leaner analysis profiles)
- Replace the first external tools: objdump, Rizin, Cutter
- ✓ Switch to the latest MCP revision 2026-07-28 done (older revision only as a transition; Claude Code already speaks the new one)
- Remove Hopper, IDA and JEB
- Persistent investigation projects and persistent engine projects
- Trace a feature end to end: user interface → native code → effect
- Reconstructions with executable proof
- Own analyzers in the engine, deeper type recovery
- Semantic comparison of two builds
- New, lean web interface (Thymeleaf), first as a status and monitoring view
- Unified transport on Windows, integration of BSim and Function ID
- Event-based process observation
- One domain module after a three- to five-day feasibility study
- Evaluate the engine debugger as a runtime source, further toolchain upgrades
GUI removal in detail
Ghidra's Swing UI was removed in five waves. Every wave was secured by the agent layer's verification runs, the engine unit tests and a net of headless integration tests, and committed separately.
| Wave | Content | Scope | Status |
|---|---|---|---|
| Upfront | Ghidra Server and its service wrapper removed | module, scripts, 21 tests; vulnerability findings 153 → 12 | done |
| Wave 1 | Modules without headless relevance: debugger complex, system emulation, ByteViewer, diff and graph views, screenshot generators | 28 modules; distribution 723 MB | done |
| Wave 2 | Source files not reachable from any headless path, determined from the class graph (jdeps), plus the tests of removed GUI features | about 1,450 production and more than 200 GUI test files; distribution 644 MB | done |
| Wave 3 | Move window-module classes the core uses that contain no UI themselves (settings, field locations, sort state, filter strategies, constants, task base types) into the UI-free base module Generic; Java packages stay the same. Swing building blocks are left for wave 4 | 69 classes and their tests; checked with 13 lanes, 7,643 unit and 1,512 headless integration tests | done |
| Wave 4 | Decouple the gateways through which the window framework comes along, in steps: 4a options and help references (done: options system and resource lookup UI-free, theme binding through an interface), 4b colours and icons (done: theme values through an interface, icon part of the data type helpers split off), 4c task execution (done: tasks, prompts and HTML helpers UI-free), 4d comment annotations, script headers and file filters (done), 4e script API dialogs (done; the tool layer follows with wave 5); pure UI parts go away with their windows in wave 5 | about 166 window-module classes that headless operation loads at run time today | done |
| Wave 5 | Clean-up in steps: 5a decoupled infrastructure that hung on the UI by a single edge (server client, links, Ghidra URL protocol, prompts, theme values), 5b script API without the tool (GUI methods such as goTo, show, askValues removed, GUI-only scripts deleted), 5c cut edges (PDB symbol servers, version tracking API, service providers by name, annotation click handlers), 5d deleted the window, help and theme frameworks, the tool layer and the rest of the UI world (about 2,700 classes, 550 test files); what headless needs, such as SARIF import, Jython, the ISF server and 17 bundled scripts, was decoupled instead of deleted. Multi-user merge on check-in is gone (the Ghidra server had already been removed) | start-up 4.81 s → 4.12 s (−14 %), class search 958 → 386 ms, module JARs 195 → 118; 13 verification runs, 7,001 unit and 429 headless integration tests green | done |
Engine work packages
P0 = prerequisite, P1 = immediate benefit, P2 = deepening, P3 = later option.
G0 Engine working on its own on the LTS toolchain P0 done
- Goal
- A demonstrably building, tested engine state without the agent layer, as the starting point for integration.
- Scope
- Build on Java 25 and current Gradle, unit and integration tests with a per-module coverage baseline, raised bytecode target, dedicated engine CI, dependency and vulnerability scan.
- Result
- All steps done; the Ghidra Server was removed as well (153 → 12 findings).
T0 Bug when reopening a target P0 done
- Finding
- Reopening the same target started the engine immediately and could then miss a changed source file.
- Result
- Fixed in the session lifecycle with a reproduction test; the verification run passes against the self-build.
T1 Rename to RHEXA P0 done
- Scope
- Display name,
rhexacommand, MCP key, configuration file, package name, about 210 environment variables (old names remain valid for one release), documentation; engine branding (application name, archive and settings names, start scripts). Java packages stay unchanged. - Acceptance
- RHEXA runs under its own name and does not collide with a parallel installation of the original.
- Status
- Name,
rhexacommand, MCP key, npm packagerhexa-agents, configuration and documentation are switched, as are theRHEXA_*environment variables; setREA_*values keep working with a notice for one major version. The verification lanes are calledverify:engine*. The engine is called Rhexa Engine and has its own archive (rhexaengine_…) and settings directory, so a parallel Ghidra keeps its settings. Internal prefixes (temporary directories, bridge class names) stay on purpose because they are not visible outside.
G1 Repository integration and guidelines P0 done
- Scope
- Licence documents describe the engine as a derivative work, own engine guidelines for provenance, individual upstream adoptions and security review, build integration into the repository tooling.
- Acceptance
- TypeScript checks stay unaffected by the Java part; licence documents name the engine.
- Result
- Licence documents describe Rhexa Engine as a derivative work under Apache 2.0. All 392 modified upstream files carry the change notice Apache 2.0 requires, and the engine CI checks this against the upstream tree. Engine guidelines cover provenance, adoptions and security review;
npm run engine:buildbuilds the engine from the repository tooling.
G2 Bridge as an engine module and shared contract source P0 done
- Scope
- The bridge becomes a compiled engine module tested with JUnit, split into dispatcher, serialiser and operation groups. The contract is maintained as JSON Schema, generating types for TypeScript and Java; a handshake checks the contract version.
- Acceptance
- All 28 operations run through the module, a deliberately mismatched schema makes both conformance tests fail, no Java compiler at runtime.
- Status
- The bridge is an engine module and runs pre-compiled with Rhexa Engine; a separately installed Ghidra still compiles it. Together with a converted Windows analyzer, no verification run loads the Java compiler any more. The bridge's 4,900 lines are split into protocol, dispatcher and eight operation groups, and 20 integration tests check the operations directly against an imported program. A versioned contract covering all 31 operations is generated from the agent layer's schemas; both sides check against it and against recorded responses of the real bridge, and the handshake refuses a foreign protocol version.
G3 Engine distribution and installation P0 in progress
- Scope
- Release archives per platform with a SHA-256 manifest,
rhexa engine install|status|remove, diagnostic checks, a separate Ghidra only as a developer option. - Acceptance
- On a fresh machine with Java 25, RHEXA delivers pseudocode after installation without further steps.
- Status
- Met for Linux x86-64:
rhexa engine installdownloads the engine from rhexa.janda.io, checks size and SHA-256 and installs it;rhexa decompilethen returns pseudocode, and every analysis names the engine's origin. Archives for macOS and Windows follow.
G4 Start-up time and removal of the Swing UI P1 in progress
- Starting point
- Headless runs load 3,878 of 19,996 classes; the UI is entangled with the core in only about 165 places (settings, task monitors, options, colours).
- Scope
- In waves: remove unused modules, delete unreachable classes, move entangled core classes into a UI-free module, remove the window, help and theme frameworks, drop GUI-only libraries; reduce start-up time with a class archive and leaner analysis profiles.
- Acceptance
- After every wave, engine tests, verification runs and benchmark pass; class list and start-up time documented before and after.
G5 Provider consolidation P1 in progress
- Order
- objdump → Rizin single commands and Cutter (replaced by curated engine scripts) → Hopper → IDA → JEB. Debug sessions remain until G9.
- Acceptance per step
- Parity matrix documented, tools rebound to the engine or removed with a migration note, a separate release marked as a breaking change.
- Status
- objdump: the parity matrix is in place. The new tool
inspect_object_filereads the header, sections, symbols and relocations of ELF, PE and Mach-O files straight from the original bytes through the engine's parser, paging large tables. DWARF compilation units and line tables are included;rhexa engine languageslists the engine's processor languages with their GNU names.disassemble_rangelists whole sections or address ranges without decoding data as code. Every objdump operation has its counterpart andinspect_with_objdumpis removed (a breaking change with a migration table). Mach-O chained fixups remain open. Rizin and Cutter: the parity matrix is in place. Free command lines are replaced byrun_engine_script, a fixed, versioned catalog of engine scripts with validated parameters:raw_strings(every text sequence in the file bytes),instruction_search(regular expressions over instruction text),function_graph(basic blocks and edges) andcpp_classes(C++ classes with vtable, type info and methods). Every other command family already had an engine tool.execute_rizin_commandand the Cutter bridge are removed (a breaking change with a migration table); Rizin debugger sessions stay until G9. Hopper comes next.
G6 Persistent engine projects P1 Phase 3
- Scope
- Own project format with a manifest (artefact hash, engine version, analysis profile, contract version), explicit open and save, invalidation when the artefact changes, a long-lived engine service holding several programs.
- Acceptance
- Investigations resume after a restart; a changed binary creates a new artefact version.
G7 Independent engine development P1 Phase 4
- Scope
- Developer documentation, own versioning scheme, own analyzers and loaders instead of script workarounds: repair of wrong no-return assumptions, MIPS soft-float, PSP, .NET NativeAOT.
- Acceptance
- An engine feature can be developed, tested and shipped without changing the agent layer.
G8 Windows unification P2 Phase 5
- Scope
- One transport path for all platforms; Windows loses its "read-only" special status.
G9 Engine debugger as a runtime source P3 Phase 6
- Scope
- Evaluate whether static and dynamic evidence can be merged in the same program model; decide only after a successful feasibility study.
Analysis work packages
A Reproducible task benchmarks P0 baseline available
- Problem
- A new feature or a shorter answer is no proof of better analysis.
- Scope
- Corpus of self-built programs with known solutions: find a function, explain a file write, detect a change between two builds, verify a static call dynamically, reimplement a function.
- Next steps
- Harder variants (stripped and optimised builds, indirect calls) so that quality gains become measurable too.
B Task-oriented, economical result delivery P0 done
- Scope
- Summaries first for inventory questions, reference evidence already read instead of sending it again, avoid duplicate serialisation; optionally hybrid search over symbols, full text and semantic search.
- Acceptance
- Fewer total tokens in the benchmark at the same answer quality.
- Status
- First step done: the opt-in profile
RHEXA_MCP_RESULT_TEXT_PROFILE=compactdelivers results without the duplicate copy and without the repeated analysis profile; the session keeps the complete evidence.rhexa setupsets it for Claude Code automatically. In the benchmark 30% smaller tool responses and 15.5% fewer tokens at the same quality (30 of 30 runs). A new task on a large statically linked program shows that agents reach the answer there by search rather than complete lists (6 of 6 correct), so separate inventory summaries are not needed.
C Persistent investigation projects P1 Phase 3
- Scope
- Named projects with automatic saving, a manifest, hypotheses and counter-evidence, resumption after a restart.
- Acceptance
- An investigation continues after a restart; contradictory evidence becomes visible.
D End-to-end tracing of a feature P1 Phase 4
- Scope
- A question such as "What happens on save?" becomes an evidence-backed chain from the user interface through native code to the effect, statically and at runtime.
- Acceptance
- A known fixture yields an evidence-backed chain, also under address space randomisation.
E Event-based process observation P1/P2 Phase 6
- Scope
- Platform adapters for process start, exit, re-execution and child processes.
- Acceptance
- Even very short-lived child processes are detected.
F Deeper native type and call analysis P1/P2 Phase 4
- Scope
- Structure layouts, argument types, function pointers and virtual calls, computed in the engine.
- Acceptance
- A self-built fixture with inheritance and function pointers is reconstructed correctly.
G Semantic version comparison P1/P2 Phase 5
- Scope
- "Which earlier findings and extension points must be rechecked after an update?" – matching renamed and moved functions across builds.
- Acceptance
- Two builds with known changes are matched correctly.
H From reconstruction to executable proof P1 Phase 4
- Scope
- Requirements on a reconstruction produce test harnesses and input corpora that compare original and reimplementation.
- Acceptance
- A deliberately wrong reconstruction is rejected.
I New analysis interface P2 Phase 5
- Scope
- Server-rendered web interface with Thymeleaf, first as a status and monitoring view for sessions, engine processes, providers and benchmark runs, then as a read-only view of the investigation record. No analysis of its own in the interface.
- Acceptance
- Every conclusion can be expanded down to its evidence; missing coverage is visible.
Optional domain modules
| Module | First scope | Priority |
|---|---|---|
| Games | Detect engine and deployment form, inventory resources, classes and extension points | P1 with a games focus |
| Java/Spring | Examine one Spring Boot archive: REST routes, services, configuration references | P1 with an enterprise focus |
| .NET/C# | Link a decompiler export with unique member identities | P2 |
| Protocols | Structure recurring messages in captures | P2 |
| Security analysis | Provenance-backed rules for risky API usage and data flows | P2/P3 |
| Component provenance | Turn package metadata into a provenance report, SBOM export | P2 |
| Symbolic analysis | One small pure function, one narrowly scoped question | P3 |
Principles
Decisions
- Source base and toolchainGhidra 12.1.4, Java 25 (LTS), the current stable Gradle release.
- One repository, two stacksEngine as a source copy in the repository, separate build, test and lint gates per stack.
- NameRHEXA for product and engine; Java packages stay unchanged, attribution is retained.
- One contractOne schema source, generated types and conformance tests for both sides.
- No merging with upstreamSecurity fixes are watched and adopted individually with provenance.
- HeadlessThe Swing UI goes away; a new interface is built only when needed.
Quality rules
- Demonstrable benefitEvery package needs a concrete analysis case and measurable added value.
- EvidenceArtefact identity, engine and contract version, parameters, location; facts, inferences, hypotheses and open questions kept apart.
- Real runsNo support claim without a real run on the claimed platform.
- Untrusted contentStrings and code from the target are data, never instructions to the agent.
- No silent side effectsStatic analysis never executes the target; runtime actions and write effects are visible in the tool contract.
- Engine changesA test in the affected module, an entry in the provenance record, no drop in coverage.
Risks and countermeasures
| Risk | Countermeasure |
|---|---|
| Missing upstream security fixes | Regular review, individual adoption with provenance, own regression tests for importers |
| GUI removal makes later adoptions harder | Move core classes, do not rewrite them; analyzers, loaders and processors stay unchanged |
| Loss of capability when removing providers | Parity matrix and gate before every removal, transition period, breaking-change note |
| Contract drifts apart | One schema source, generators, golden examples for both sides |
| Scope grows | Gates with benchmark; the analysis packages run independently of the engine work |
Licence and attribution
Agent layer
Based on REA by morluto, published under the MIT licence. The original copyright notice is retained in all copies.
Rhexa Engine
Derived from Ghidra, published under the Apache License 2.0. Licence text,
NOTICE file and all attributions are retained; every deviation is
documented in engine/UPSTREAM.md. Ghidra logos are not used.