洞窟物語の改造

ゲーム改造の練習に洞窟物語を改造してみる。
とりあえずeXeScopeで開いてみると以下のようにデッバガセーブ/消音というメニューがあることが分かる。


この二つのメニューはゲームのプレイ時には表示されていない。Win32 APIを使って削除していると予測する。
次はデバッガの出番。
eXeScopeを閉じてImmunity Debuggerで洞窟物語を開く。
Ctrl+NでAPIの一覧を表示させ、メニューを削除するAPIはDeleteMenuかRemoveMenuしかないのでそれらを探す。
DeleteMenuが見つかった。


DeleteMenuの項目を右クリックし、Find references to importを選ぶ。
すると、以下のような画面が出る。


アドレス00412D58と00412D91が見つかるのでアドレス00412D58の項目をダブルクリックする。
出てきた周辺の逆アセンブルコードリストを眺めると以下のようになっている。

メニューを削除しないようにするには2つのDeteleMenu呼び出し箇所、00412D4D~00412D58、00412D86~00412D91を実行しないようにすればよい。
全てNOPで埋めるのが一番簡単だが書き換えバイト数も多くなり美しくない。
一つ目のDeleteMenuは最初の引数をPUSHしているところをDeteleMenu呼び出し後の場所にJMPするようにし、二つ目のDeleteMenuはアドレス00412D84がJNZ SHORT Doukutsu.00412D97となっていることに着目しこのJNZを強制ジャンプ、JMPに変更するとパッチも小さく済む。
最終的に変更箇所は以下のようになった。

; 一つ目
; 変更前
00412D4D  |. 6A 00          PUSH 0                                   ; /Flags = MF_BYCOMMAND|MF_ENABLED|MF_STRING
00412D4F  |. 68 459C0000    PUSH 9C45                                ; |ItemId = 9C45 (40005.)
00412D54  |. 8B55 FC        MOV EDX,DWORD PTR SS:[EBP-4]             ; |
00412D57  |. 52             PUSH EDX                                 ; |hMenu
00412D58  |. FF15 F0C14800  CALL DWORD PTR DS:[<&USER32.DeleteMenu>] ; \DeleteMenu
00412D5E  |. 8B45 08        MOV EAX,DWORD PTR SS:[EBP+8]
00412D61  |. 50             PUSH EAX                                 ; /hWnd
00412D62  |. FF15 F4C14800  CALL DWORD PTR DS:[<&USER32.DrawMenuBar>>; \DrawMenuBar

; 変更後
00412D4D     EB 0F          JMP SHORT Doukutsu.00412D5E
00412D4F  |. 68 459C0000    PUSH 9C45                                ; |ItemId = 9C45 (40005.)
00412D54  |. 8B55 FC        MOV EDX,DWORD PTR SS:[EBP-4]             ; |
00412D57  |. 52             PUSH EDX                                 ; |hMenu
00412D58  |. FF15 F0C14800  CALL DWORD PTR DS:[<&USER32.DeleteMenu>] ; \DeleteMenu
00412D5E  |. 8B45 08        MOV EAX,DWORD PTR SS:[EBP+8]
00412D61  |. 50             PUSH EAX                                 ; /hWnd
00412D62  |. FF15 F4C14800  CALL DWORD PTR DS:[<&USER32.DrawMenuBar>>; \DrawMenuBar


; 二つ目
; 変更前
00412D84  |. 75 11          JNZ SHORT Doukutsu.00412D97
00412D86  |. 6A 00          PUSH 0                                   ; /Flags = MF_BYCOMMAND|MF_ENABLED|MF_STRING
00412D88  |. 68 479C0000    PUSH 9C47                                ; |ItemId = 9C47 (40007.)
00412D8D  |. 8B55 F8        MOV EDX,DWORD PTR SS:[EBP-8]             ; |
00412D90  |. 52             PUSH EDX                                 ; |hMenu
00412D91  |. FF15 F0C14800  CALL DWORD PTR DS:[<&USER32.DeleteMenu>] ; \DeleteMenu
00412D97  |> 8B45 08        MOV EAX,DWORD PTR SS:[EBP+8]
00412D9A  |. 50             PUSH EAX                                 ; /hWnd
00412D9B  |. FF15 F4C14800  CALL DWORD PTR DS:[<&USER32.DrawMenuBar>>; \DrawMenuBar

; 変更後
00412D84     EB 11          JMP SHORT Doukutsu.00412D97
00412D86  |. 6A 00          PUSH 0                                   ; /Flags = MF_BYCOMMAND|MF_ENABLED|MF_STRING
00412D88  |. 68 479C0000    PUSH 9C47                                ; |ItemId = 9C47 (40007.)
00412D8D  |. 8B55 F8        MOV EDX,DWORD PTR SS:[EBP-8]             ; |
00412D90  |. 52             PUSH EDX                                 ; |hMenu
00412D91  |. FF15 F0C14800  CALL DWORD PTR DS:[<&USER32.DeleteMenu>] ; \DeleteMenu
00412D97  |> 8B45 08        MOV EAX,DWORD PTR SS:[EBP+8]
00412D9A  |. 50             PUSH EAX                                 ; /hWnd
00412D9B  |. FF15 F4C14800  CALL DWORD PTR DS:[<&USER32.DrawMenuBar>>; \DrawMenuBar

変更が終わったら右クリック->Copy to executable->All modificationsで現れるダイアログに対してCopy allを選ぶ。すると、ウィンドウが表示されるので右クリック->Save fileでファイルにセーブする。


セーブしたファイルを起動すると表示されていなかったメニューが表示されていることが確認できた。


パッチを作成すると以下のようになった。

*== TARGET_FILE ================
FILENAME Doukutsu.exe
* FileSize: 1478656 bytes
* LastMod.: 2005/06/12 16:07:12
*===============================
00012D4D: 6A EB
00012D4E: 00 0F
00012D84: 75 EB