[KongchangAI]
· 3 min read· 1,677 words

We Tested GitHub's #1 Trending REA: Can AI Really Reverse-Engineer .NET Apps?

We Tested GitHub's #1 Trending REA: Can AI Really Reverse-Engineer .NET Apps?

REA is a coordinator that calls decompilers and hands results to AI—real capability, but skipping it is actually faster.

The article tests open-source project REA (Reverse Engineer Anything)—which gained ~183,000 stars in a week but does no decompilation itself, instead coordinating an AI agent with real tools like Ghidra, IDA, and ILSpy. Using a 105-line C# app called Naze Pixel compiled into regular .NET, Obfuscar-obfuscated, and Native AOT forms, all tests recovered the key and achieved byte-for-byte rebuilds. But the key twist: an ordinary AI without REA was faster in all three cases (41s, 56s, 4 min vs. 85s, 3 min, 18 min). Obfuscation renamed classes to invisible characters yet left the plaintext key untouched, proving again it only slows things down. The core lesson: any binary shipped to a user's machine is readable, and client-side embedded keys are useless.

What REA Is: A Coordinator Disguised as a "Universal Reverse-Engineering Tool"

REA project hands-on screenshot

An open-source project called REA (Reverse Engineer Anything) racked up roughly 183,000 stars in a single week, rocketing to the top of GitHub's weekly trending list. Its pitch is blunt and simple: plug in your AI coding agent, and it will dissect programs it has never seen the source for—even turning machine code back into readable code.

