# SPEED2.EXE build and decompilation notes

## Binary located in the XP VM

The XP disk image at `/home/jhylands/vms/winxp/winxp.qcow2` contains the installed game under `Program Files/EA GAMES/Need for Speed Underground 2`. The game's `SPEED2.EXE` was read from NTFS MFT entry 11609. The analysis copy is `/tmp/nfsu2-speed2.exe`; it is kept out of the project because it is proprietary game code.

SHA-256: `f9dd86c054878ce6276beb07c1fd61874f7a1e4bf1f241b084c65b73e24168a7`

## Build fingerprints

- PE32 GUI executable for 32-bit Intel x86.
- PE linker version fields: 7.0. This is consistent with Microsoft's VC7-era linker, but does not identify the exact compiler version or build switches.
- PE timestamp decodes to 1987-09-15, which is implausible for this 2004/2005 game executable. Treat the timestamp as overwritten or unreliable.
- No PDB/debug directory, exports, or symbols are present. The game code is stripped.
- Six PE sections are present; the last two section names are blank. Embedded strings include `/* HOODLUM */` and `ON2.COM VERSION VP60D 6.1.0.5`, indicating this VM's executable has been modified by a release/crack wrapper. Therefore, its linker metadata may not faithfully describe the original shipping executable.
- Imports include DirectDraw, DirectInput 8, DirectSound, and Direct3D 9.

## Compiler matching assessment

The executable is x86 Windows code using the `__thiscall`/Windows ABI patterns expected for an MSVC C++ game. Ghidra 11.0.3 imports it as `x86:LE:32:default:windows`. That is the useful compiler/ABI match for interpreting the binary. The PE header alone does not justify asserting an exact Visual C++ release, and compilation matching cannot recreate the source or recover removed names.

## Matching-decompilation route

An upstream project now targets both PC `SPEED2.EXE` v1.0 and v1.2: [cobanov/nfsu2-decomp](https://github.com/cobanov/nfsu2-decomp). Its v1.2 target expects a 4,800,512-byte executable with entry point `0x75BCC7`, which matches this VM copy. I cloned it to `/tmp/nfsu2-decomp`, placed the VM executable in its ignored `orig/SPEED2_EXE_1_2/` input folder, and successfully generated the v1.2 build configuration. It selects the `Win32/7.1` linker/toolchain profile.

This establishes a practical matching-decompilation path, but not a completed decompilation: I repeated the setup from a fresh clone on 2026-10-14, and the PC v1.2 `splits` list was still empty, so configuration generated no matched PC functions or usable source rebuild. The project documents that v1.0's Rich header identifies MSVC 7.1 build 3077 for most objects; its v1.2 compiler profile is a project assumption pending further verification. The VM binary contains a HOODLUM marker and two unnamed PE sections, so byte-matching should first verify the game-code sections against a clean/decrypted v1.2 executable. The project notes that SafeDisc-wrapped retail code must be unpacked before splitting.

For our WebGL reconstruction, the useful next step is targeted work on the car physics, traffic controller, and lane/intersection AI methods, with matching used to validate each recovered function. Whole-executable source recovery is not necessary for extracting those mechanics.

## Useful code leads

The binary retains behavior and class-name strings, including `TrafficMover`, `TrafficController`, `StreamingTrafficCar`, `Drive Traffic Lane`, `AIActionDriveTrafficLane`, `AIActionObeyTrafficIntersections`, and `PlayerSteering`. Basic x86 immediate-reference scans find code references for `TrafficMover` at `0x004087b7` and `0x00779b67`, `StreamingTrafficCar` at `0x0040bd47`, `TrafficController` at `0x00429cf7` and `0x00779753`, and the `Drive Traffic Lane` string at `0x004242c1`. These are starting points for Ghidra cross-reference analysis; a string reference alone does not establish a routine's full behavior.

## Targeted decompilation results

Ghidra 11.0.3 accepted the executable as `x86:LE:32:default:windows`. Full automatic analysis spent several minutes in expensive decompiler analysis and emitted an address-space error, so I switched to a targeted import with automatic analysis disabled and manually created functions at class/vtable addresses. That produced readable C-like output without waiting for whole-game analysis.

The class strings sit next to pointer tables. Following those tables found real action methods as well as serializers:

- `0x00408820` is a `TrafficMover` update method from its vtable. It advances position and heading using elapsed time and speed, clamps the mover's speed to `0..24.5865` internal units, updates the associated vehicle transform, and refreshes wheel state. It is evidence for a simple traffic mover, not necessarily the main ambient traffic controller.
- `0x004242d0` is the `AIActionDriveTrafficLane` action method. It examines traffic/controller state, queries vehicle speed through a virtual method, and updates an action target field at `+0x1f0` while calling lane-follow helpers.
- `0x00425150` is the `AIActionObeyTrafficIntersections` action method. It checks lane/intersection state and changes the target-speed/action flags. Its branches use constants `6`, `15`, and `30`; the exact units and helper semantics still need confirmation.
- `0x004087b0`, references `TrafficMover`: serializes fields at offsets `0x0c`, `0x14`, `0x18`, `0x1c`, and `0x20`.
- `0x0040bd40`, references `StreamingTrafficCar`: serializes fields at `0x900` through `0x914`, so this object includes a large base or embedded state block.
- `0x00429cf0`, references `TrafficController`: serializes fields around `0x77c` through `0x7a4` and calls additional serializers.
- `0x004242c0` returns the `Drive Traffic Lane` action name.

The targeted pseudocode is in `/tmp/nfsu2-key-decompile.txt`; the temporary Ghidra project is under `/tmp/nfsu2-ghidra-actions`. This confirms matching the Windows x86 ABI is useful, and it gives concrete hooks for a closer traffic simulation. Full automatic analysis remains incomplete.
