DEV Community

Cover image for How AI Reverse Engineering Really Works: REA, Ghidra and angr on One 17-Byte Function
RuntimeStack
RuntimeStack

Posted on AI-assisted

How AI Reverse Engineering Really Works: REA, Ghidra and angr on One 17-Byte Function

AI doesn't read machine code.

So what's it actually reading? And those viral Adobe clones? Their builder says they never used REA.

There are two ways to copy an app, like those Adobe clones: watch it from the outside, or open it up. We'll open one up, one real function at a time, and see exactly where the AI comes in. Plus the two places it quietly breaks.

A hex dump of a compiled app in a terminal, with the rea command typed below it

Compiling is baking

Think of compiling as baking.

Your source code is the recipe. The compiler bakes it into a binary.

Comments never make it into the cake. And for a release, most apps strip out the function names too.

Here's the recipe we'll bake:

int price(int qty) {
    if (qty > 10)
        return qty * 90;
    return qty * 100;
}
Enter fullscreen mode Exit fullscreen mode
gcc -O1 -o app main.c
strip app
nm app
# nm: app: no symbols
Enter fullscreen mode Exit fullscreen mode

So you ship the cake. Not the recipe. You can't get the recipe back. But a good food lab gets surprisingly close.

Inside the binary: seventeen bytes

So let's open the cake. This is that exact function, from the stripped app.

The whole thing is seventeen bytes:

f3 0f 1e fa 83 ff 0a 7f 04 6b c7 64 c3 6b c7 5a c3
Enter fullscreen mode Exit fullscreen mode

To you, it's noise. To the CPU, it's a list of instructions. The only question is: where does each instruction start?

The disassembler: bytes to assembly

A disassembler maps them to instructions.

The first four are a security marker. Skip those. 83 ff 0a: compare the input with 10. 7f 04: if it's bigger, jump. Otherwise multiply by a hundred, and after the jump, by ninety.

$ objdump -d app
1169:  f3 0f 1e fa   endbr64                  # landing marker, skip
116d:  83 ff 0a      cmp    $0xa,%edi         # compare qty with 10
1170:  7f 04         jg     1176              # if bigger, jump
1172:  6b c7 64      imul   $0x64,%edi,%eax   # times 100
1175:  c3            ret
1176:  6b c7 5a      imul   $0x5a,%edi,%eax   # times 90
1179:  c3            ret
Enter fullscreen mode Exit fullscreen mode

The 17 bytes split into instructions, with the objdump listing and a comment on each line

The decompiler: assembly to C

Assembly's still slow to read. So, tool two: a decompiler.

The famous one is Ghidra, from the NSA. Here we'll use another free one, called angr. Same idea.

First, each instruction becomes tiny steps, every side effect spelled out. Ghidra calls it P-code. That one compare? Ten steps:

unique[78b00:4] = EDI
CF = unique[78b00:4] < 0xa
OF = sborrow(unique[78b00:4], 0xa)
unique[78d00:4] = unique[78b00:4] - 0xa
SF = unique[78d00:4] s< 0x0
ZF = unique[78d00:4] == 0x0
unique[58300:4] = unique[78d00:4] & 0xff
unique[58400:1] = popcount(unique[58300:4])
unique[58500:1] = unique[58400:1] & 0x1
PF = unique[58500:1] == 0x0
Enter fullscreen mode Exit fullscreen mode

Then it throws away the ones nothing uses. Then it spots the patterns. Compare plus jump is an if, and out comes C:

unsigned int sub_401169(int a0)
{
    if (a0 > 10)
        return a0 * 90;
    return a0 * 100;
}
Enter fullscreen mode Exit fullscreen mode

What came back: the logic, but no names

Look at what came back, though.

The logic is exactly right. But angr calls the function sub_401169. The input is called a0. And nothing says why 90, and not 100.

Every ingredient, every step. Not one note from the recipe.

angr's decompiler output: the correct if/else logic, but the function is sub_401169 and the input is a0

Now picture thousands of functions like that.

What the AI adds: the chef's guesses

So if the tools did the hard part, what's the AI for?

