Case study · DX-Ball 1.07

Rebuilding DX-Ball
from its executable.

The goal is a maintainable C version of the 1996 Windows game. REA helps the agent inspect the original, one function at a time.

Windows i386 · C · REA

DXBALL.EXE function 0x00406400 is inspected with REA. A brick-hit caller supplies 20 plus 30 times tile_x. Instructions load x, multiply by 1.5625, subtract 500.0, apply pan_scale and return an integer. The maintained C is checked independently against the original x86 in 3,205 cases and by VC4.0 compiler replay matching 63 bytes.
One function, from executable to checked C. REA supplies the instructions, callers and data reads; the reconstruction project implements and tests the result. Open figure
55
maintained C functions
45,380
original-x86 differential cases
33
byte-exact functions

Project checkpoint: 7 October 2026. Progress ledger · Test coverage

The project so far

The recovered code covers board and resource handling, brick hits, animations, particles and bonus production. Current builds provide inspection utilities and an analysis library. Work on the playable game continues with ball and paddle physics, power-up handling and Windows integration.

The analysis starts from the DX-Ball 1.07 executable. REA returns function code, instructions, callers and state references. These findings guide the C implementation; execution of the original x86 functions and compiler replay check the result.

Finding the sound-pan calculation

When a brick is hit, its horizontal position is passed to the sound code. The investigation needed to recover how that screen coordinate becomes a left/right panning value.

Your coding agent

Use REA to find how DX-Ball calculates sound panning. Explain the calculation and show the code.

An example prompt for your coding agent, with the local executable available. The investigation below shows the REA queries and evidence behind the answer.

The agent used REA to inspect the function, follow its brick-hit caller and read the constants from the executable. Those results supplied the input and arithmetic needed to write the C function below.

The first function result for 0x406400 included pseudocode declaring FUN_00406400(void) and calling __ftol(). Its instruction view showed a stack input and floating-point operations. That discrepancy gave the agent a concrete reason to keep investigating.

The first decompiler view
REA result · pseudocode excerpt
longlong FUN_00406400(void)
{
  longlong lVar1;

  lVar1 = __ftol();
  return lVar1;
}

The output shows a conversion call. Reading the instructions below reveals the input and the calculation feeding that call.

Three questions answered through REA

  1. Recover the missing input

    Agent → REA · analyze_function
    {"procedure": "0x406400"}
    REA → agent · instruction excerpt
    0x406409: MOV EAX, dword ptr [EBP + 0x8]
    0x40640c: MOV dword ptr [EBP + -0xc], EAX
    0x40640f: FILD dword ptr [EBP + -0xc]

    The function result includes instructions alongside pseudocode and callers. Here, [EBP+8] exposes the integer input missing from the decompiler view.

  2. Follow the caller to understand the input

    Agent → REA · analyze_function
    {"procedure": "0x411f40"}
    REA → agent · caller excerpt
    0x411f5b: ADD EAX, 0x14
    0x411f5e: PUSH EAX
    0x411f5f: CALL 0x00406400

    REA identified this caller in the first result. Its preceding instructions scale tile_x by 30; adding 20 gives the brick's screen coordinate, 20 + 30 × tile_x.

  3. Read the values behind the memory addresses

    Agent → REA · two read_bytes requests
    {"address": "0x420068", "length": 16}
    {"address": "0x4210a0", "length": 8}
    REA byte results · decoded as doubles
    000000000000f93f → 1.5625
    0000000000407f40 → 500.0
    000000000000f03f → 1.0

    The returned bytes establish the two arithmetic constants and initial pan scale. The agent now has the values needed for the C expression.

REA exposes these operations through CLI and MCP, with target identity and Evidence IDs in the results. The agent can follow up on a caller or data address directly, then use the findings to write maintained C.

From REA's findings to C

Follow the five steps below. Each selection highlights the original instructions and the C lines they informed.

