Studium przypadku * DX-Ball 1.07

Przebudowa DX-Ball
z jego pliku wykonywalnego.

Celem jest utrzymanie wersji C gry Windows z 1996 roku. REA pomaga agentowi sprawdzić oryginalną, jedną funkcję na raz.

Windows i386 * C * REA

DXBALL.Funkcja EXE 0x00406400 jest sprawdzana za pomocą REA . Dzwoniący z cegły dostarcza 20 plus 30 razy tile_x. instrukcje załaduj x, pomnóż przez 1,5625, odejmij 500,0, zastosuj skalę pan_scale i zwróć liczbę całkowitą. Utrzymane C jest sprawdzane niezależnie od oryginalnego x86 w 3205 przypadkach i przez kompilator VC4.0 replay pasujący do 63 bajtów.
Jedna funkcja, od wykonywalnego do sprawdzonego C. REA dostarcza instrukcje, rozmówców i odczyty danych; projekt rekonstrukcji implementuje i testuje wynik. Otwórz rysunek
55
utrzymywane funkcje C
45,380
porównania z oryginalnym kodem
33
funkcje z dopasowanymi skompilowanymi bajtami

Punkt kontrolny projektu: 7 października 2026 r. Progress ledger · Pokrycie testu

Dotychczasowy projekt

Odzyskany kod obejmuje obsługę tablic i zasobów, trafienia cegieł, animacje, cząstki i produkcję bonusów. Obecne Kompilacje zapewniają narzędzia inspekcyjne i bibliotekę analiz. Prace nad grywalną grą kontynuowane są z fizyką piłki i wiosła, obsługą zasilania i integracją Windows.

Znalezienie obliczenia lewej / prawej pozycji dźwięku

Po uderzeniu Cegły jej pozycja pozioma jest przekazywana do kodu dźwiękowego. Dochodzenie wymagało odzyskania, w jaki sposób ta współrzędna ekranu staje się wartością panoramowania w lewo/w prawo.

Twój agent kodowania

Użyj REA, aby dowiedzieć się, jak DX-Ball oblicza pozycjonowanie dźwięku stereo. Wyjaśnij obliczenia i pokaż kod.

Przykładowy monit dla agenta kodującego z dostępnym lokalnym plikiem wykonywalnym. Poniższe dochodzenie pokazuje zapytania REA i dowody stojące za odpowiedzią.

Agent użył REA do sprawdzenia funkcji, podążania za jej dzwoniącym z cegły i odczytywania stałych z pliku wykonywalnego. Wyniki te dostarczyły danych wejściowych i arytmetycznych potrzebnych do zapisania funkcji C poniżej.

Pierwszy wynik funkcji dla 0x406400 dołączono deklarowanie pseudokodu FUN_00406400(void) i dzwonienie __ftol(). Jego widok instrukcji pokazywał wejście stosu i operacje zmiennoprzecinkowe. Ta rozbieżność dała agentowi konkretny powód do dalszego dochodzenia.

Pierwszy widok dekompilatora
Wynik REA * fragment pseudokodu
longlong FUN_00406400(void)
{
  longlong lVar1;

  lVar1 = __ftol();
  return lVar1;
}

Wyjście pokazuje wywołanie konwersji. Czytanie poniższych instrukcji ujawnia wejście i podawanie obliczeń, które wywołanie.

