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.
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.
- 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. - 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.
- Measure what must be exact. Arithmetic, random numbers, procedural generation and anything a simulation depends on: emulate the original and compare bit for bit.
- 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. - 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 ---------+| Step | Question it answers | Skill |
|---|---|---|
| Set up | Are Ghidra, Java, Python, Unicorn and REA ready? | re-setup |
| Inventory | Which files hold the game's own code? Which engine, which protection, which data containers? What kind of game is it? | re-inventory |
| Observe | What does the original actually do? Run it, drive it, capture frames, state, inputs; list every input and screen | re-observe |
| Investigate with REA | Quick, evidence-backed answers about a binary, package, browser or Electron app | re-rea |
| Decompile | Turn machine code into searchable pseudocode, and run one-off decompiles | re-ghidra |
| Trace | How does the original do X? Which function, which fields, which constants? | re-trace |
| Decode a format | What is in this data file, field by field? | re-format |
| Emulate | What exactly does this original function return for these inputs? | re-emulate |
| Reimplement | Write new code that behaves the same | re-port |
| Verify | Is the new code bit-exact, deterministic, compatible with real saves? | re-verify |
| Land | Document, label, commit | re-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.
| Agent | Stage | Usually hands off to |
|---|---|---|
re-surveyor | Setup check, inventory, kind of game | re-decompiler, re-observer |
re-observer | Run, drive and capture the original | re-tracer, re-verifier |
re-decompiler | Ghidra export, REA | re-tracer |
re-tracer | How the game does one thing | re-decoder, re-measurer, re-porter |
re-decoder | One data format, proven on every file | re-porter, re-tracer |
re-measurer | Ground truth under the emulator | re-porter, re-verifier |
re-porter | The reimplementation | re-verifier |
re-verifier | Parity, determinism, saves, pictures | re-lander, or back to re-porter |
re-lander | Document, label, commit, push | the 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.
| Agent | Task | Usually hands off to |
|---|---|---|
re-identifier | The engine, middleware, compiler and libraries, with library code labelled | re-decompiler, re-tracer |
re-randomiser | Every random generator, its seeding, its callers and the draw order | re-porter, re-verifier |
re-listener | Every input from outside, and the port's input record | re-porter, re-observer |
re-cataloguer | Every screen of the interface, with captures | re-tracer, re-porter |
re-mapper | Hardware registers, memory banks and RAM variables, named | re-tracer, re-listener |
re-matcher | A crate, library or released source compared with the game's version | re-porter, re-tracer |
re-editor | Documents edited to the writing rules, wording only | re-checker, re-lander |
re-checker | Every claim's evidence and sources checked, doubtful ones marked | re-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
- 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. scripts/setup.sh(and--installif anything is missing). Seere-setup.- If the project has no repository yet:
scripts/new-project.sh DIR "Game Name" PATH/TO/GAME../gameframe steps,./gameframe toolsand./gameframe find WORDshow the method, the tools and where a subject is covered../gameframe tool NAMEprints a tool's usage. - Read
AGENTS.md,docs/CHECKLIST.mdanddocs/FINDINGS.mdif they exist. Searchdocs/andlabels/for anything you are about to touch: earlier sessions may have traced it. re-inventory: runtools/pe/peinfo.py(Windows) ortools/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 withtools/dos/tdinfo.py).- Classify the game: read
docs/games/README.mdand its family page, and write the kind of game, its time model and how exact the interface must be intodocs/FINDINGS.md. Copy the family's rule set into the project'sAGENTS.md. re-observe: get the original running where you can watch, drive and capture it.re-ghidra: export the game's own binaries (scripts/ghidra-export.sh).- 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-verifyhas 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.mdreflects 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.