Devirt logo

Devirt

Archives
Log in
Subscribe
November 10, 2026

AI Decompiler vs Ghidra vs Devirtualization, Compared

What an AI decompiler, a classic decompiler like Ghidra and devirtualization each recover from a binary, side by side, and which one a protected file needs.

An AI decompiler, a classic decompiler like Ghidra and devirtualization answer three different questions about a binary. People mix them up constantly. In November 2026 it's common to see "just run it through an AI decompiler" offered as the answer to a VM-protected file, which is a bit like asking a translator to read a page that's been shredded.

About Devirt: Devirt recovers the code that protectors such as VMProtect and Themida hide inside their own virtual machines, for files you own or are authorized to analyze. You get an IDA database and annotated pseudocode, with a ledger showing which functions were proven. If nothing is proven, you pay nothing. Start with a free assessment.

Below is what each of the three does, side by side, and how to pick between them.

The short answer

  • A classic decompiler (Ghidra, IDA Pro's Hex-Rays, Binary Ninja) turns machine code into pseudocode using rules.
  • An AI decompiler uses a language model to make that pseudocode read like human-written code.
  • Devirtualization recovers functions that a protector has compiled into bytecode for its own virtual machine. Neither kind of decompiler can read that bytecode as the original logic.

In practice they stack, and plenty of analyses use all three. Which one you start with depends on what's in the binary.

Side by side: AI decompiler, Ghidra, devirtualization

Classic decompiler (Ghidra, IDA Pro) AI decompiler Devirtualization
Input Machine code Assembly or decompiler pseudocode VM bytecode inside a protected binary
Output Pseudocode Readable, renamed code with explanations Recovered functions as pseudocode and a tool database, each with a proof state
Strength Faithful to the instructions Readability, naming, summaries Removes the virtual machine layer
Weak spot Hard to read on large functions Can invent names and logic without flagging it Only for supported protectors and an accepted scope
On VM-protected code Decompiles the interpreter Explains the interpreter Recovers the protected function

[IMAGE 1: three lanes, from the same binary to three different outputs.]

One function, three views

Here's a small made-up example, not taken from a real binary, to show what each tool hands you. Picture a function that checks whether a buffer starts with a four-byte magic value.

A classic decompiler prints something like this:

undefined4 FUN_00401a30(int param_1, uint param_2)
{
  if (param_2 < 4) {
    return 0;
  }
  if (*(int *)param_1 == 0x46445645) {
    return 1;
  }
  return 0;
}

An AI decompiler rewrites it:

// Returns true if the buffer begins with the file signature.
bool has_valid_signature(const uint8_t *buffer, size_t length)
{
    if (length < 4) return false;
    return *(const uint32_t *)buffer == FILE_MAGIC;
}

That's easier to read, and in this case it's right. The names has_valid_signature and FILE_MAGIC are still the model's guesses. Nothing in the binary says "signature".

Now protect the same function with a virtual machine protector. The decompiler shows something closer to this:

void FUN_00405f10(void)
{
  do {
    opcode = *vm_ip++;
    (*handler_table[opcode])(vm_context);
  } while (vm_running);
}

That's the interpreter. The AI decompiler will explain it accurately as a dispatcher loop, and it will never mention a magic value, because the comparison now lives in bytecode the loop is reading. Devirtualization is the step that gets the comparison back.

What a classic decompiler does

A classic decompiler rebuilds higher-level pseudocode from machine code with rules: it recovers the control-flow graph, infers types, recognizes library functions and prints C-like code. Ghidra, IDA Pro's Hex-Rays decompiler and Binary Ninja are the usual choices.

The output is faithful to the instructions, which is its biggest strength and the reason it's hard to read. Variable names are placeholders like local_28. Loops sometimes come out as gotos. RevEng.AI, which builds an AI decompiler, notes in its write-up that Ghidra "produces a kind of pseudo-C code rather than standard C." That's a fair description of what you're working with.

What an AI decompiler adds

An AI decompiler adds a language model on top: it reads the assembly or the pseudocode and rewrites it the way a person might have written it. Names get meaningful, structure gets tidier, and you often get a plain-English summary.

That is useful. On simple functions it can be close to right. In a 2025 write-up, one game-decompilation contributor reported a model hitting a 96% match against the target assembly on the first try when they tried it in January 2025.

The cost is that every improvement is a prediction. A model can call a field timeout when it's a retry counter, or fold two branches that only look alike. The output doesn't tell you which parts are guesses. RevEng.AI's own write-up describes its evaluation as "simple pass/fail testing" and lists semantic correctness as something still to build in.

What devirtualization does, and why VM protection needs it

Devirtualization recovers code that a protector has hidden inside its own virtual machine. Protectors such as VMProtect and Themida take selected functions, compile them into bytecode for a private instruction set, and ship an interpreter to run it. What's left in the binary is a dispatcher loop and its handlers.

That's a different problem from making code readable. There's no original function to tidy up, because it isn't stored as machine code any more. Devirtualization translates the bytecode back into readable logic. Devirt's version also counts every protected function in scope before recovery and places each one in one of four states: proven, runtime-dependent, unresolved or permanently bounded. That way the result tells you what was checked, not just what was produced.

If you want the longer version of where devirtualization sits next to unpacking and deobfuscation, Devirt has a separate explainer on devirtualization vs deobfuscation vs unpacking.

Can an AI decompiler read VM-protected code?

No. An AI decompiler can't read the logic of a VM-protected function, because that logic no longer exists as machine code. VMProtect, Themida and similar protectors replace the function with bytecode run by an interpreter, so an AI decompiler only sees a dispatcher and handlers.

What you get back is an accurate, well-written explanation of the interpreter. It's tempting to keep prompting, and it won't help. Devirtualization has to come first. After that, an AI decompiler is useful again for naming and explaining the recovered code.

What decompiler vs disassembler means here

A disassembler translates machine code into assembly instructions, one for one. A decompiler goes a step further and rebuilds pseudocode with loops, conditions and functions. An AI decompiler is a third layer that rewrites that pseudocode with a language model. When a virtual machine protector is involved, devirtualization sits underneath all three: it gives the other tools real code to read.

Where each one goes wrong

Each tool fails in its own way, and it helps to know which failure you're looking at.

  • Classic decompiler: wrong types and missed structure. A struct gets read as a pile of offsets, or a switch statement comes out as nested ifs. The behavior is usually still faithful, just hard to follow.
  • AI decompiler: right-looking, wrong meaning. The structure is clean and the names are confident, and a name or a merged branch quietly changes what you think the code does. This is the hardest failure to spot, because it looks like success.
  • Devirtualization: functions that can't be settled from the code. Some behavior depends on values only known at runtime, and some questions sit outside what the method can model. A good result labels those functions instead of guessing. That's what the runtime-dependent, unresolved and permanently bounded states are for.

The pattern is that the more readable the output, the more you need a separate check, because readability is what makes a mistake persuasive.

Which one do you need?

Your situation Start with Then
Ordinary compiled binary, you need accuracy Classic decompiler Add an AI decompiler to speed up reading
Large codebase, you need orientation fast AI decompiler on top of a classic decompiler Verify the functions your conclusion depends on
The function you care about shows a dispatcher loop Identify the protector Devirtualization, then an AI decompiler to explain the result
You need to cite or act on what a function does Whichever tool, plus a check Record each function as proven, runtime-dependent, unresolved or bounded

How to check the result, whichever you use

Whichever tool produced the code, sort the functions you rely on into those same four states before you trust them. Proven means a check supports the behavior within a stated scope. Runtime-dependent means you need runtime evidence. Unresolved means the evidence didn't settle it. Permanently bounded means it's outside what your method can model.

The habit that matters is keeping every function in the count. "Decompiled" says nothing. "30 proven, 90 not yet" tells you exactly how far you can go.

If you work with AI agents and protected binaries, Devirt's AI reverse engineering page explains how a recovered, checked result gets handed to your agent through a read-only connection. Its free triage shows what's protected in a file before you commit to anything.

Devirt only works on files you own or are authorized to analyze. It doesn't remove DRM, bypass license checks or crack software.

Don't miss what's next. Subscribe to Devirt:
← Newer PEiD Is Old: What Replaced It, and What Packer Detection Misses Older → Evaluating Software Reverse Engineering Companies: A Checklist
devirt.re
GitHub
devirt.gitbook.io
YouTube
dev.to
Twitter
Medium
Substack
Powered by Buttondown, the easiest way to start and grow your newsletter.