LGT 던전앤파이터 귀검사편 逆向筆記
逆向工具
- ChatGPT 5.5
- IDA MCP
- IDA Pro 9.1
- Wie Emulator
逆向檔案
- 0002E1A1.jar/binary.mod
逆向目標
- Sera Shop(세라샵)內的線上商品可隨意購買。
- 完全跳過開幕的網路校驗,無需做無意義的等待。
修補準則
- 基於原遊戲語義。
- 維持
binary.mod的原始大小,不擴展.text,不移動 ELF section。
切入點
Sera Shop 字串
세라샵:商店入口구입하시겠습니까:購買確認訊息구입하였습니다:購買成功訊息,訊息 ID10006인벤공간이 부족합니다:背包空間不足현금、정보이용료、통화료별도:運營商計費 KEY
通過定位這些關鍵字串,範圍可被限定到 商店 UI、訊息渲染、購買確認和伺服器成功處理 附近。
Sera Shop 事件狀態
KEY 全局變數:
| Address | Meaning |
|---|---|
0x0150c464 |
當前 UI/state 描述 |
0x0150c520 |
當前確認面板選項 |
0x0150b268 |
事件槽數組,每槽 0x14 Byte |
0x0150c484/0x0150c485 |
排程可見的當前事件 |
0x0150b0b8 |
Sera 當前商品類型和索引 |
0x0150c446 |
當前選中的商品和索引 |
KEY State:
| State | Meaning |
|---|---|
0x27 |
普通購買詳情/確認面板 |
0x12 |
數量類購買流程 |
0x28 |
等級/數量選擇面板 |
0x2a |
原運營商確認計費面板 |
開幕網路驗證狀態
開幕驗證的關鍵為『初次啟動狀態機』:
0x0150000c:啟動認證計數/完成標記。handleCommand(7000):初次認證入口,原鏈路會進入0x63 -> 0x64 -> 0x65。handleCommand(2000):並行網路等待入口,原鏈路會進入0x6d/0x6e。setGameState:啟動後進入 標題/認證/遊戲狀態 的核心狀態切換。0x62ae0:標題階段渲染分流,錯誤狀態會進入未初始化完整場景渲染。
逆向定位路徑
1. 定位『購買成功』的路徑
使用遊戲原本的鏈路完成購買:
1 | 0x1efc4: Sera success processor |
最終本地物品發放鏈路為:
1 | 0x1e604 |
2. 繞過無效伺服器購買校驗
| Address | Final behavior |
|---|---|
0x1e582 |
0x4b 『直接確認類』商品進入 0x1e604 |
0x1e66e |
非 0x4b 『直接確認類』商品進入 0x1e604 |
0x1de38 |
『數量選擇類』商品確認之後進入 0x1e604 |
0x1e3ba |
state=0x2a 兜底進入 0x1e604 |
0x1e39a |
SKIP f670/f5b0 舊計費檢查,進入 0x1e604 |
NOTE: 『直接確認類』商品不一定是 type == 0x4b,只修 0x4b 會使 裝備 和 1800s 類商品在規則之外。
3. 修正『背包已滿』的誤判
進入 0x81329 前的背包計數元資料不可信,因此:
1 | 0x1e604 |
0x81329 的滿包判斷只以物理 90 格為最終邊界:
0x813500x8140e
這樣既避免空包誤判,也不允許越界寫背包陣列。
4. 返回/取消必須恢復事件棧
返回的正確語意是彈出目前確認事件,並恢復上一層商店事件。
原函式 0x10014(index) 的語義正確:
1 | clear 0x0150b268 + index * 0x14 |
不安全之處,則在於原函式內部透過間接的 native/memset 清除事件槽;在 WIE 執行路徑中,會觸發 undefined instruction。
最終的修法是改寫 0x10014 本體:
- 以 5 次直接
str將 20 Byte 的事件槽清零。 - 保留後半段恢復前一事件的邏輯。
5. 等級商品必須阻止舊計費視窗的建立
在舊的偵錯過程中,曾嘗試在 state=0x2a 內部跳過計費檢查,但實際測試中仍會出現「購買成功,但彈窗下方又再次生成商品彈窗」的問題。
原因在於補丁位置太晚:0x2a 視窗已由父狀態建立。
正確的建立點在 state=0x28:
1 | 0x1df4a..0x1dfae: 寫入商品類型、索引、等級/數量 |
最終修法:
1 | 0x1dfb0: b 0x1e3ee |
6. 開幕驗證必須保留初始化,只替換狀態目標
失敗的偵錯方向:
- 直接跳過首次啟動分支:會跳過必要初始化,導致進入錯誤的 UI。
- 只隱藏
0x63/0x6e視窗:輸入仍停留在認證/網路狀態,標題畫面按鍵無效。 - caller-side no-op
handleCommand(7000/2000):會留下不一致狀態,導致渲染或輸入崩潰。 - 在補丁 stub/新堆疊框架中呼叫
0x6ccc:此方向錯誤。0x6ccc是0x5cf0大函式的共享 epilogue,並非一般函式。
最終策略:
保留首次啟動初始化,並將首次啟動後的狀態改為非首次的標題狀態:
1 | 0x5dda: bl 0x6ea61 |
這裡保留反組譯看到的 bl 0x6ccc,但不能將它理解為一般函式呼叫。0x5df4 位於 0x5cf0 這個大函式內部,執行到此處時,當前堆疊框架正是 0x6ccc epilogue 預期要彈出的那個框架。
先前失敗的是在補丁 stub 內另起一個呼叫框架後再 bl 0x6ccc。這會讓 0x6ccc 從錯誤的堆疊位置 pop 返回地址,最終跳到無效地址。因此『不可作為一般函式呼叫』是指不可從外部 stub/新堆疊框架 呼叫它,而非要改掉原始 0x5df4 這條控制流。
並保留兩處配套修正:
1 | 0x1c66e: b 0x1c684 ; [0x0150000c] == 2 時跳過 handleCommand(2000) |
關鍵結論
0x1efc4是 Sera Shop 本地成功處理的正確抽象。0x12c4c並非通用的購買發放函式,不可傳入 Sera 商品索引。- 直接確認商品不等於
type == 0x4b。 - 背包容量須以物理 90 格陣列為最終邊界。
- 返回/取消是事件堆疊恢復問題,而非 UI 跳轉問題。
- 等級商品的問題在於
state=0x28建立state=0x2a的時機,而非state=0x2a內部。 - 開幕驗證不能只遮蔽視窗,必須讓狀態機進入原版非首次的標題狀態。
0x6ccc是0x5cf0的共享 epilogue,只能沿原函式內控制流抵達;不可從補丁 stub 當一般函式呼叫。- WIPI/Thumb-1 補丁填充必須使用
c046,不可引入 Thumb-2 的00bf。 - 維持相同大小的原地補丁,是 WIPI ELF 最穩健的交付方式。
補丁思路
正確的補丁點應位於狀態機已準備好資料、但即將進入已失效線上流程之前。
購買鏈路:
1 | 繞過已失效的線上檢查 |
啟動鏈路:
1 | 保留首次啟動初始化 |
實驗性:音頻 Hack
因韓國手機的硬體限制,多數遊戲至多同時播放一個音軌。
這很煩人,因為音樂頻頻被音效打斷的感覺並不好。
不過既然現在有模擬器,那為何不作 Patch 呢?
修補的思路如下:
.text追加0xd4Byte 声音 stub。.bss擴大到0x3b100,用於新增音樂 handle0x0153b000。0x6c722:bl 0x6c428改為bl 0x9d350。
OK,大概就這樣了,畢竟我對二進位逆向實在不太在行。
這次仰仗 ChatGPT 和 IDA 的犀利,才能順利完成這項工作。
不知日後的漢化會遇見何種糟糕的問題呢?
現在已經實現了初步的成果,但從 1 到 100,從來不是一件容易的事情。
小敘
本不打算寫這篇總結,畢竟假以外物,通篇皆為『之乎者也』,令人不知所云。
整個逆向過程相當之無趣:靜態分析 → 偵錯 → 靜態分析 → 偵錯…… 機械到令人髮指。
作為一個二進位逆向的菜鳥,沒有比逆向過程不受自我掌控更可怕的事情……
不過我更擔憂的是,玩家手裡,只有一個成品;而 AI 最終產出的方法論,淪為『黑箱』。
如果後人想要復現,該如何開始?
這便是本 POST 整理兼發佈的目的。

