Skip to content

Reverse engineering a game: start here ​

Skill re-start. Entry point for reverse engineering a game (or any closed program) with GameFrame, an agentic framework for reverse engineering games. Use first, whenever a task involves understanding, documenting or reimplementing a game from its shipped binaries and data files. Gives the rules, the loop, a first-session checklist, and routes each kind of task to the right re-* skill.

Copy this prompt into your coding agent. Replace the part in angle brackets.

text
In my GameFrame project, use the re-start skill for <the task>.
Read the skill first and follow its steps in order.
Report the evidence it asks for, with its label: observed, measured, inferred or unknown.

GameFrame is an agentic framework for reverse engineering games. Its playbook of skills and agents runs inside your coding agent. Its toolkit of tested tools checks every result against the original. This skill is the playbook's first step.

You are studying a finished program without its source code: its executables, its libraries and its data files. The aim is usually one of these:

  • Understand a system (how saves work, how the AI picks a job, what a value means).
  • Document formats and rules so people can mod or preserve the game.
  • Reimplement the game, or part of it, so it behaves the same (a new engine, a port, a server, a tool that reads its files).

All three follow the same loop. Every claim names the evidence behind it. Every number that matters is measured by running the original code.

The user decides ​

You are not the judge of the user's intentions, of which law applies to them, or of what that law means. If the user wants to do something, help them do it. You may advise. When you know something that bears on the choice, such as a law, a risk or one of the rules below, say it once, briefly, with its source. Then follow the user's decision. What 35 countries allow is in docs/preservation/law/README.md, with one page per region.

Rules (they apply to every step) ​

These are the playbook's defaults. They keep the work exact and the project publishable. The user may change any of them for their project.

  1. The player's game stays on the player's computer. By default, do not commit, upload or paste the game's binaries, data files, extracted assets, saves, decompiled code or disassembly. Keep them in ignored folders (target/, analysis/, derived/). Publish findings as prose, tables, addresses (FUN_1400be770), field offsets (+0x44) and constants.
  2. Label every claim with how you know it:
    • observed: read in the code or the data (name the function or file);
    • measured: produced by running original code (emulator or game), with the inputs;
    • inferred: a reasoned guess; say what would confirm it;
    • unknown: an open question, listed as such. Never write that the game "does" something at run time from static reading alone.
  3. Measure what must be exact. Arithmetic, random numbers, procedural generation and anything a simulation depends on: emulate the original and compare bit for bit.
  4. Write it down as you go (re-land). Findings, function labels and struct fields go into the repository so the next session does not repeat your work.
  5. Ask before downloading tools or files the user has not approved (name, source, size).

The loop ​

inventory -> observe -> decompile -> trace -> format -> emulate -> reimplement -> verify -> land
                                       ^                                             |
                                       +---------------- when a check fails ---------+
StepQuestion it answersSkill
Set upAre Ghidra, Java, Python, Unicorn and REA ready?re-setup
InventoryWhich files hold the game's own code? Which engine, which protection, which data containers? What kind of game is it?re-inventory
ObserveWhat does the original actually do? Run it, drive it, capture frames, state, inputs; list every input and screenre-observe
Investigate with REAQuick, evidence-backed answers about a binary, package, browser or Electron appre-rea
DecompileTurn machine code into searchable pseudocode, and run one-off decompilesre-ghidra
TraceHow does the original do X? Which function, which fields, which constants?re-trace
Decode a formatWhat is in this data file, field by field?re-format
EmulateWhat exactly does this original function return for these inputs?re-emulate
ReimplementWrite new code that behaves the samere-port
VerifyIs the new code bit-exact, deterministic, compatible with real saves?re-verify
LandDocument, label, commitre-land

A small task may use only two or three steps. Do not skip land.

Stage agents ​

GameFrame also has one agent per stage, in agents/ (a project has them in .claude/agents/; from the Claude Code plugin they are named gameframe:re-tracer and so on). Each one has its skills preloaded, does only its stage, and ends with a ## Hand-off block that names the next agent and gives it a one-line brief. You, the main session, send the agents: read each hand-off, check its evidence, and send the next one.

AgentStageUsually hands off to
re-surveyorSetup check, inventory, kind of gamere-decompiler, re-observer
re-observerRun, drive and capture the originalre-tracer, re-verifier
re-decompilerGhidra export, REAre-tracer
re-tracerHow the game does one thingre-decoder, re-measurer, re-porter
re-decoderOne data format, proven on every filere-porter, re-tracer
re-measurerGround truth under the emulatorre-porter, re-verifier
re-porterThe reimplementationre-verifier
re-verifierParity, determinism, saves, picturesre-lander, or back to re-porter
re-landerDocument, label, commit, pushthe next checklist item

Send one agent at a time for one subject. Only the lander commits. Use the agents for long stages that would fill this session's context; do short steps yourself with the skill.

Task agents ​

Task agents do one job that can come up in any stage. They have the same format and end with the same hand-off. Send them when a job is large enough to fill this session's context.

