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 (game/, media/, saves/, analysis/, derived/). In a project these are links into the GameFrame home (~/gameframe/games/ID/), outside every repository. Publish findings as prose, tables, addresses (FUN_1400be770), field offsets (+0x44) and constants. game/ is the user's copy of the game and git keeps none. Never delete, move or git clean -x it. An older project calls it target/, which is not build output either.
  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 -> profile -> 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
ProfileWhat is the game's genre, engine, release, presentation and hardware support? What should we check first?re-profile
ViewCan a person and an agent see every file and what the decoders make of it?re-browse
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
PublishWhat would a reader want to know about the work so far? A diary entry per milestone, the documents as pagesre-site

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). Codex, Gemini CLI, GitHub Copilot and OpenCode read copies in their own formats (Agents in every client). If your agent By default, take each role yourself in this session: read the agent's file, load its skills, do its stage and write its hand-off. If the user chooses delegation and your client can start subagents, use these roles for only the stages in the agreed scope. The clean-room team is an exception after the user chooses that workflow. Its source-blind implementer must use a fresh task with only the approved packet. Ask before creating that task if the user has not already chosen the clean-room workflow. If the client cannot provide the boundary, stop after the contract and report that source-blind implementation is unavailable in this setup.

These role agents are optional. Continue in the current session by default. When separate work could help, explain why and ask whether the user wants delegation. A task being self-contained is not permission to start a subagent, create another task or make a worktree. Paid API runs have their own opt-in rule in docs/working/api-credits.md.

When the user chooses subagents, use only the stages in the agreed scope. Each agent 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, read each hand-off and check its evidence. Continue in this session by default. Send the next agent only when that stage is within the user's agreed scope; otherwise ask before extending the delegation. While an agent runs, ./gameframe progress shows the lines it has logged so far, newest first (./gameframe progress re-porter for one agent's whole log). Read that rather than the agent's transcript. Show the user each hand-off's Decisions line and anything under Open that asks them a question, before continuing to another stage. Agents do not start other agents. They stop and ask before downloading, working around protection, writing outside the project or choosing a version of the game.

AgentStageUsually hands off to
re-surveyorSetup check, inventory, kind of game and project profilere-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-typerStructures, classes and enumerations, with sizes, fields and evidencere-tracer, re-decoder, re-porter
re-matcherA crate, library or released source compared with the game's versionre-porter, re-tracer
re-specifierA neutral behavior contract with a separate source evidence ledgerre-cleanroomporter
re-cleanroomporterNew code from an allow-listed behavior contract, without source accessre-verifier
re-vectoriserSIMD code (MMX, 3DNow!, SSE) and CPU builds: routines grouped, matched to their plain twins, measuredre-porter, re-measurer, re-tracer
re-accelerator3D card APIs (Glide, ATI3DCIF, S3D): state calls named, texture paths, per-card builds and their datare-tracer, re-decoder, re-porter
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
re-publisherThe project's site: a diary entry for a milestone, a page for each new documentre-editor, re-checker, 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, clean-room implementation, 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 a plugin or a skills folder alone (the Claude Code plugin, for example) 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 there is no GameFrame home yet (./gameframe home says it is missing), run ./gameframe home init. If the project has no repository yet: scripts/new-project.sh ID "Game Name" PATH/TO/GAME. The game goes to ~/gameframe/games/ID/ and the repository to ~/gameframe/projects/ID/. A project that still keeps its game inside (target/, game-data/) moves it with ./gameframe home adopt . --id ID. ./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. Find every edition of the game (first release, regional releases, re-releases, patches, demos) and its date, and record them in docs/versions.md. First check whether the project's copy is the latest official build: read its identity with tools/triage/buildid.py, then search MobyGames, PCGamingWiki, the publisher's old site on archive.org and the GOG and Steam pages for later official releases. The reference is by default the last version released (re-inventory, "Every edition, and the reference"; docs/working/versions.md). Do this before deep work: a newer edition found late costs the work again. If one turns up mid-project, follow the move's order (moving to a newer version): export both, fill the gaps, match the functions (match_functions.py), carry the labels and patches, record the references again, and keep tests for both.
  6. 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).
  7. 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. Then read the story: the manual and the program's long strings (./gameframe run sentences), into docs/lore.md with the table "in the story → in the code → evidence" (re-inventory, "Read the story"). The lore says what each system is for and which must be exact. Read it again whenever a system's purpose is unclear.
  8. re-profile: after the first inventory, create docs/GAME_PROFILE.md. Gather the release, engine, presentation, graphics, sound and input evidence. Distinguish official support, file/code evidence, measured behavior and community reports. Ask the human only about open choices that would change the goal or next route.
  9. re-browse: run the catalogue (tools/formats/catalog.py game derived/catalog) so the person and you can see every file, and grow it into the project's viewer as the decoders come (docs/working/viewer.md).
  10. re-observe: get the original running where you can watch, drive and capture it.
  11. re-ghidra: export the game's own binaries (scripts/ghidra-export.sh).
  12. When the work on the game starts, 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.