Reading. The model has seen millions of functions that look a lot like this one. So it renames a0 to qty, the function to price, and 90 to a bulk discount:

- unsigned int sub_401169(int a0)
+ int price(int qty)
  {
-     if (a0 > 10)
-         return a0 * 90;
-     return a0 * 100;
+     if (qty > 10)
+         return qty * 90;   // bulk discount?
+     return qty * 100;
  }
Enter fullscreen mode Exit fullscreen mode

Those names are guesses. Good ones. But guesses.

In the kitchen, that's the chef reading the lab report and saying: brown butter.

The model's guesses as a diff over angr's output: price(int qty) and a bulk discount comment

So what is REA?

REA is an MCP server: a standard plug that lets an agent like Claude Code drive those tools.

agent  <-> MCP <->  REA  <->  Ghidra | Hopper | IDA
Enter fullscreen mode Exit fullscreen mode

For native apps, it drives Ghidra, Hopper or IDA. It doesn't ship a decompiler of its own.

The analysis runs locally. The model, cloud or local, only sees the findings REA sends back.

How REA fits: the agent talks MCP to REA, which drives Ghidra, Hopper or IDA, all on your machine

Rebuild, test, repeat

But a guess isn't proof. So the agent rebuilds the function from its renamed copy:

int price(int qty) {
    if (qty >= 10)        // bulk = 10 or more?
        return qty * 90;
    return qty * 100;
}
Enter fullscreen mode Exit fullscreen mode

Then it runs both, the original and the rebuild, on the same inputs:

Input Original Rebuild
5 500 500 ✓
10 1000 900 ✗

Bulk discount sounded like ten or more, so it wrote that. Its own guess leaked in.

The test catches it. Decompile, guess, rebuild, test, repeat.

The agent's rebuild with qty >= 10, run next to the original: input 10 gives 1000 vs 900

Where it breaks, part one: obfuscation

Decompilers work because compilers write code in familiar patterns. Protectors break them on purpose.

VMProtect turns your code into bytecode for a made-up CPU, and ships the interpreter inside the app.

It's not a cake anymore. It's a cake baked inside another cake.

Where it breaks, part two: the agent's own report

The second place is quieter. It's the agent's own report. Picture a summary that says: tested every edge case, matches the original. (The video labels this report as illustrative.)

Did it? The log says five and eleven. That's it:

$ cat test.log
5  -> 500 ✓
11 -> 990 ✓
# no line for 10: it never ran
Enter fullscreen mode Exit fullscreen mode

A summary isn't evidence. The test log is. So you still steer, and you ask for the edge cases.

Is it worth the tokens?

Not always. In one informal test, a plain agent working from screenshots finished first. And its copy was only slightly behind. Nobody's published a token count yet.

If it's all visible on screen, watching is often enough.

The Adobe clones: they watched

According to their builder, that's exactly what the Adobe clones did. They watched. Public specs and the apps' visible behaviour. No decompiling, by their own rules.

That's the idea behind clean-room design: build from the spec, never from the original code.

In kitchen terms? They tasted the cake in the shop, and never sent it to the lab.

Is it legal?

Decompiling the original and shipping what you find is a much riskier legal story.

REA's own readme limits it to lawful research, interoperability, and software you're authorized to examine.

This isn't legal advice, but know which kitchen you're cooking in.

Recap

Kitchen Reverse engineering
the cake the binary
reading its ingredients, exactly the disassembler
rebuilding the steps, but not the names the decompiler
the chef, guessing the names and the why the AI
the taste test the tests: the only part you should really trust

And for the Adobe clones: would you have watched, or opened it up? Tell me in the comments.

More in this series: AI agent sandboxing, reward hacking, Pi 1.0 and Pi Durable.


This is the written version of a 7-minute animated explainer on RuntimeStack. Sources: REA README, MindStudio blog, Ghidra README, Ghidra (Wikipedia), P-code reference, Springer chapter, pypcode, angr decompiler, KuCoin news: ArtCraft founder and REA, innFactory: AI rebuilt Photoshop, PetaPixel, TweakTown, Clean room design, x86 reference, ENDBR64, back.engineering blog.

Top comments (0)