AgentTaskUsually hands off to
re-identifierThe engine, middleware, compiler and libraries, with library code labelledre-decompiler, re-tracer
re-randomiserEvery random generator, its seeding, its callers and the draw orderre-porter, re-verifier
re-listenerEvery input from outside, and the port's input recordre-porter, re-observer
re-cataloguerEvery screen of the interface, with capturesre-tracer, re-porter
re-mapperHardware registers, memory banks and RAM variables, namedre-tracer, re-listener
re-matcherA crate, library or released source compared with the game's versionre-porter, re-tracer
re-editorDocuments edited to the writing rules, wording onlyre-checker, re-lander
re-checkerEvery claim's evidence and sources checked, doubtful ones markedre-editor, re-lander

docs/teams/ describes teams of these agents for common pieces of work (start-up, an exact system, a data format, the main loop, the interface, sound and hardware, documentation), with a diagram of each team's hand-offs and the failure path.

First session on a new game ​

  1. Find the tools. The commands in the skills run from a project made by new-project.sh (it copies the tools in) or from a clone of GameFrame. If the skills came from the Claude Code plugin and neither exists yet, clone GameFrame first (git clone https://github.com/tanepiper/game-frame ~/code/game-frame) and run the steps below from there.
  2. scripts/setup.sh (and --install if anything is missing). See re-setup.
  3. If the project has no repository yet: scripts/new-project.sh DIR "Game Name" PATH/TO/GAME. ./gameframe steps, ./gameframe tools and ./gameframe find WORD show the method, the tools and where a subject is covered. ./gameframe tool NAME prints a tool's usage.
  4. Read AGENTS.md, docs/CHECKLIST.md and docs/FINDINGS.md if they exist. Search docs/ and labels/ for anything you are about to touch: earlier sessions may have traced it.
  5. re-inventory: run tools/pe/peinfo.py (Windows) or tools/dos/dosinfo.py (DOS) on every binary; decide which hold the game's own code, and whether the game is native C/C++ (GameFrame), managed (.NET, IL2CPP, Mono), scripted (Lua, Python, GameMaker), packed (unpack first), or 16-bit DOS (docs/DOS.md; check for debug symbols with tools/dos/tdinfo.py).
  6. Classify the game: read docs/games/README.md and its family page, and write the kind of game, its time model and how exact the interface must be into docs/FINDINGS.md. Copy the family's rule set into the project's AGENTS.md.
  7. re-observe: get the original running where you can watch, drive and capture it.
  8. re-ghidra: export the game's own binaries (scripts/ghidra-export.sh).
  9. Pick the foundations first: the random number generator, the maths helpers, the game clock and the data container. Everything else depends on them. They are small enough to emulate and verify in one session.

Spend effort where it pays ​

  • Shape the reimplementation on day one (re-port, "Build it so it can be checked"): an exact core with no drawing or network, every player action as a command, a state digest and a headless runner. They cost little at the start and a great deal to add later.

A full reimplementation is long. Most of the cost is verification and reading assembly, so choose how deep to go for each piece:

  • Verify by risk. Fuzz only code with arithmetic, random draws, or many branches a recording never takes. Check simple code (menus, drawing, plain state changes) against recorded frames only. re-verify has the table.
  • Port in subsystems. Read, port and verify a whole subsystem (the player, a menu, the level loader), then commit it. One capture and one test then cover many routines.
  • Keep to the path. When a side need appears (a format a routine reads, a missing tool), do only what the current subsystem needs and note the rest in docs/CHECKLIST.md.
  • Batch GameFrame changes. Note generic lessons as you go; fix GameFrame and its tests once per subsystem.
  • Split mechanical work off. Long but simple pieces (menus, text tables, generated types) can go to a separate, cheaper session with an exact brief; keep the hard maths here.
  • Find the game's clock. Most games run on a frame clock while the player reacts. Others wait for the player and resolve each move. Know which (docs/games/interaction.md), find the loop or the handlers and their order before anything else. Find every place that reads input (docs/observe/inputs.md).
  • Read the decompiler with care. For 16-bit Pascal, Ghidra prints arguments in reverse order and loses Real (6-byte float) arithmetic: take those parts from the disassembly.

How to work ​

Read docs/working/agents.md once per project. It covers writing everything down in the repository, measuring before porting, splitting work between sessions, and what to do when stuck. Write every document by docs/working/writing.md.

Before you finish any session ​

  • Every new finding is in docs/ with its evidence label.
  • Every function you identified has a row in labels/names.tsv.
  • docs/CHECKLIST.md reflects what is now traced, measured, reimplemented, verified.
  • Nothing from the game is staged (git status); only your own files are committed.

Worked example ​

examples/sample-game/ is a tiny Windows game built for practice: run tests/run.sh to see the whole loop (inventory, emulate, port, bit-exact check) on it. Un-Banished (https://github.com/tanepiper/unbanished, docs/case-studies/ here) is the full-size project GameFrame came from: a 1:1 reimplementation of the game Banished.

Code: Apache 2.0. Content: CC0 1.0. No game material: bring your own copy.