Goals for a new project ​

Give the work goals a reader would notice, in this order unless the user's goal says otherwise (the project's AGENTS.md, "Milestones"):

  1. Inventory: every file known (re-inventory).
  2. Profile: a quick start from the game's family, engine, release and hardware (re-profile).
  3. A viewer of every asset, before the game: pictures, palettes, sounds, music, models, levels, text and saves, opened by the project's own readers (re-browse, re-format). This is the best first goal. Each format becomes three things that the rest of the project reuses: a reader crate or module, proved on every file; a document in docs/; and a panel in the viewer. The port starts with its data layer done and tested, mod tools come for free, and the person directing the work can check every decoder by looking.
  4. A site: the diary and the format documents, for the people who use them (re-site).
  5. The foundations: random generator, maths, clock and main loop, measured and verified.
  6. The game, one system at a time.

At each goal, write a diary entry and update docs/CHECKLIST.md. When a goal turns up something generic, a reader or a pitfall another game will meet, fix it in GameFrame or its crates/.

Spend effort where it pays ​

  • Build a viewer on day one (re-browse): every file listed, every decoder's output drawn or tabled. A wrong width, palette or vertex layout shows in a picture at once, and the person directing the work can check content without reading code.
  • 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 ​

When a command fails, run ./gameframe advise "<error text>" before you debug it. When the work turns to a new era, platform, runtime or kind of hardware, run ./gameframe advise TOPIC (./gameframe advise windows-9x directdraw, ./gameframe advise wine). It names known failures with their fixes, dead ends with what was tried, and the context for that era. A hook does the same after each shell command in Claude Code. Read docs/working/knowhow.md for how it works.

A report from the running port (an issue labelled gameframe-report, or a file in the port's reports/ folder) names a place the game reached that is not ported, or a crash. Its body gives the port's file and line, the original's address, the values there, the game's state and the launch to start it again. Work it as a normal slice: re-trace the address, re-emulate with the values, re-port, re-verify, then re-land with the issue's number. tools/triage/report_issue.py list shows the local reports, most frequent first, and report_issue.py file ID files one, once per place.

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.

Agents and tools ​

No agent preloads this skill. The main session reads it.

Tools this skill names:

  • peinfo: First look at a Windows executable or DLL: what it is, how it was built, what it uses.
  • dosinfo: First look at a DOS or Windows 3.x executable (MZ, NE): what it is, how it was built, what it uses.
  • tdinfo: Read Borland Turbo Debugger symbols (TDINFO, signature FB52) from a DOS or NE executable.
  • buildid: Pin down which build of a game this is: everything a copy says about its own version.
  • match_functions: Match the functions of two builds of a game, and carry your labels from one to the other: a patch, another release, a demo, a version for another platform with the same compiler.
  • report_issue: List a port's reports, and file one as a GitHub issue, once per place.
  • catalog: A first resource viewer: every file of a game, what it is, and what the project's decoders make of it, as a static HTML page for people and a JSON manifest for agents.
  • ghidra-export: Analyse one or more binaries with Ghidra (no window) and export them as text an agent can search: decomp.c, functions.tsv, strings.txt, imports.txt, exports.txt per binary.
  • new-project: Start a reverse-engineering project for one game, with GameFrame's toolkit and playbook.
  • setup: Check, and optionally install, everything GameFrame uses.

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