Decompiling a First-Person Shooter with AI Agents
Executive Summary
Autonomous AI agents can successfully decompile complex software, but without objective, machine-checkable acceptance criteria, they produce "hallucinated" code that is readable but semantically incorrect. The most effective way to ensure fidelity in game decompilation is byte-matching decompilation, where the reconstructed C++ code is compiled and compared byte-for-byte against the original binary. This approach allows even lower-capability models to produce high-fidelity results by providing a binary PASS/FAIL signal.
The Orchestration Framework
To achieve a feature-complete recreation of a game, a multi-agent system was deployed using a combination of Claude and Codex models. The infrastructure focused on autonomy and progress tracking:
- Agent Roles: The system utilized worker agents for decompilation and commits, and a reviewer agent to coordinate and flag bugs.
- Progress Tracking: GitHub Issues were used as the primary tracking mechanism, with one issue per translation unit (.cpp file).
- Communication: Agents communicated via a shared Discord channel, allowing for agent-to-agent and human-to-agent interaction. CI failures were pushed to this channel via GitHub webhooks.
- Tooling: The agents utilized the official
ida-mcpby Hex-Rays for headless, stable disassembly and decompilation.
Overcoming Agent Drift and Hallucinations
Initial attempts at autonomous decompilation revealed that agents tend to lose focus and "drift" over time, especially as context windows fill. To maintain alignment, the team implemented two key strategies:
- Aggressive Context Compaction: The default compaction threshold was reduced from 90% to 42%. This removes volatile, irrelevant information (such as previously decompiled functions) from the context more frequently.
- Instruction Refreshing: An hourly cron job automatically injected a request for agents to reread the project's goal and operational guidelines, preventing the decay of instructions over time.
The Failure of Human-Like Review
Despite the game launching and rendering menus, the initial output was semantically flawed. Agents introduced incorrect function signatures, invented logic, and replaced efficient global variable access with expensive hash table lookups.
This failure occurred because the reviewer agent lacked objective acceptance criteria. The reviewer often accepted the worker agent's justifications in commit comments—essentially a form of unintentional prompt injection—rather than independently verifying the code against the original binary.
Implementation of Byte-Matching Decompilation
To solve the correctness problem, the team implemented a verification script that acts as a "ground truth" oracle:
- The Process: The script compiles the reconstructed C++ code using the original game's compiler. It then compares the resulting OBJ file against the original game EXE/PDB.
- Handling Relocations: Because absolute memory addresses change, the script excludes relocation bytes and instead verifies that both versions reference the same symbol with the same offset.
- Security Measures: To prevent agents from "cheating" (e.g., using inline assembly or modifying the verification script), the system forbids specific constructs and hashes the verification script in CI to ensure it hasn't been tampered with.
Results and Trade-offs
By the end of the project, 99% of the game's functions were present in the reconstructed source, with 83% being byte-exact. The project utilized a scale of 14 Luna and 2 Opus 5.5 agents in the final stages.
Advantages
- Guaranteed Semantics: Byte-exact matches guarantee identical behavior, including original bugs.
- Model Efficiency: Precise feedback allows cheaper, less capable models (like Luna or Haiku) to produce results comparable to smarter models.
Disadvantages
- Increased Effort: Agents take significantly longer to match functions exactly, as they must struggle with register selection and calling conventions.
- Diminishing Returns: Some functions cannot be byte-matched due to non-deterministic compiler output or linker behaviors (e.g., COMDAT folding).
Community Perspectives and Alternatives
Discussion among technical peers suggests alternative methods for achieving functional equivalence without the rigidity of byte-matching:
"What's been working for me is that for every function... the harness runs both the original function and the submitted function in a virtual machine/simulator/emulator... The harness will only accept the implementation if 1) the read/write sequence to RAM is identical to the original function's, and 2) there must be complete line and branch coverage of the original function being decompiled."
Other critics pointed out the high environmental and financial cost of the project, estimating 600-700 billion tokens were consumed, and questioned the utility of a project that cannot be legally shared due to trademark and copyright restrictions.
Sources
Related
- Dispatch
- Dispatch
- Dispatch
- Dispatch
- Dispatch