Grand Theft Auto -- Static Recompilation
August 23, 2026 ยท View on GitHub
A static recompilation of the original Grand Theft Auto (1997) by DMA Design, targeting modern Windows. No emulation: the original x86 machine code is lifted to compilable C, linked against modern replacements for the legacy APIs, and compiled into a native executable.
It renders.

Frame 120 of a 200-frame capture. 552,201 of 614,400 bytes non-zero, 15,255 distinct colours, no crash. Every pixel comes from the game's own code -- the recompiled MGL software renderer drawing into a surface the port hands it, then blitting that surface to the primary through a DirectDraw shim built out of our own COM vtables.
Project Status
| Phase | Status | Description |
|---|---|---|
| Phase 0 | Complete | Binary analysis, PE parsing, installer extraction |
| Phase 1 | Complete | Function discovery -- 2,590 functions over five rounds |
| Phase 2 | Complete | Classification: import callers vs. pure game logic |
| Phase 3 | Complete | x86-to-C lifting -- 952,581 lines of C, 0 errors |
| Phase 4 | Complete | Compilation and linking |
| Phase 5 | Complete | Runtime bringup -- CRT init, import bridging, WinMain |
| Phase 6 | Complete | Win32/DirectDraw HAL -- COM shim, 75 vtable slots, window and surfaces |
| Phase 7 | In Progress | Frames, input and audio -- the front end responds to keys and loads Liberty City through its own menu; sound effects play through a waveOut mixer. Remaining: the front end never starts the loaded game (see docs/PROGRESS.md) |
What Works Today
The recompiled binary runs the game's own code from its CRT entry point to a rendered title screen:
- Maps at
0x400000, its original image base, through a self-relaunching launcher -- so every absolute address in the lifted code is simply correct - Enters through the lifted CRT startup: heap, stdio, locale and codepage tables, argv, environment, then WinMain
- All 166 imports bound by name from the image's own import table
- Reads its own data files out of
..\gtadata\, extracted from the original InstallShield cabinets - Creates its window, negotiates a cooperative level and display mode, and gets a primary surface with a back buffer
- Drives our DirectDraw:
EnumDisplayModes,CreateSurface,Lock/Unlock,CreatePalette/SetEntries,Blt/BltFast,Flip-- 75 slots across four interfaces, each a bridge cookie in a vtable built in game memory - Plays sound: a waveOut software mixer stands in for the Miles Sound System -- 40 voices, sample format and rate from the game's own calls, and music tracks loaded from RIFF/WAVE
- Renders: hundreds of frames captured per run, no crash, running until the watchdog stops it
- Takes input: keys arrive as window messages, through
PeekMessageAandDispatchMessageAinto the game's own WndProc, and drive the front end
Left alone the game loops its title animation -- nine distinct frames, and
GetKeyState is never called. Send it keys and it reads them and moves on to
the city-select map: twenty-six distinct frames over the same interval. What it
does not do yet is navigate a menu through to actually starting a city.
The Interesting Bugs
A recompilation fails a long way from its cause, so these are worth recording.
Every zero looked negative. The game asked for ..\GTADATA\AUDIO\LEVEL-00.RAW
when the format string is LEVEL%03d and the file on disk is LEVEL000.RAW.
%03d of zero should print 000; the port printed -00. The lifted _output
decides sign with test edx,edx / jg / jl, and the second of those two jumps sat
in a different basic block from the compare -- where the lifter had discarded
what set the flags and fell back to a stale carry. One branch, and every zero the
CRT ever formatted came out negative.
One in nine functions started in the wrong place. Blocks were emitted lowest-address-first, and a function whose entry is not its lowest-addressed block -- one sharing a body with a jump-table arm or a common tail -- began executing in the wrong block. 295 of 2,590 functions, 11%, running code that was never called.
Flags that no single instruction set. MSVC's signed-modulo idiom
(and / jns / dec / or / inc / je) reaches its final je from two predecessors
that set the flags with different instructions, so no static pairing exists.
474 branches were in that position. They now record which kind of instruction
wrote the operand snapshot and settle the condition at runtime, exactly.
Those three shared one symptom -- a conditional branch reading whatever carry happened to be lying around -- and together accounted for 598 branches in GTA1 alone. Fixing them took the game from a failed display init to a title screen.
Four bytes, one million times. AIL_ms_count is @0, not @4; the bridge
popped one argument too many. The game busy-waits on it, so the stack pointer
climbed four bytes per call until it walked off the top of the simulated stack.
The exe's own decorated import names had said @0 all along.
The full log is in docs/BRINGUP.md, including the two theories that were confidently wrong.
Supported Games
| Game | Year | Executable | Compiler | Status |
|---|---|---|---|---|
| Grand Theft Auto | 1997 | Grand Theft Auto.exe | MSVC 6.0 | Renders |
| Grand Theft Auto | 1997 | gtawin.exe (original) | MSVC 4.2 | Analyzed |
| GTA London 1969 | 1999 | gta_uk.exe | MSVC 5.1 | Lifted (2,137 functions) |
| GTA London 1961 | 1999 | GTA_61.exe | MSVC 5.1 | Analyzed |
| Grand Theft Auto 2 | 1999 | gta2.exe | MSVC 5.1 | Blocked (TAC-packed) |
All of these share the Race'n'Chase engine, written by Mike Dailly at DMA Design. GTA1 and GTA London run the identical engine -- London is a mission pack. GTA2 evolves it onto DirectX 6, with similar file formats and game logic.
Building
Requirements
- CMake 3.20+
- Visual Studio 2022 (MSVC), Win32 target
- Python 3.10+ with
capstoneandpefile - SDL2 (optional; audio does not need it -- the mixer uses waveOut)
- The pcrecomp toolkit
Step 1: lift the game
This repository ships no lifted code. The C under src/recomp/gen/ is
machine-translated from the game's own executable, so it is not ours to
distribute -- you generate it from your copy. Budget about an hour; the
disassembler makes five discovery passes over the binary.
python tools/run_pipeline.py "game/extracted_full/WINO/Grand Theft Auto.exe" --all --split 500 --functions-json config/functions_gta1.json
python tools/soften_fatal.py
That writes 2,590 functions as ~950k lines of C into src/recomp/gen/. Re-run it
after any change to the pcrecomp lifter.
Step 2: build
cmake -B build -G "Visual Studio 17 2022" -A Win32
cmake --build build --config Release
Add -DGTA_TRACE=ON for the crash trace ring.
Game Data
You supply your own copy of the game. Extract the real data from the installer cabinets:
python ../tools/tools/assets/isextract.py game/data1.cab game/data1.cab -o game/extracted_full
The archive spans data1.cab and data2.cab; the extractor discovers both and
reports the split (Volumes: data1.cab [0..17], data2.cab [17..194]). All 195
files should extract with no errors. The stub copy in game/extracted/ is not
usable -- 171 of its 173 files are zero bytes.
Running
cd game/extracted_full/WINO
/path/to/build/bin/Release/gta1.exe "Grand Theft Auto.exe"
Run from the directory holding the executable: the game resolves its data as
..\gtadata\, relative to its own location. The original executable is the
argument -- it is mapped at 0x400000 so the lifted code can read its .rdata
and .data.
To capture frames:
GTA_DUMP_FRAMES=200 GTA_WATCHDOG_MS=60000 gta1.exe "Grand Theft Auto.exe"
The other diagnostic switches are listed in docs/BRINGUP.md.
Architecture
src/
common/ Shared types, math, memory model
engine/ Recomp runtime, IAT bridges, image loader, premap launcher
video/ DirectDraw shim, Smacker shim
sound/ waveOut mixer replacing the Miles Sound System
renderer/ Modern OpenGL 4.x, replacing SciTech MGL (not yet wired)
net/ Network play replacing DirectPlay (stub)
recomp/gen/ Lifted GTA1 -- 2,590 functions, 952,581 lines (generated)
recomp/gen_london69/ Lifted London -- 2,137 functions, 205,665 lines (generated)
tools/
run_pipeline.py Analysis, discovery, lifting, code generation
soften_fatal.py Post-lift patch so one failed check does not hide the rest
config/
functions_gta1.json Discovered function list
docs/
TECHNICAL.md Engine, binary, formats, import surface
BRINGUP.md How it gets 0x400000, diagnostics, the fix log
PROGRESS.md Phase-by-phase detail and known gaps
Statistics
| Metric | Value |
|---|---|
| Functions lifted (GTA1) | 2,590 |
| Lines of generated C | 952,581 |
| Lifting errors | 0 |
| Imports bound by name | 166 of 166 |
| DirectDraw methods served | 75 vtable slots |
| Stale-flag branches remaining | 0 (was 598) |
| Game executables analyzed | 5 |
Documentation
- docs/TECHNICAL.md -- the Race'n'Chase engine, GTA1's PE layout, subsystems, data formats, import surface, MGL notes
- docs/BRINGUP.md -- how the image gets its original base, the diagnostic switches, and the full fix log
- docs/PROGRESS.md -- phase checklists and known gaps
License
The code in this repository is released under the MIT License.
That covers this project's own source -- the runtime, the IAT bridges, the DirectDraw, Miles and Smacker shims, the launcher and the tooling. Everything in this repository is code written for this project.
It does not cover Grand Theft Auto itself. The game's binary, assets and data remain the property of their owners and are not distributed here. Neither is the lifted C: that is machine-translated from the original executable and carries whatever rights the executable does, so it is generated on your machine, from your copy, and never checked in.
Legal
This project is for game preservation purposes. You must supply your own copy of the game. No copyrighted game assets are included in this repository.
Rockstar Games have made Grand Theft Auto and Grand Theft Auto 2 freely available for years, which is the only reason this project targets them rather than a title still being sold. If the rights holders would prefer this not exist, say so and it comes down.
Credits
The game itself is the work of DMA Design -- Mike Dailly wrote the Race'n'Chase engine this recompilation is built on, and it is a genuinely good piece of 1990s engineering to read. Published by BMG Interactive, now Rockstar Games, who released it as freeware.
Standing on:
- pcrecomp -- the unified PC static recompilation toolkit this project shares with its siblings
- Capstone -- disassembly
- SDL2 -- audio, and eventually windowing and input
- SciTech Software for MGL and RAD Game Tools for Smacker and the Miles Sound System -- the libraries being stood in for here
Related Projects
Part of the sp00nznet recompilation collection: