AI reverse engineering with byte-identical verification
relumea analyzes stripped binaries with an AI agent, then recompiles each recovered function with the original toolchain and compares it with the binary, so you know which results are exact.
The agent called a tool that changes data, so the run is paused until you decide.
{ "function_id": 3, "name": "decode_config", "actor": "agent" }
→ rename_function284 tools in the registry. 134 are read-only and run as soon as the agent calls them. The other 150 change data, so the run pauses until you approve the call.
272compiler toolchains7,546tests44example targets
Triage, matching, decompilation and remediation in one workspace
For stripped binaries with no source or symbols, from first triage to detection rules.
- Agentic malware analysis
- Identity, imports, capabilities, protocols and ATT&CK mapping in one run, with a threat score, family detection against your own reference samples and a written summary.
- run_conversation_agent
- Function matching
- Match functions against your own corpus, compare candidates side by side and carry names across to the binary you are working on.
- resembl · get_matches
- AI decompilation
- Decompiler output with model-proposed names, comments and types, each journaled and revertible.
- rebrew decompile · get_decompilation
- Automated remediation
- A YARA rule, Snort 2 rules per network indicator, a STIX 2.1 bundle, an SBOM and a PDF report, generated from the same scans.
- remediation · export_sbom · report-pdf
What relumea adds
- Byte-identical verification
Recovered C is recompiled with the target’s own toolchain and compared with the original bytes.
- Decompilation projects
Each binary becomes a source tree that rebuilds, with a verdict for every function.
- Approval for every write
Tools that change data pause the run until you approve the call; approved changes are journaled and revertible.
Works with your tools
- Ghidra
- renames as a runnable Python script
- IDA Pro
- renames as an IDA Python script
- Binary Ninja
- renames as a JSON document
- MCP
- every registry tool, for agent clients
- REST API
- the API the web workspace uses
- CLI
- reportal, from a terminal
- SBOM
- CycloneDX, SPDX or CSV per artifact
- Detection
- YARA, Snort 2 and STIX 2.1
One triage run, call by call
The agent runs triage tools in order and cites the evidence for each finding. In this run 8 read-only calls ran without asking; the rename waited for an analyst's approval.
Illustrative sample · updater_svc.exe
- Task
- Triage updater_svc.exe: find the persistence mechanism and the C2 send routine.
- Target
- PE · x86_32 · mingw-14.2.0-win32 · 412 functions · sha256 a7ed6974787de73373b3ca48d32faaf6611b6745ed362e85599282d68c1489d4
- 01get_pe_inforead-only{ "binary_id": 1 }PE · x86_32 · 4 sections · 196,608 bytes
- 02get_importsread-only{ "binary_id": 1 }106 imports from 5 libraries
- 03get_capabilitiesread-only{ "binary_id": 1 }networking · persistence · process-injection
- 04get_protocols_scanread-only{ "binary_id": 1 }http
- 05get_threat_reportread-only{ "binary_id": 1 }3 ATT&CK techniques · software type · threat score
- 06get_decompilationread-only{ "function_id": 3 }fcn.00401a20 · 10 lines of C
- 07rename_functiongated{ "function_id": 3, "name": "decode_config", "actor": "agent" }journal_action 31 · name_history row written
The run paused here until an analyst approved the rename.
- 08get_matchesread-only{ "function_id": 3 }8 candidates from your corpus
- 09get_remediationread-only{ "binary_id": 1 }YARA rule
Findings
From the import table and strings. Each finding lists the import that triggered it.
- networkinghighcapabilities · WinHttpSendRequest
- persistencehighcapabilities · RegSetValueExA
- process-injectionhighcapabilities · CreateRemoteThread
- anti-debug-apihighhardening · IsDebuggerPresent
- httphighprotocols · WinHttpOpen
- T1071 Application Layer Protocolhighthreat · WinHttp* + WS2_32
- T1547 Boot or Logon Autostartmediumthreat · RegSetValueExA on a Run key
- T1055 Process Injectionhighthreat · CreateRemoteThread
Byte-identical verification
Function matching and AI decompilation give you a likely answer. relumea checks it: the recovered C is compiled with the same compiler and flags as the target, and the output is compared with the original bytes. Point at a line on either side to see how source and instructions correspond.
Illustrative sample · updater_svc.exe
Recovered source
cfg/decode.cLine 6 → 8 instructions, 22 bytes
89 d1 8b 74 24 14 83 e1 03 c1 e1 03 d3 ee 89 f1 32 0c 13 88 0c 13
Original bytes
mingw-14.2.0-win32From stripped binary to verified source
One function from a stripped PE, run through real tools. The decompiler output is correct but hard to read. The corrected C adds names, types and the original loop structure, and compiles to the same 60 bytes.
Sample function · real compiler and decompiler output
Original assembly
0x00401000 · 60 bytes · no symbols- 0040100055push ebp
- 0040100189e5mov ebp, esp
- 0040100356push esi
- 004010048b550cmov edx, dword [ebp + 0xc]
- 004010078b4508mov eax, dword [ebp + 8]
- 0040100a53push ebx
- 0040100b8b5d10mov ebx, dword [ebp + 0x10]
- 0040100ef7d0not eax
- 0040101001d3add ebx, edx
- 0040101239dacmp edx, ebx
- 004010147420je 0x401036
- 004010160fb60amovzx ecx, byte [edx]
- 0040101942inc edx
- 0040101a31c8xor eax, ecx
- 0040101cb908000000mov ecx, 8
- 0040102189c6mov esi, eax
- 0040102383e001and eax, 1
- 00401026f7d8neg eax
- 00401028d1eeshr esi, 1
- 0040102a252083b8edand eax, 0xedb88320
- 0040102f31f0xor eax, esi
- 0040103149dec ecx
- 0040103275edjne 0x401021
- 00401034ebdcjmp 0x401012
- 004010365bpop ebx
- 00401037f7d0not eax
- 004010395epop esi
- 0040103a5dpop ebp
- 0040103bc3ret
Decompiler output
Ghidra (rz-ghidra)- uint32_t __cdecl fcn.00401000(int32_t arg_4h, char *arg_8h, int32_t arg_ch)
- {
- uint8_t uVar1;
- uint32_t uVar2;
- int32_t iVar3;
- uint8_t *puVar4;
- // [00] -r-x section size 4096 named .text
- uVar2 = ~arg_4h;
- puVar4 = (uint8_t *)(arg_8h + arg_ch);
- while ((uint8_t *)arg_8h != puVar4) {
- uVar1 = *arg_8h;
- arg_8h = (char *)((uint8_t *)arg_8h + 1);
- uVar2 = uVar2 ^ uVar1;
- iVar3 = 8;
- do {
- uVar2 = -(uVar2 & 1) & 0xedb88320 ^ uVar2 >> 1;
- iVar3 = iVar3 + -1;
- } while (iVar3 != 0);
- }
- return ~uVar2;
- }
Corrected C
names, types and structure- uint32_t crc32_update(uint32_t crc, const uint8_t *buf, size_t len)
- {
- crc = ~crc;
- while (len--) {
- crc ^= *buf++;
- for (int bit = 0; bit < 8; bit++)
- crc = (crc >> 1) ^ (0xEDB88320u & -(crc & 1));
- }
- return ~crc;
- }
- Names
- fcn.00401000 → crc32_update, arg_4h and uVar2 → crc, arg_8h → buf, arg_ch → len, iVar3 → bit
- Types
- int32_t → uint32_t, char * → const uint8_t *, int32_t → size_t
- Structure
- end-pointer loop → while (len--), countdown do/while → for over 8 bits, uVar1 and puVar4 dropped
Recompiled assembly
mingw-w64 gcc 16.2.0 -Os- 0040100055push ebp
- 0040100189e5mov ebp, esp
- 0040100356push esi
- 004010048b550cmov edx, dword [ebp + 0xc]
- 004010078b4508mov eax, dword [ebp + 8]
- 0040100a53push ebx
- 0040100b8b5d10mov ebx, dword [ebp + 0x10]
- 0040100ef7d0not eax
- 0040101001d3add ebx, edx
- 0040101239dacmp edx, ebx
- 004010147420je 0x401036
- 004010160fb60amovzx ecx, byte [edx]
- 0040101942inc edx
- 0040101a31c8xor eax, ecx
- 0040101cb908000000mov ecx, 8
- 0040102189c6mov esi, eax
- 0040102383e001and eax, 1
- 00401026f7d8neg eax
- 00401028d1eeshr esi, 1
- 0040102a252083b8edand eax, 0xedb88320
- 0040102f31f0xor eax, esi
- 0040103149dec ecx
- 0040103275edjne 0x401021
- 00401034ebdcjmp 0x401012
- 004010365bpop ebx
- 00401037f7d0not eax
- 004010395epop esi
- 0040103a5dpop ebp
- 0040103bc3ret
Decompilation projects
Each binary becomes a project: a tree of recovered C files that builds with the original toolchain, and a verdict for every function. When a function is close, relumea searches compiler flags and source variants for an exact match, and uses angr and Z3 to prove equivalence where the bytes still differ. This project covers all 412 functions, including the ones that do not match yet.
Illustrative sample · updater_svc.exe
- EXACT198
- Recompiled bytes identical to the original.
- RELOC141
- Identical except for addresses the linker fills in.
- PROVEN12
- Bytes differ; equivalence proven with angr and Z3.
- NEAR2
- At least 60% of bytes match; the rest is usually register allocation, instruction order or a compiler flag.
- STUB3
- Under 60% of bytes match: not implemented yet, or control flow differs.
- unattempted56
- Not attempted yet. Counted in the total.
| Address | Name | Size | Verdict | Source |
|---|---|---|---|---|
| 0x00401020 | svc_Main | 1,842 | STUB | svc/main.c |
| 0x00401840 | cfg_LoadEncrypted | 412 | RELOC | cfg/load.c |
| 0x00401a20 | decode_config | 54 | EXACT | cfg/decode.c |
| 0x00401c80 | net_OpenSession | 288 | RELOC | net/session.c |
| 0x00402210 | http_SendBeacon | 640 | NEAR | net/beacon.c |
| 0x00402a90 | reg_PersistRunKey | 196 | EXACT | persist/runkey.c |
| 0x00403100 | inj_WriteRemote | 720 | PROVEN | inj/remote.c |
| 0x004038c0 | anti_IsDebugged | 48 | EXACT | anti/debug.c |
Data handling and control
What the workspace does with your binaries, and what the agent is allowed to change.
- Stored by content hash
- Each binary is kept under its sha256 in your workspace.
- Model features are opt-in
- AI routes stay off until the workspace configures a model.
- Writes wait for approval
- The 150 tools that change data pause the run until a person approves the call.
- Every write is journaled
- Approved changes record the value they replaced, and revert_journal_entry undoes them.
Frequently asked questions
Matching, the model, packers and the tools you already use.
How is this different from similarity-based function matching?
Similarity matching suggests what a function probably is. relumea uses it as a starting point, then recompiles the recovered C and compares it with the original, so each function ends with a verdict instead of a score.
Does relumea depend on an LLM?
The capability, protocol, hardening and secrets scans, the ATT&CK mapping, the matching and the byte comparison run without a model. The model is opt-in: it drives the agent and proposes names, comments and types for stored decompilation.
What happens when a function does not match?
Its verdict records how close it got (NEAR or STUB), and it stays in the project and in the coverage figure.
How do you handle packed malware?
Filetype detection names the packer from section names, entry-point bytes, constants and entropy. LZEXE and UPX can be unpacked on request; a packer that rewrites its own stub is not identified.
Does it work with Ghidra, IDA Pro and Binary Ninja?
Yes. Renames export as a Python script for Ghidra or IDA and as a JSON document for Binary Ninja.
Can it match across architectures and file formats?
Only coarsely. Platform and architecture scope is inferred from the stored fingerprint, and results say it is inferred.
Do you support firmware?
Yes. Firmware has its own extraction and scanning pipeline, separate from PE analysis.
Join the waitlist
The hosted workspace is open by invitation. We’ll email you one.