Trzy pytania odpowiedział przez REA

  1. Odzyskaj brakujące dane wejściowe

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

    Wynik funkcji zawiera instrukcje obok pseudokodu i rozmówców. Tutaj, [EBP+8] ujawnia dane wejściowe całkowite brakujące w widoku dekompilatora.

  2. Postępuj zgodnie z rozmówcą, aby zrozumieć Dane wejściowe

    Agent → REA · analyze_function
    {"procedure": "0x411f40"}
    REA → agent * fragment dzwoniącego
    0x411f5b: ADD EAX, 0x14
    0x411f5e: PUSH EAX
    0x411f5f: CALL 0x00406400

    REA zidentyfikował tego rozmówcę w pierwszym wyniku. Jego poprzednia skala instrukcji tile_x przez 30; dodanie 20 daje współrzędną ekranu Cegły, 20 + 30 × tile_x.

  3. Przeczytaj wartości za adresami pamięci

    Agent → REA * dwa read_bytes wnioski
    {"address": "0x420068", "length": 16}
    {"address": "0x4210a0", "length": 8}
    Wyniki bajtów REA * dekodowane jako podwójne
    000000000000f93f → 1.5625
    0000000000407f40 → 500.0
    000000000000f03f → 1.0

    Zwracane bajty ustanawiają dwie stałe arytmetyczne i początkową skalę przesuwania. Agent ma teraz wartości potrzebne do wyrażenia C.

Od ustaleń REA do C

Wykonaj pięć poniższych kroków. Każdy wybór podkreśla oryginalne instrukcje i poinformowane przez nich linie C.

Oryginalny x86 * fragment
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
Zrekonstruowany 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 * odczytaj dane wejściowe. Widok instrukcji w wyniku funkcji REA odczytuje [EBP+8] i używa FILD aby załadować liczbę całkowitą. Po wywołaniu przez REA ustanawia znaczenie współrzędnych ekranu parametru C x.

Fragment zestawu wybiera instrukcje wejściowe, arytmetyczne i zwrotne. Pełna lista poniżej obejmuje również interwencyjne sklepy oraz konfigurację i czyszczenie funkcji.

Pełne zgromadzenie i dowody potwierdzające
Wynik REA * 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

Co dostarcza rozmówca

Funkcja brick-hit w 0x411f40 skaluje współrzędną płytki o 30, dodaje 20, a następnie popycha ją przed wywołaniem:

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

Co odczytują dane

Bajt REA odczytuje, dekoduje jako mało - endian podwaja
Adres Wartość Używany do
0x420068 1.5625 Pierwsze mnożenie
0x420070 500.0 Odejmowanie
0x4210a0 1.0 początkowo Przechowywana skala patelni

Nagrany z REA 4.1.0 Dla celu DX-Ball 1.07 przypiętego hash. Powiązane notatki z dochodzenia zachowują identyfikatory dowodów.

Utrzymane źródło · Notatki z dochodzenia i odniesienia do dowodów

Sprawdzanie odzyskanej funkcji

Odzyskana Funkcja Przechodzi dwa kontrole: jej wartości zwracane są zgodne z oryginałem, a skompilowane bajty są zgodne z plikiem wykonywalnym.

3205 przypadków zachowania

Testy wykonują oryginalną funkcję x86 i porównują jej wartość zwracaną z utrzymanym C. obejmują każdą pozycję całkowitą od 0 do 640 w pięciu skalach pan: 0, 0,5, 1, 20 i -1.

63 pasujące bajty

Funkcja C jest kompilowana z przypiętym łańcuchem narzędzi VC4.0. Powtórka kompilatora pasuje do pełnej funkcji po zastosowaniu sprawdzonych relokacji i sprawdzeniu przywoływanych stałych.

W skali 1 odzyskane obliczenia zwracają -500 na lewej krawędzi, 0 Na środku i 500 na prawej krawędzi. Kolejną częścią pracy audio jest integracja tej wartości z zapleczem dźwiękowym gry.

Przeczytaj szczegóły powtórki kompilatora

Kontynuuj dochodzenie

To samo podejście stosuje się w przypadku aktualizacji cząstek, kolejek wybuchowych i generowania premii: sprawdź odpowiednie funkcje, Odzyskaj ich stan i zależności, a następnie porównaj implementację z oryginałem.

Aby samodzielnie sprawdzić funkcję panoramowania dźwięku, postępuj zgodnie z instrukcjami konfiguracji projektu DX-Ball i podaj odpowiadający jej oryginalny cel. Następnie uruchom:

W kasie DX-Ball
scripts/rea function original/DXBALL.EXE 0x00406400 \
  --snapshot .analysis/rea/dxball.snapshot.json --json

Top