But there's a line buried in the README that the hype tends to gloss over: REA itself does no decompilation. It's a coordinator: your AI agent asks a question, REA calls the real analysis tools to run a pass, and then hands the results back with evidence.

  • For .NET, it has its own assembly metadata and CIL (bytecode) reader—purely static analysis, no need to run the target program.
  • For native machine code, it drives classic decompilers: Ghidra (NSA's free, open-source tool), Hopper, or IDA.

The key point: decompilers produce C-like pseudocode littered with names like FUN_140001f00 and param_1. It's the AI that reads this "messy stew," guesses what each chunk of logic does, and rewrites it into clean code. REA is a real tool, but its essence is "decompiler plus intelligent guessing," not an undo button for compilers.

The Difference Between Decompilation, Disassembly, and CIL: Disassembly converts machine code into assembly mnemonics (like mov, call), preserving instruction-level detail but being nearly unreadable. Decompilation goes further, abstracting assembly into C-like pseudocode and recovering loops, conditionals, and function-call structure—at the cost of losing some information and guessing at names. The Ghidra, Hopper, and IDA mentioned in this article are all decompilers, and they don't handle .NET well, because .NET programs ship as CIL (Common Intermediate Language) bytecode rather than native machine code, and must first be compiled to machine code via JIT or AOT before they can run. CIL retains extensive metadata (class names, method signatures, string literals), which is the fundamental reason .NET is easier to reverse-engineer than native programs. Only by understanding these three layers of abstraction can you understand why the same app has wildly different reverse-engineering difficulty across three build forms.

The Test Subject: A Real Little C# App

The test subject isn't a toy. Naze Pixel is roughly 105 lines of C# code that converts 24-bit BMPs into dithered ASCII art: load the bitmap, grayscale it, downscale it, apply Floyd–Steinberg dithering, and map pixels to characters. Like many real apps, it has a built-in upload key.

var image = Bmp.Load(path);
var gray  = Pixels.Grayscale(image);
var small = Pixels.Resize(gray, image.Width, image.Height, width);
var dots  = Pixels.Dither(small);
var art   = Pixels.ToAscii(dots);

Console.WriteLine(art);
if (args.Contains("--share")) Uploader.Share(art);

The embedded key (a fake key for testing):

const string ApiKey   = "nzp_live_7c41e9a0d3b8f2a6";          // FAKE upload key
const string Endpoint = "https://api.nazepixel.example/v1/art";

The author compiled the app into three forms (regular .NET, obfuscated, and Native AOT), ran each one through REA, and then asked a question the hype avoids: Can an ordinary AI agent, without REA, handle it on its own? To keep the binary from leaking machine info, the build used <DebugType>none</DebugType> and <Deterministic>true</Deterministic>—otherwise PDB paths containing the username would be left in the binary.

Reverse-Engineering Comparison Across Three Build Forms

Test 1: Regular .NET Build

REA's .NET reader processed NazePixel.dll and returned 114 KB of JSON in about 1.5 seconds: every method, signature, bytecode summary, and all string literals—including usage text, endpoints, and the key.

Handed this blob of JSON (and only this JSON) to a brand-new AI with no source code, it rebuilt the entire app in 85 seconds: grayscale weights accurate to four decimal places, the 7/3/5/1 dithering pattern, everything restored.

To verify fidelity, the author recompiled the AI's version and fingerprinted both outputs with SHA-256:

ours    317eb0c60108775b9e6a88a7f371e21eb34fc11cc607fc3a66f6938ba6d92261
ai      317eb0c60108775b9e6a88a7f371e21eb34fc11cc607fc3a66f6938ba6d92261

The hashes matched, meaning the outputs were byte-for-byte identical.

Control group (without REA): Given only the bare .dll and told to "use whatever tool you like," the same agent found the already-installed free .NET decompiler ILSpy and got the real C# code back in 41 seconds—faster than using REA.

The Significance of Byte-for-Byte SHA-256 Comparison: SHA-256 is a cryptographic hash function that produces a fixed-length 256-bit (64 hexadecimal characters) digest for any input; a change in even a single bit of input causes an avalanche effect in the output. So if two files have the same hash, they are byte-for-byte identical with overwhelming probability. The author used this to verify whether the AI-rebuilt code was faithful to the original program: recompile the AI-generated C#, then compare the hash of the compiled output against the original. This is a far stronger verification than "looks similar" or "functionally passes." Note that the Native AOT and .NET build outputs hashed identically because the app's logic is fully deterministic (no randomness, no timestamps), and <Deterministic>true</Deterministic> eliminated compiler-introduced nondeterminism—otherwise even two builds of the same source could differ.

Test 2: Obfuscated Build

Processed with the free, open-source obfuscator Obfuscar, every class and method was renamed to invisible Unicode whitespace characters, and all strings were encrypted. REA's string list came back empty.

So could the AI still understand it? Relying only on REA's output, in about three minutes it:

  • Reconstructed the entire algorithm from bytecode.
  • Cracked the encryption on paper: each byte was XORed with its position and a fixed value—b ^ i ^ 0xAA. The author verified this personally; it was exactly right.
  • Did not actually read the strings—it could only guess by length (guessing the share flag was --debug, when it was actually --share).

But it made a prediction: the key is a constant, constants live in metadata, so it's very likely still plaintext. So the author went searching:

> search the obfuscated .dll for a UTF-16 "nzp_live_..." string
nzp_live_7c41e9a0d3b8f2a6

The full key, in plaintext, sitting in the "obfuscated" file. The obfuscator turned everything into invisible characters—except the very thing it was supposed to hide.

Control group (without REA): In 56 seconds it decompiled, found the encryption logic, and decrypted every string (including the key) with a few lines of Python.

Test 3: Native AOT (Machine Code)

This is where the hype actually gets tested. dotnet publish -p:PublishAot=true produced a 1.1 MB pure x64 machine-code .exe—with no CIL bytecode at all. At this point the Dither function looks like this:

140001f00  48 89 5c 24 08 57 48 83 ec 20 8b f2 48 8b d9 ...

REA loaded the exe into Ghidra, which found 3,627 functions—almost all of them .NET runtime. Our code was a few needles in that haystack. With only REA, the AI searched for strings, followed the code referencing them, and decompiled target functions one by one. About 18 minutes later: the entire app was restored—same weights, same dithering, same key—and it even annotated each function with its address in the exe.

The author compiled this machine-code reconstruction, and its output hash matched the original:

ours     317eb0c6...6d92261
rebuild  317eb0c6...6d92261

Byte-for-byte reconstruction from machine code—this part of the hype holds up.

Control group (without Ghidra): Took less than 4 minutes. The agent wrote its own disassembly script in Python, recovered the same constants, the same key, and even got the real class names (.NET leaves class names in the exe for stack traces). One detail worth flagging: it also ran this unknown exe to observe behavior—fine for your own app, but you should never let an agent do that with a stranger's binary.

Native AOT and Metadata Residue: Native AOT (Ahead-Of-Time) compiles CIL to native machine code at publish time, so no JIT is needed at runtime, and the output is a pure x64 executable that is theoretically the hardest to reverse—there really is no CIL to read. But the .NET runtime still keeps class names in the exe because exception stack traces, reflection, and diagnostics need them. That's why the AI in the test could get "real class names." Another key point: Native AOT links the entire runtime into the output, so the vast majority of those 3,627 functions are runtime code, and the actual business logic is just a few needles—which is why Ghidra's output is so noisy and the AI has to hunt through a haystack. By contrast, a native program compiled from pure C/C++ has no such metadata burden, making reverse-engineering harder.

Hands-On Conclusion: The Real Deal or Hype?

Build FormWith REAWithout REA (Ordinary AI)
Regular .NET85 seconds, byte-for-byte identical rebuild41 seconds (ILSpy)
Obfuscated~3 minutes, key recovered56 seconds, key recovered
Native AOT~18 minutes, byte-for-byte identical rebuild~4 minutes, key + class names

REA is the real deal. It's careful, purely static for .NET, and in the pure machine-code scenario it genuinely helped the AI reconstruct the app precisely. But in every single test, the same AI without it could do the job too—and faster. For a program of this size, the AI itself is doing the reverse-engineering, REA or no REA.

Where REA actually earns its value is the scenario the author didn't test: large native applications where you need a real decompiler plus verifiable evidence, rather than letting an agent improvise in Python. For a 105-line C# app, it's overkill. The capability is real; the "you must use this tool" narrative is the hype—and it's only half true.

The Real Lesson for .NET Developers

This was never about a single trending repository. It's the same lesson told three ways:

  • Obfuscation just slows people down.
  • Native AOT slows them down a little more.
  • Neither hides secrets.

Anything shipped to a user's machine can be read—strings, keys, endpoints, all of it. A key embedded in an app is essentially just a password with a delivery address. Keep it on a server you control, behind an API.

This article is based on a hands-on report from Naze Lab. Sources: the morluto/rea repository and docs, Ghidra 12.1.4, Obfuscar, ILSpy, .NET 10 Native AOT.

#REA reverse engineering#.NET reverse engineering#Native AOT#Obfuscar obfuscation#AI decompilation#Ghidra
Share:

Related articles