Decompilation isn’t new, but AI makes it fast
As a student, I used to “cheat” in PC games, and cheat codes were only part of it. Memory scanners let you search the game’s RAM for a value, such as your gold count. You spent some gold, searched again to narrow the matches, and then overwrote the value. Unlimited resources. Those tricks became less effective in server-authoritative games, where critical state is validated remotely.
Years later, decompilers came back into my life at work, legitimately. A hardware vendor supported their device only through a C library compiled into a DLL, and they told us to bridge it into our Java stack. Getting the calls right meant decompiling and inspecting the binaries. Along the way we also decompiled some Java, and it was a shock to see how readable compiled Java is. From then on, we always shipped obfuscated Java archives.
So reverse engineering isn’t new. What is changing is automation and synthesis. AI agents can significantly accelerate reverse-engineering workflows by coordinating specialized tools and interpreting their output. Tasks that previously required extensive manual inspection can sometimes be completed in minutes, although results still depend on the target format and the underlying tools.
That raised a practical question for me: if I ship a Godot game today, how much of my source code can someone get back, and how does modern AI tooling handle it?
The toolchain: REA and GDRE Tools
To find out, I looked at two very different tools:
1. REA (“Reverse Engineer Anything”)
REA recently gained traction as an agentic reverse-engineering framework. But REA itself is not an LLM. It is an orchestration layer and Model Context Protocol (MCP) server that connects AI coding agents (such as Claude Code, Cursor, or Gemini CLI) to established analysis engines:
- Ghidra, IDA Pro & Hopper: For native PE, ELF, and Mach-O binaries.
- JADX: For Android APK decompilation and DEX bytecode lifting.
- Electron & Node analyzers: For unpacking ASAR bundles and static JavaScript inspection.
- Binwalk & Unblob: For firmware and embedded extraction.
Crucially, REA enforces an evidence model (the “receipt model”). Because both LLMs and decompilers can hallucinate or make speculative guesses, REA requires tools to return structured JSON with concrete evidence—file hashes, exact memory offsets, instruction addresses, and decompiler constraints. Note that REA’s integrations vary by analysis lane and version, and not every backend is equally mature. The AI agent then reasons over real decompilation receipts rather than speculating.
2. GDRE Tools / GDSDecomp
GDRE Tools
is an open-source, dedicated Godot reverse-engineering toolkit. Unlike general-purpose reverse-engineering suites, GDRE is built specifically for Godot’s engine internals: it unpacks Godot packfiles (.pck) and decompiles compiled GDScript bytecode tokens back into human-readable scripts.
The legal bit: reverse engineer your own work
Reverse engineering commercial software usually runs into license terms (EULAs), anti-circumvention law and copyright. The safest target is your own work, which also gives you the original source to check the results against (though care is still warranted around third-party asset licenses or engine components). So I used my own game.
The target: The Jade Crypt (see Building The Jade Crypt for how it was made). It’s a 2.5D wuxia platformer built in Godot 4.7: 66 GDScript files, 30 chambers built from ASCII text maps, and a headless solver that proves every chamber can be beaten.
I exported a Web release build with GDScript in compiled token mode, which stores scripts as tokens instead of plain source text:
| File | Size | What it is |
|---|---|---|
index.pck |
100 MB | The game archive: scripts, chamber maps, assets |
index.wasm |
40 MB | The Godot engine WebAssembly binary |
index.js / .html |
~300 KB | The stock web loader |
Round 1: REA and the format boundary
I started by seeing if a modern agentic reverse-engineering tool could inspect the build out-of-the-box:
rea inspect-artifact build/index.pck
# → unsupported_target: Cannot open artifact: unsupported binary format.
rea inspect-artifact build/index.wasm
# → needs the separate WebAssembly lane (requires WABT 1.0.42)
rea analyze-javascript-application build/
# → works, but it only unpacks Godot's browser shell/loaderREA immediately refused index.pck. The structured error receipt explains why:
| Field | Value |
|---|---|
| Error | Analysis failed |
| Code | target_unavailable |
| Category | unsupported_target (retryable: false) |
| Message | Cannot open artifact: unsupported binary format. |
| Path | build/index.pck |
| Constraint | file_format_rejected |
| Remediation | Review the reported file-format reason and select a supported, well-formed target. |
The takeaway on AI reverse engineering
This highlights a fundamental reality of AI-driven reverse engineering: agents are orchestrators, not magicians.
An AI agent paired with REA can orchestrate Ghidra or JADX with extraordinary speed, but if the underlying decompiler toolchain does not have a parser for a specific binary format (like Godot’s custom .pck container and GDScript bytecode), the AI hits a hard boundary. For specialized runtimes, domain-specific decompilers are still mandatory.
Round 2: A dedicated Godot decompiler
Next, I pointed GDRE Tools directly at the .pck file:
gdre_tools.x86_64 --headless --recover=build/index.pck --output=recoveredDetected Engine Version: 4.7.2
Extracted 700 files, no errors detected!
Decompiled scripts: 66 Scripts not decompiled: 0
Recovery finished in 00m06s
In six seconds, GDRE Tools fully unpacked the game.
GDRE Tools v2.7.4
Ubuntu 26.04.1 LTS 26.04, headless
Opening file: build/index.pck
Loaded 319 imported files
Detected Engine Version: 4.7.2
Detected Bytecode Revision: 4.5.0-stable (ebc36a7)
Successfully loaded PCK!
Version: 4.7.2
Verified 700 files, no errors detected!
Extracted 700 files, no errors detected!
Saved project config.
********************************EXPORT REPORT********************************
Totals:
Decompiled scripts: 66
Scripts not decompiled: 0
Imported resources for export session: 319
Successfully converted: 319
Lossy: 168
Rewrote metadata: 212
Non-importable conversions: 0
Not converted: 0
Failed conversions: 0
-------------
------------------------------------------------------------------------------------
Use Godot editor version 4.7.2 to edit the project.
*******************************************************************************
Recovery finished in 00m06sComparing recovered code with source
I ran a script comparing all 66 recovered .gd scripts against my original git repository (ignoring whitespace and comments):
| Metric | Result |
|---|---|
| Scripts recovered | 66 / 66 |
| Code match after normalization | 66 / 66 matched after normalization (25 exact matches; 41 differ only in float notation; no meaningful logic differences detected) |
| ASCII chamber maps | 37 / 37 byte-for-byte identical |
| Imported assets converted | 319 converted (168 of which were marked lossy/downscaled) |
| Comment lines | 2,170 → 0 (blank lines observed in recovery) |
The only “differences” in code were trivial literal representations:
- const TAUT_DISTANCE: float = 1.20
+ const TAUT_DISTANCE: float = 1.2
- if aabb.size.length_squared() < 0.000001:
+ if aabb.size.length_squared() < 1e-06:
Once the code is decompiled into clean GDScript, this is where an AI agent thrives: an LLM fed these 66 recovered scripts can explain the game loop, map enemy patterns, or uncover hidden mechanics in seconds.
What was actually lost: the why
In this experiment, every comment came back as a blank line, so line numbers in the recovered files happened to align with the original source. The constants and algorithms survived, but the reasoning behind them didn’t:
# Original source
# standing apex = 7.8^2 / (2*24) = 1.27 m
# double jump apex = 1.27 + 0.96 = 2.23 m
const MOVE_MAX_RISE_CELLS := 3
# Recovered decompilation
const MOVE_MAX_RISE_CELLS := 3Also, my solver and chamber validator weren’t in the recovered build at all because the Godot export filter excluded tools/ and validator/. What you never ship cannot be recovered.
How to actually protect your Godot game
You can take measures to significantly increase the difficulty of reverse engineering, but absolute client-side prevention is impossible.
Godot is an open-source engine. As long as your game runs on the player’s device, the code and assets must ultimately be decrypted and executed in memory by the engine. However, through the following two core strategies, you can effectively deter the vast majority of casual unpackers and script kiddies.
(Note: While GDRE recovery was directly demonstrated on The Jade Crypt above, the following encryption and obfuscation sections outline architectural defense options based on official documentation and community tooling, rather than verified tests on this specific 4.7.2 build.)
Strategy 1: Compile custom export templates and enable PCK encryption
Godot provides built-in AES-256 encryption for selected resources inside exported PCK archives. This can prevent straightforward extraction of protected scripts, scenes, and assets using tools such as GDRE Tools.
- Core Principle: Encrypt selected files inside the PCK using a 256-bit AES key. The matching decryption key is compiled into the Godot runtime, rather than distributed as a separate plaintext key file.
- Critical Requirement: You must compile your own export templates from Godot’s source code. Official precompiled export templates do not contain your encryption key and cannot decrypt resources encrypted with it.
Generate a 256-bit key:
openssl rand -hex 32Set the generated 64-character hexadecimal key before compiling the appropriate platform-specific export templates:
export SCRIPT_AES256_ENCRYPTION_KEY="<your_64_character_hex_key>"Because our target experiment was a Web build, compiling custom Web export templates requires the Emscripten toolchain:
# Run from the Godot engine source directory
# Requires the Emscripten toolchain
scons platform=web target=template_releaseDuring compilation, Godot should report that the custom SCRIPT_AES256_ENCRYPTION_KEY has been detected. The resulting Web export template is generated under bin/ as godot.web.template_release.wasm32.zip. Select the generated archive as the custom release template in the Web export preset. (Other platforms require their own build targets, such as platform=windows or platform=linuxbsd.)
- Configuring the Export Preset: In Godot’s Project → Export → Encryption settings:
- Enter the same 64-character hexadecimal key.
- Configure the include filters for the resources you want encrypted.
- Select the matching custom export templates in the export preset.
- Export, verify that the game runs using the custom template, and confirm that the intended resources are actually encrypted.
- Important: Godot’s encryption include filters are empty by default. Without specifying which files to encrypt (such as
*.gd,*.tscn, or*), entering a key alone does not protect your project resources. - Platform Considerations: The custom export template must match the target platform. For Web exports, this means working with the WebAssembly-based Godot runtime. Web-based protection should be treated as an additional obstacle, not a secure boundary, because the browser must obtain everything needed to run the game.
- Android Note: Android packaging differs from desktop PCK exports. Verify how resources are packaged for your specific APK or AAB workflow rather than assuming that enabling PCK encryption automatically protects all packaged assets.
Strategy 2: Use GDScript obfuscation plugins
Even with an encrypted PCK, scripts are decrypted in memory when the game loads. Obfuscation ensures that if someone recovers or dumps the bytecode, reading and modifying the code is substantially harder.
- Example Tool: GDMaim (open-source Godot obfuscation plugin).
- How it works: During the export process, GDMaim renames private variables, internal functions, and script classes into meaningless random strings (like
__6vjJ), while optionally scrambling string literals. It also generates asource_mapso you can map stack traces and errors back to your original source code during debugging. - Usage Restrictions and Compatibility:
- Obfuscation plugins typically do not process binary scene files (
.scnor.res). You must save your scenes and resources in text format (.tscn/.tres) so the obfuscator can parse and rename node references consistently. - Check compatibility with your Godot version: GDMaim’s original documentation references Godot 4.2-stable, while newer releases report testing with Godot 4.5.1 and 4.6 (with added Web support). Compatibility with Godot 4.7.2 should still be verified, particularly when using compiled GDScript token exports or platform-specific builds. In some Godot versions, script export must first use text mode for the obfuscator to process scripts, with its own export mode handling subsequent bytecode conversion. Test exported gameplay, scene references, signals, resource serialization, and dynamic script calls before release.
- Obfuscation can also break code relying on dynamic identifiers, reflection, string-based
call(), or serialized resource properties.
- Obfuscation plugins typically do not process binary scene files (
Realistic limitations to keep in mind
- Not absolutely secure against determined reverse engineers: The AES key is inside your executable. While finding it in an optimized binary takes skill, specialized memory inspection tools (like
KeyDot) can hook the running process or scan memory to extract the AES key and decrypt the PCK. - File renaming is useless: Renaming
.pckto.dator hiding assets in subdirectories provides zero protection. Unpackers detect Godot header magic bytes regardless of file extension. - Bytecode decompilation remains efficient: Godot’s compiled token format is inherently structured. Once decrypted, bytecode will be mapped back to syntax trees by tools like GDSDecomp.
- Keep sensitive logic server-side: Never store sensitive API secrets, database credentials, or authoritative multiplayer validation in client scripts. If the client runs it, the client can inspect it.
Summary
If you want to protect your Godot release:
- Exclude internal tools using Godot’s export filters (
tools/*, tests, raw art assets). - Compile custom export templates with AES-256 encryption and configure the appropriate include filters to make straightforward resource extraction more difficult.
- Consider GDScript obfuscation (such as GDMaim, verifying compatibility with your engine version) so recovered scripts lack meaningful identifiers.
These defenses can raise the effort required for casual extraction, but they do not make client-side code inaccessible. As modern decompilers and AI-driven agents continue to evolve, the fundamental security principle remains: anything delivered to and executed on client hardware should be treated as potentially recoverable.