- 55
- 個可維護的 C 函式
- 45,380
- 與原始程式碼的比較
- 33
- 個編譯後位元組匹配的函式
專案進度截至 2026 年 10 月 7 日。進度記錄 · 測試覆蓋情況
當前進度
目前已還原關卡與資源處理、磚塊碰撞、動畫、粒子和獎勵生成。當前構建提供檢查工具與分析庫。可玩的遊戲版本還在開發,後續工作包括球和擋板的物理邏輯、道具處理及 Windows 整合。
找出聲音的左右位置如何計算
磚塊被擊中時,它的橫座標會傳給聲音處理程式碼。這次調查要找出:螢幕座標如何轉換為聲音的左右聲像值?
用 REA 找出 DX-Ball 如何計算聲音的左右位置。解釋計算過程,並展示程式碼。
把本地可執行檔案交給程式設計助手,再使用這個示例 prompt。下面展示助手為回答問題發起的 REA 查詢,以及得到的證據。
助手用 REA 檢查函式、追蹤呼叫它的磚塊碰撞函式,再從可執行檔案中讀取常量。這些結果確定了輸入和計算步驟,才有了下面的 C 函式。
REA 最初返回的 0x406400 虛擬碼宣告瞭 FUN_00406400(void),並呼叫 __ftol()。但指令中還有來自棧的輸入和浮點運算。這個差異提示助手:還需要繼續查。
最初的反編譯結果
longlong FUN_00406400(void)
{
longlong lVar1;
lVar1 = __ftol();
return lVar1;
}
結果裡能看到一次轉換呼叫。繼續閱讀下面的指令,就能找出輸入,以及傳入這個呼叫前的計算。
用 REA 回答三個問題
-
找回缺失的輸入
程式設計助手→ REA ·analyze_function{"procedure": "0x406400"}REA →程式設計助手·指令摘錄0x406409: MOV EAX, dword ptr [EBP + 0x8] 0x40640c: MOV dword ptr [EBP + -0xc], EAX 0x40640f: FILD dword ptr [EBP + -0xc]函式結果同時提供虛擬碼、指令和呼叫方。這裡的
[EBP+8]顯示了反編譯結果中缺失的整數輸入。 -
追蹤呼叫方,理解輸入含義
程式設計助手→ REA ·analyze_function{"procedure": "0x411f40"}REA →程式設計助手·呼叫方摘錄0x411f5b: ADD EAX, 0x14 0x411f5e: PUSH EAX 0x411f5f: CALL 0x00406400REA 在第一次結果中就給出了這個呼叫方。呼叫前的指令將
tile_x乘以 30,再加上 20,得到磚塊的螢幕座標20 + 30 × tile_x。 -
讀取記憶體地址後面的值
助手 → REA · 兩次read_bytes請求{"address": "0x420068", "length": 16} {"address": "0x4210a0", "length": 8}REA 位元組結果 · 雙精度浮點數解碼000000000000f93f → 1.5625 0000000000407f40 → 500.0 000000000000f03f → 1.0返回的位元組確定了兩個運算常量,以及聲像縮放係數的初始值。助手由此得到編寫 C 表示式所需的數值。
從 REA 分析結果到 C 程式碼
下面分五步展示計算。點選每一步,原始指令和對應的 C 程式碼行會同時高亮。
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
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 · 讀取輸入。 REA 返回的指令讀取 [EBP+8],再透過 FILD 載入這個整數。用 REA 追蹤呼叫方,就能確定 C 引數 x 表示螢幕座標。
02 · 乘以 1.5625。 FMUL 讀取 0x420068 處的雙精度浮點數。REA 的 read_bytes 返回的位元組解碼後是 1.5625,C 程式碼使用相同常量。
03 · 減去 500.0。 FSUB 讀取 0x420070 處的雙精度浮點數。REA 返回的位元組解碼後是 500.0,讓計算的中心對應螢幕座標 320。
04 · 乘以儲存的縮放係數。 第二條 FMUL 讀取 0x4210a0。這個全域性變數在重建原始碼中名為 dxball_pan_scale。REA 的第二次位元組讀取確認它的初始值是 1.0。
05 · 返回整數。 0x406430 處的呼叫進入 __ftol,REA 返回的被呼叫函式資訊確認了這一點。C 程式碼把結果轉換為 DxBallInt,再與原始 x86 函式比較,驗證返回值。
這段彙編節選包含輸入、運算和返回指令。下面的完整列表還保留了中間的儲存操作,以及函式開頭和結尾的處理。
完整彙編與相關證據
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
呼叫方傳入什麼
0x411f40 處的磚塊碰撞函式把格子座標乘以 30,再加上 20,然後在呼叫前將結果壓棧:
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
讀取資料確認了什麼
| 地址 | 數值 | 用於 |
|---|---|---|
0x420068 |
1.5625 |
第一次乘法 |
0x420070 |
500.0 |
減法 |
0x4210a0 |
1.0 最初 |
儲存的聲像縮放係數 |
使用 REA 4.1.0 記錄,分析目標為透過雜湊確定的 DX-Ball 1.07 檔案。連結的調查筆記保留了 Evidence ID。
驗證還原的函式
還原的函式透過了兩項檢查:返回值與原版一致,編譯後的位元組與原始可執行檔案一致。
3,205 個行為測試用例
測試執行原始 x86 函式,將返回值與重建的 C 函式比較。測試覆蓋 0 到 640 的所有整數位置,並分別使用五個聲像縮放係數:0、0.5、1、20 和 −1。
63 位元組完全匹配
C 函式使用指定的 VC4.0 工具鏈編譯。應用經過檢查的重定位,並核對引用的常量後,編譯結果與原始函式的全部位元組一致。
縮放係數為 1 時,計算在螢幕左邊緣返回 −500,中心返回 0,右邊緣返回 500。接下來要將這個值接入遊戲的聲音後端。
繼續調查
粒子更新、爆炸佇列和獎勵生成也使用同樣的方法:檢查相關函式,還原狀態與依賴,再把實現和原版比較。
如果你也想分析這個聲像函式,先按 DX-Ball 專案的說明配置環境,並準備匹配的原始檔案。然後執行:
scripts/rea function original/DXBALL.EXE 0x00406400 \
--snapshot .analysis/rea/dxball.snapshot.json --json
- DX-Ball 儲存庫當前原始碼、進度和本地配置。
- REA 分析流程追蹤這段計算,再用同樣方法分析自己的二進位制檔案。
- 粒子與獎勵生成進一步分析狀態、佇列和畫素寫入。