這次以SAGA PLANET做的一個小遊戲為分析對象,遊戲可以免費下載:
【はつゆきパズル☆神経衰弱☆】
下載下來的是一個壓縮檔,檔名為 hatsukipuzzle01.zip,直接解壓縮會得到一個資料夾,
名字為: はつゆきパズル
其實遊戲必要的只有 はつゆきパズル\StartData\GameData 這個資料夾,直接把GameData資料夾搬到隨便一個地方,執行SiglusEngine.exe即可啟動遊戲。
可惜事情沒這麼簡單,直接執行SiglusEngine.exe,會出現這個視窗:
圖一 |
於是我使用OllyDbg啟動遊戲進行調試,思路很簡單,就是直接對MessageBox函式下斷,
然後重新啟動程式,按F9繼續執行就會停在這裡:
0045DCCF |. 8D4424 50 LEA EAX,[ESP+50]
0045DCD3 |> 6A 30 PUSH 30
0045DCD5 |. 51 PUSH ECX
0045DCD6 |. 50 PUSH EAX
0045DCD7 |. A1 BCF3B304 MOV EAX,DWORD PTR DS:[4B3F3BC]
0045DCDC |. 50 PUSH EAX
0045DCDD |. FF15 B0D47700 CALL DWORD PTR DS:[<&USER32.MessageBoxW>] ;彈出錯誤訊息
接著我就往上查找,看看有沒有繞過這一段指令的跳轉,很幸運的只有找到一處:
0045DC5A |. E8 81F9FFFF CALL 0045D5E0
0045DC5F |. 84C0 TEST AL,AL
0045DC61 |. 0F85 A9000000 JNZ 0045DD10 ;關鍵跳轉
這裡邏輯很簡單,只要 call 0x0045D5E0返回值不為零就跳走,若為零則繼續執行並印出錯誤訊息。既然這樣修改的方式也很簡單,直接把 JNZ 改為 JMP 即可,這樣不管返回值為何都會跳走。
於是我們修改指令,並把修改保存到執行檔,之後再直接啟動程式,結果如下:
圖二 |
這次我們先在上次找到的關鍵跳轉下斷,之後一步一步跟蹤看看問題出在哪裡。
依照經驗,通常這些檢查都會在鄰近的地方。
剛才的關鍵跳轉(已修改):
0045DC5A |. E8 81F9FFFF CALL 0045D5E0
0045DC5F 84C0 TEST AL,AL
0045DC61 E9 AA000000 JMP 0045DD10 ;第一個關鍵跳轉
0045DC66 90 NOP
跳轉目的:
0045DD10 |> E8 8BFCFFFF CALL 0045D9A0 ;跳到這裡,第一個關鍵跳轉目的
0045DD15 |. 84C0 TEST AL,AL
0045DD17 0F85 E9000000 JNZ 0045DE06 ;第二個關鍵跳轉
很眼熟不是嗎? 我們先不要修改繼續按 F8 跟蹤,結果程式在這裡停了下來,
跳出了圖二的錯誤訊息:
0045DD9B |. 6A 30 PUSH 30 ; /Arg1 = 30
0045DD9D |. 8BC6 MOV EAX,ESI ; |
0045DD9F |. 8D4C24 34 LEA ECX,[ESP+34] ; |
0045DDA3 |. E8 78FA1000 CALL 0056D820 ; \SiglusEngine.0056D820 ;這裡!!
也就是說 SiglusEngine.0056D820 裡面呼叫了MessageBox。
我們回到剛剛的 JNZ 發現他剛好有可能跳過呼叫 SiglusEngine.0056D820 的這段程式碼,
也就是說這個 JNZ 也是一個關鍵跳轉。
我們同樣改為 JMP,然後保存修改,直接執行程式,又出現一個:
圖三 |
一樣,我們先對圖二的那個關鍵跳轉下斷,然後按F8跟蹤,馬上又找到一個地方:
0045DE06 |> E8 E5FCFFFF CALL 0045DAF0 ;第二個關鍵跳轉目的
0045DE0B |. 84C0 TEST AL,AL
0045DE0D |. 0F85 DE000000 JNZ 0045DEF1 ;第三個關鍵跳轉
修改方式一模一樣,這裡不再贅述。為防萬一,我繼續往下找是否還有類似的地方,
結果在第三個關鍵跳轉後,這個函式很快的就返回了,看來應該是沒有類似的檢查了。
保存修改後直接執行:
成功!!
整理一下結果可以發現整個地區檢查的邏輯是這樣(C虛擬碼):
void check_location() {
if(!is_japanese_system()) {
...
MessageBox();
...
}
if(!is_japanese_system_language()) {
...
MessageBox();
...
}
if(!is_japan_time_zone()) {
...
MessageBox();
...
}
}
從這裡可以看出來 SiglusEngine 時做了三種檢查地區的方法,之後再來一一分析好了,
目標就是把這三種方法寫成像這樣的函式:
bool is_japanese_system();
bool is_japanese_system_language();
bool is_japan_time_zone();
以上~
留言
張貼留言