如何測試與除錯 DLL
本篇定位
這是 Phase 8「整合測試與發布」的第一篇。 DLL 開發的除錯比一般應用程式複雜:你不能直接執行 DLL,崩潰訊息也不像 EXE 那樣直接。這篇整理從開發到穩定運行的完整測試流程。
一、測試環境建立
1.1 獨立測試資料夾
永遠在一個和正式遊戲目錄分開的測試資料夾裡測試:
C:\MapleTest\ ← 測試環境(只放這裡)
├── MapleStory.exe ← 遊戲執行檔的副本
├── dinput8.dll ← 剛編譯的登入器 DLL
├── dinput8.ini ← 設定檔(Debug 選項開啟)
└── *.wz ← WZ 資源檔案
C:\MapleStory\ ← 正式遊戲目錄(不碰)
不要直接在正式遊戲目錄測試
崩潰的 DLL 可能損壞遊戲設定,或者讓正式帳號資料出問題。測試環境和正式環境完全分開。
1.2 設定檔開啟 Debug 模式
[Debug]
ShowConsole = true ; 開啟控制台視窗,看即時日誌
VerboseLog = true ; 顯示每個 Hook 的安裝訊息開啟後,遊戲啟動時會出現一個 cmd 視窗,顯示:
[MainMain] Waiting for Themida depack...
[MainMain] Themida depack complete.
[Config] Server: 127.0.0.1:8484
[Config] Resolution: 1280x720
[Hook] Hook_CreateMutexA installed
[Hook] Hook_WSPStartup installed
...
[Client] Resolution set to 1280x720
二、常見崩潰原因與排查方式
2.1 遊戲立刻崩潰(DLL 載入時)
症狀:點擊 MapleStory.exe,視窗閃一下就消失,或直接沒有反應。
原因排查:
| 可能原因 | 排查方式 |
|---|---|
| Hook 安裝了錯誤的地址 | 用 x64dbg 附加,查看崩潰時的 EIP 和 Call Stack |
| DLL 本身有編譯錯誤 | 確認是 Release x86 編譯,不是 Debug 或 x64 |
dinput8.dll 找不到系統 DLL | 控制台日誌是否有 Failed to load original dinput8.dll |
| 使用了錯誤版本的 EXE | 確認 EXE 的 MD5 與登入器支援的版本一致 |
2.2 遊戲卡在載入畫面
症狀:黑色視窗出現但沒有進展,或者 Nexon 啟動畫面卡住。
最常見原因:WaitForThemida() 等待條件永遠不成立(特徵 byte 沒有變成 0x55)。
// 在 WaitForThemida 加入計時器,超時後輸出診斷
while (*(BYTE*)CHECK_ADDR != 0x55) {
Sleep(100);
elapsed += 100;
if (elapsed > 10000) { // 10 秒
std::cout << "[Error] Themida wait timeout. "
<< "Current byte at " << std::hex << CHECK_ADDR
<< ": 0x" << (int)*(BYTE*)CHECK_ADDR << std::endl;
break;
}
}2.3 遊戲崩潰在特定操作後
症狀:能進入遊戲,但在登入 / 選角 / 進入地圖時崩潰。
排查:用 x64dbg 在崩潰時查看 Call Stack,找到第一個屬於我們 DLL 的函式。
三、主要除錯工具
3.1 x64dbg / OllyDbg:動態除錯
用途:在遊戲執行時設定斷點、查看暫存器、追蹤崩潰原因
步驟:
1. 開啟 x64dbg(選 x32 版本,因為 v83 是 32 位元)
2. File → Open → 選 MapleStory.exe
3. Debug → Run(讓遊戲啟動,DLL 會自動載入)
4. 崩潰時 x64dbg 會自動暫停,顯示崩潰位置和 Call Stack
如何附加到已執行的遊戲
如果遊戲已經在跑,可以用
File → Attach選擇 MapleStory.exe 的進程 ID。但注意附加後 Themida 可能偵測到偵錯器並讓遊戲崩潰。用ScyllaHide外掛可以隱藏偵錯器的存在。
3.2 Cheat Engine:記憶體驗證
用途:確認我們寫入的值是否正確到達目標地址
步驟:
1. 附加到 MapleStory.exe
2. 搜尋特定地址(如 GameWidth_Addr = 0x00C4FCA4)
3. 查看該地址的值是否已被改為我們設定的解析度寬度
3.3 Process Monitor(Procmon):檔案系統追蹤
用途:確認 dinput8.ini 是否被正確讀取,追蹤 WZ 檔案載入順序
步驟:
1. 開啟 Procmon
2. 設定 Filter:Process Name is MapleStory.exe
3. 啟動遊戲,觀察檔案讀取事件
3.4 Console 日誌(最快速的除錯手段)
在關鍵位置加入 std::cout 輸出,確認執行到哪一步:
void Client::UpdateResolution() {
std::cout << "[Client] Starting UpdateResolution..." << std::endl;
Memory::Write<int>(addys::GameWidth_Addr, m_nGameWidth);
std::cout << "[Client] GameWidth written: " << m_nGameWidth << std::endl;
// ... 每個步驟都輸出確認
std::cout << "[Client] UpdateResolution complete." << std::endl;
}四、測試清單(Checklist)
每次修改 DLL 後,依序確認:
基礎功能
□ DLL 成功載入(控制台出現 "Themida depack complete")
□ 遊戲視窗以正確解析度出現
□ 連線到私服而非官方伺服器(查看私服伺服器端的連線日誌)
登入流程
□ 登入畫面 UI 元素位置正確(帳號輸入框置中)
□ 帳號密碼輸入正常
□ 登入按鈕可以點擊
選角流程
□ 角色名稱和等級顯示正確
□ 角色位置平均分布
□ 「開始遊戲」按鈕正常
遊戲內
□ HUD 元素(血條、魔力條、小地圖)位置正確
□ 聊天視窗顯示正常
□ 角色可以正常移動、攻擊
□ NPC 對話視窗顯示正常
穩定性
□ 遊戲運行 10 分鐘無崩潰
□ 換地圖 3 次無崩潰
□ 開啟背包、裝備視窗無崩潰
五、Access Violation 的診斷思路
最常見的崩潰是 Access Violation(0xC0000005),表示程式嘗試存取不存在或沒有權限的記憶體。
崩潰訊息:Access violation at 0x009F5239
診斷步驟:
1. 確認 0x009F5239 是有效地址(在 EXE 的 .text section 範圍內)
2. 如果是在 Hook 安裝後立刻崩潰:
→ 可能是 JMP 目標地址計算錯誤(相對偏移算錯)
3. 如果是在呼叫 Trampoline 時崩潰:
→ 可能是被覆蓋的原始指令沒有完整複製(截斷了多 byte 指令)
4. 如果是在普通 Memory::Write 後崩潰:
→ 確認目標地址在記憶體中確實存在且已解壓縮
延伸閱讀
- 02_打包發布與使用教學 — 下一篇:測試通過後如何打包和發布
- 02_Memory.cpp_讀寫記憶體工具 — WriteProtected 的 VirtualProtect 原理
- 03_MainMain.cpp_初始化流程解析 — ShowConsole 控制台的開啟方式