Original x86 · excerpt
0x406409: MOV EAX, dword ptr [EBP + 0x8]
0x40640c: MOV dword ptr [EBP + -0xc], EAX
0x40640f: FILD dword ptr [EBP + -0xc]
0x406415: FMUL double ptr [0x00420068]
0x40641e: FSUB double ptr [0x00420070]
0x406427: FMUL double ptr [0x004210a0]
0x406430: CALL 0x0041678c
0x40643e: RET
Reconstructed C
DxBallInt dxball_screen_pan(DxBallInt x)
{
    double pan;
    pan = (double)x;
    pan = pan * 1.5625;
    pan = pan - 500.0;
    pan = pan * dxball_pan_scale;
    return (DxBallInt)pan;
}

01 · Read the input. The instruction view in REA's function result reads [EBP+8] and uses FILD to load the integer. Following its caller through REA establishes the screen-coordinate meaning of the C parameter x.

The assembly excerpt selects the input, arithmetic and return instructions. The full listing below also includes the intervening stores and function setup and cleanup.

Full assembly and supporting evidence
REA result · 0x406400–0x40643e
0x406400: PUSH EBP
0x406401: MOV EBP, ESP
0x406403: SUB ESP, 0xc
0x406406: PUSH EBX
0x406407: PUSH ESI
0x406408: PUSH EDI
0x406409: MOV EAX, dword ptr [EBP + 0x8]
0x40640c: MOV dword ptr [EBP + -0xc], EAX
0x40640f: FILD dword ptr [EBP + -0xc]
0x406412: FST double ptr [EBP + -0x8]
0x406415: FMUL double ptr [0x00420068]
0x40641b: FST double ptr [EBP + -0x8]
0x40641e: FSUB double ptr [0x00420070]
0x406424: FST double ptr [EBP + -0x8]
0x406427: FMUL double ptr [0x004210a0]
0x40642d: FST double ptr [EBP + -0x8]
0x406430: CALL 0x0041678c
0x406435: JMP 0x0040643a
0x40643a: POP EDI
0x40643b: POP ESI
0x40643c: POP EBX
0x40643d: LEAVE
0x40643e: RET

What the caller supplies

The brick-hit function at 0x411f40 scales its tile coordinate by 30, adds 20, then pushes it before the call:

0x411f50: MOV EAX, dword ptr [EBP + 0x8]
0x411f53: ADD EAX, EAX
0x411f55: LEA EAX, [EAX + EAX*0x2]
0x411f58: LEA EAX, [EAX + EAX*0x4]
0x411f5b: ADD EAX, 0x14
0x411f5e: PUSH EAX
0x411f5f: CALL 0x00406400
0x411f64: ADD ESP, 0x4

What the data reads establish

REA byte reads, decoded as little-endian doubles
Address Value Used for
0x420068 1.5625 First multiplication
0x420070 500.0 Subtraction
0x4210a0 1.0 initially Stored pan scale

Recorded with REA 4.1.0 for the hash-pinned DX-Ball 1.07 target. The linked investigation notes retain the Evidence IDs.

Maintained source · Investigation notes and evidence references

Checking the recovered function

The input, caller context and constant values returned through REA guided the maintained C implementation. The project then checked it against the original x86 function and the pinned compiler. For this function, both checks pass.

3,205 behavior cases

The tests execute the original x86 function and compare its return value with the maintained C. They cover every integer position from 0 to 640 at five pan scales: 0, 0.5, 1, 20 and −1.

63 matching bytes

The C function is compiled with the pinned VC4.0 toolchain. Compiler replay matches the complete function after applying the reviewed relocations and checking the referenced constants.

At a scale of 1, the recovered calculation returns −500 at the left edge, 0 at the center and 500 at the right edge. The next part of the audio work is integrating that value with the game's sound backend.

Read the compiler replay details

Continue the investigation

The same approach is being used for particle updates, explosion queues and bonus generation: inspect the relevant functions, recover their state and dependencies, then compare the implementation with the original.

To inspect the sound-pan function yourself, follow the DX-Ball project's setup instructions and supply its matching original target. Then run:

In the DX-Ball checkout
scripts/rea function original/DXBALL.EXE 0x00406400 \
  --snapshot .analysis/rea/dxball.snapshot.json --json