既補のプログラムの機胜を拡匵する

゜フトりェアの䞖界では、開発者によっお忘れられた膚倧な数のプログラムがありたす。 すでに優れた代替手段がある堎合は良いこずです。 そしお圌女がそうでない堎合は 䞀郚の些现なこずはプログラムでひどく芋萜ずされる可胜性があり、いく぀かの迷惑な゚ラヌは䜕幎もの間ナヌザヌに倚倧な䞍䟿をもたらす可胜性があり、プログラムはOSの新しいバヌゞョンで動䜜するこずさえ拒吊するかもしれたせん。 ゜ヌスコヌドは、プログラムをクリヌンアップするために垞に利甚できるものではありたせん。 プログラムが単玔であれば、短時間で代替を䜜成するこずは難しくありたせん。 しかし、プログラムが倧きく耇雑な堎合、この堎合はどうすればよいでしょうか 合理的なフレヌムワヌク内で機胜を拡匵し、完成した実行可胜ファむルに既にある゚ラヌのほずんどを修正できるため、時間ずお金をかけお完党なアナログを開発するこずは必ずしも合理的ではありたせん。

この蚘事では、䌝説的なゲヌムAge of Empires II リアルタむム戊略の機胜を拡匵する䟋ずしお、実行可胜ファむルを倉曎する方法を瀺したす。



だから私たちは䜕を持っおいたす





おそらく、ラむセンス契玄の犁止を芋るこずなく、䜕かを倉曎しようずするこずができたす。 そう思いたせんか :)



免責事項



この䜜業は教育目的のみで行われたものであり、適甚法の違反を求めるものではありたせん。 著者は、提出された資料の違法䜿甚に぀いお䞀切の責任を負いたせん。



「患者」に関する情報



調査䞭のゲヌムは、1997幎から2000幎にEnsemble Studiosによっお開発されたGenie゚ンゞンで䜜成されたした。 この期間䞭、Age of Empiresシリヌズの4぀のゲヌムがこの゚ンゞンでリリヌスされたした。 さらに、GenieはLucasArtsによっおラむセンスされおおり、2001-2002幎にこの゚ンゞンで2぀のゲヌムをリリヌスしたしたが、スタヌりォヌズシリヌズのものです。 この時点で、゚ンゞンは256色モヌドで動䜜しおいたため、すでに非垞に叀くなっおいたした。これは2000幎のゲヌムず比べおも非垞に控えめです。 そのため、゚ンゞンの改良が停止され、それに基づいた新しいゲヌムはリリヌスされたせんでした。

Genieゲヌム゚ンゞンは、すべおのゲヌムグラフィックス、音楜、そしお最も重芁なもの-ナニットのリストずその特性-を倖郚ファむルからダりンロヌドしたす。 ぀たり、ほずんどの郚分でこの゚ンゞンに基づくすべおのゲヌムには非垞に類䌌した実行可胜ファむルがあり、1぀のゲヌムのほずんどすべおの倉曎は問題なく他のゲヌムに簡単に移怍できたす。



䜕を達成したいですか



1. CDチェックを無効にしたす
最近のラップトップネットブックなどでは、組み蟌みのCDドラむブがなくおも珍しくありたせん。 さらに、ゲヌムは非垞に叀いため、元のCDの読み取りが停止し、誰かが倱うこずさえありたす。 その結果、完党に合法的なゲヌムのコピヌの所有者は、ゲヌムを実行する胜力を倱いたす。 したがっお、おそらく、ディスクなしでゲヌムを実行しおください。



2.りィンドりモヌドサポヌトを远加する
Age of Empiresは、800×600、1024×768、および1280×1024の3぀の固定解像床をサポヌトしおいたす。 このような解像床では、ワむドスクリヌンモニタヌの画像が匕き䌞ばされお芋えるため、䞍快感が生じたす。 ゲヌムに新しい暩限のサポヌトを远加できたすが、ゲヌムは解像床ごずに独自のむンタヌフェむスグラフィックを䜿甚するため、それをそのたたにしお、今のずころゲヌムにりィンドりモヌドを远加するこずに制限しおみたしょう。



3.構成ファむルのサポヌトを远加したす
ある皮のシステムゲヌムオプションを有効にするには、プログラムが起動するたびにコマンドラむンから送信する必芁がありたす。 すべおのパラメヌタヌをショヌトカットに入れるこずができたすが、ゲヌムを別のディレクトリに移動するず、ショヌトカットは機胜しなくなりたす。 解決策は、構成ファむルのサポヌトを远加するこずです。



4.ゲヌムをポヌタブルにする
ゲヌムはポヌタブルではありたせん。 別のコンピュヌタヌで実行するには、ゲヌムファむルをコピヌするだけでは䞍十分です。ゲヌムのむンストヌルプロセス党䜓を実行する必芁がありたす。 倖付けドラむブの広範な配垃に関連しお、このプロパティをゲヌムに付䞎したいず思いたす。



5.既知の゚ラヌを修正
ゲヌムのむンタヌフェヌスに䞍快な゚ラヌがありたす。 たずえば、IPゲヌムに接続するためのダむアログでは、以前に入力したアドレスは最近のゲヌムのリストで切り捚おられたす。これにより、クむック接続機胜党䜓の利䟿性がれロになり、毎回サヌバヌアドレスを手動で入力する必芁がありたす。



これには䜕が必芁ですか



IDA Proは、リバヌス゚ンゞニアリングに広く䜿甚されおいるむンタラクティブな逆アセンブラヌおよびデバッガヌです。 初心者でも理解できるフロヌチャヌトを䜜成できたす。 すべおの圌の匷みは、ナヌザヌずのむンタラクティブな盞互䜜甚に衚れおいたす。 自動分析埌、ナヌザヌは関数や倉数に意味のある名前を付けたり、コヌドにコメントを付けたりできたす。 x86アセンブリ蚀語を少し理解すれば、すぐにプログラムの調査を開始できたす。



Flat Assemblerは、フリヌりェアのマルチパスアセンブラです。 FASMはサむズが小さく、コンパむル速床が非垞に速く、倚くのルヌチンタスクを自動化できる豊富で倧容量のマクロ構文を備えおいたす。 䟿利な機胜の1぀は、ヘッダヌなどのない玔粋なマシンコヌドの生成です。 これらはすべお、アセンブラヌむンサヌトの生成に圹立ちたす。



Hexplorerは無料のHEX゚ディタヌです。 シンプルなx86逆アセンブラヌを備えおいるため、実行可胜ファむル内を簡単にナビゲヌトできたす。 サむズを倉曎せずにバむナリファむルを手動で倉曎するために盎接䜿甚されたす。



それでは始めたしょう。



CDチェックを無効にする



CDが利甚可胜かどうかを確認するコヌドを芋぀けおください。IDAがお手䌝いしたす。 それは非垞にシンプルであるこずが刀明したした。 4485A0hベヌスアドレス400000h、぀たり物理的にファむル内にあり、マシンコヌドは485A0hにあるでCD存圚チェック機胜を芋぀けるず、ドラむブに関する情報を取埗するために䜿甚されるGetDriveTypeAおよびGetVolumeInformationA関数の呌び出しをトレヌスするだけで十分です。 eaxナニット。

  checkcd proc near
     sub esp、214h
     ebxをプッシュ
    プッシュESI
     ;  ...
     ; 倚くのチェック
     ;  ...
    テストeax、eax
     jz cd_check_fail
 cd_check_ok
    ポップ゚ス
     mov al、1
    ポップEBX
     ESP、214hを远加
     retn 4
 cd_check_fail
    ポップ゚ス
    ポップEBX
     ESP、214hを远加
     retn 4
 checkcd endp
この関数は、ゲヌムがむンストヌルされたディスクの文字が保存されおいるレゞストリにCDPathの倀を芁求するこずに泚意しおください。 ぀たり、ゲヌムはむンストヌル元のドラむブの文字にのみ関連付けられおおり、元のドラむブが他のドラむブにある堎合、ゲヌムはただ開始されたせん。 この堎合の最も簡単な解決策は、2バむトのnop操䜜で2バむトかかるjz cd_check_failコマンドを眮き換えるこずです。これにより、ディスクをチェックした埌、ナニットは垞にeaxに戻りたす。 ただし、レゞストリにCDPath倀が存圚しない堎合、関数はすぐに0を返すように蚭蚈されおいるため、プログラムの移怍性が劚げられたす。 したがっお、関数党䜓を3぀の単玔なコマンドに眮き換えたす。

  use32
     xor eax、eax
     Inc eax
     retn 4 
これらのコマンドのマシンコヌドを取埗するには、FASMが圹立ちたす。

  fasm src.asm dst.bin 
このアセンブラの䞻な利点は、ヘッダヌなしでクリヌンなマシンコヌドを生成できるこずです。 取埗したすコマンドごずの行

  31 C0
 40
 C2 04 00
぀たり、これらの6バむトをCDの存圚を刀断するための関数の先頭に眮き、残りのコマンドをnopコヌド90hに眮き換える必芁がありたす。

゜ヌスマシンコヌド 受信したマシンコヌド
  8B 44 24 04 81 EC 14 02
 00 00 85 C0 53 56 8B D9
 ... 
  33 C0 40 C2 04 00 90 90
 90 90 90 90 90 90 90 90 90
 ... 
通垞のHEX゚ディタヌでは、オフセット485A0hで始たる䞊蚘のマシンコヌドを眮き換えたす。その埌、レゞストリに必芁なキヌがない堎合でも、ゲヌムでCDを実行する必芁はありたせん。 同時に、远加のマシンコヌド甚に288バむトをリリヌスしたした。これは、将来的に圹立぀でしょう。



バグ修正



IPネットワヌクゲヌムに接続するず、ゲヌムには、IPのリストず、プレヌダヌが以前に接続したゲヌムの名前が衚瀺されたす。 ただし、䜕らかの理由で、IPアドレスが完党に保存されないこずが倚く、最埌の文字のいく぀かが切り捚おられたした。 問題を理解し、゚ラヌを修正する必芁がありたす。

最新のゲヌムのIPアドレスをレゞストリに保存するコヌドを怜玢したす。 このゲヌムでは、RecentGameNamedおよびRecentGameAddrdずいう圢匏の名前を持぀キヌに最近のIPゲヌムのリストが保存されるこずがわかっおいたす。 IDAを䜿甚するず、これらの行ぞの3぀のリンクが芋぀かりたす。 目的のコヌドがどこにあるかを刀断するのは非垞に簡単です-オフセット0512116hのコヌドでは、これらのキヌが蚘録され、他の堎合は読み取りたす。 発芋されたマシンコヌドの郚分は瀺したせん-箄50の呜什があり、その䞀般的な意味は小さなCコヌドずしお衚すこずができたす。

  forint i = 0; i <count; i ++
 {
	 char *キヌ名;
	 sprintfキヌ名、「RecentGameNamed」、i;
	 RegSetVal1、キヌ名、ゲヌム名[i]、strlenゲヌム名[i];
	 sprintfキヌ名、「RecentGameAddrd」、i;
	 RegSetVal1、キヌ名、gameaddr [i]、strlengamename [i];
 } 
レゞストリに倀を蚭定するために、ゲヌムは独自のラッパヌ関数RegSetValint、char * ValueName、char * Data、int DataSizeを䜿甚したす-関数ずパラメヌタヌの名前はもちろん発明されたもので、マシンコヌドにはありたせん。 ご芧のずおり、ゲヌムはレゞストリにネットワヌクゲヌムの名前ず同じ数のIPアドレスの文字を保存したす。 どうやら、プログラマはアドレスを保存するためにゲヌムの名前を保存するために2行をコピヌしたしたが、strlen呌び出しで配列の名前を修正するのを忘れおいたした。

゚ラヌを修正するには、2぀のオプションがありたす。正しい文字列をstrlenに眮き換えるか、strlenの代わりに定数16を配眮したすアドレス行の最倧長、たずえば「255.255.255.255」。

strlengamename [i]の呌び出しは、マシンコヌドではどのように芋えたすか

  _sprintfを呌び出したす。  + 0x1022CF
 mov edi、ebp
たたはecx、0FFFFFFFFh
 xor eax、eax
 ESP、0Chを远加
 Repne scasb
 ecxではない
プッシュecx 
コンパむラヌはコヌドを最適化し、strlen関数呌び出しを所定の長さの蚈算に眮き換えたした。 前のstrlenの呌び出しでは、同じ行が䜿甚されたしたが、ここでも最適化-最初の呌び出し時にポむンタヌがebpに配眮されたす。 ぀たり、ebpに正しいポむンタヌを眮くための貎重なバむトのペアがありたせん。 もちろん、jmpを関数の制限の範囲倖にしおから元に戻すこずもできたすが、これは最も矎しい方法ではありたせん。 したがっお、最も単玔なバヌゞョンの゚ラヌ修正に぀いお説明したす。垞に16バむトのアドレスを保存したす。 これを行うには、䞊蚘のマシンコヌドを次のコヌドに眮き換えたす。

アセンブリコヌド 機械コヌド
  _sprintfを呌び出したす。  + 0x1022CF
 ESP、0Chを远加
 mov ecx、0Fh 
  E8 CF 22 10 00
 83 C4 0C
 B9 0F 00 00 00 


構成ファむルのサポヌト



ゲヌムは、起動するたびに転送しないようにファむルのどこかに保存するのに䟿利な倚くの䟿利なコマンドラむンオプションをサポヌトしおいたす。 これを実装する最良の方法は、ゲヌムに倖郚ラむブラリをロヌドさせ、各起動時に初期化機胜を実行させるこずです。 このような組織を䜿甚するず、実行可胜ファむルを倉曎せずに远加のラむブラリモゞュヌルをロヌドしたり、レゞストリで関数をむンタヌセプトしお、レゞストリではなくゲヌムの構成ファむルにすべおのゲヌムデヌタのストレヌゞを敎理するなど、倚くの䟿利なものを構成ファむルに远加できたす。 さたざたな蚭定セットで耇数のプロファむルをサポヌトし、それらを迅速に切り替える機胜は䞍芁です。 それでは始めたしょう。

倖郚ラむブラリを接続する最も䟿利な堎所は、ebueulax.dllラむブラリのダりンロヌド機胜で、これはラむセンス契玄の衚瀺を担圓したす。 WinMainが起動した盎埌に呌び出されたすが、ebueulax.dllラむブラリを読み蟌んでEBUEula関数を実行するこずに加えお、倚くの䜙分な䜜業を行うため、config.dllラむブラリを読み蟌んでLoadConfigラむブラリ関数を堎所ぞのポむンタヌで実行するように完党に曞き盎したすパラメヌタずしおメモリ内のコマンドラむン倉曎するため。

アセンブリコヌド 機械コヌド
  LoadConfigLib proc near
     sub esp、208h
    プッシュESI
    プッシュ゚ディ
     ebxをプッシュ
    プッシュecx
     edxをプッシュ
     mov esi、dsLoadLibraryA
     67B8C4hを抌したす。  lpLibFileName
     esiを呌び出したす。 ロヌドラむブラリ
     mov ebx、eax
    テストebx、ebx
     jz short loc_587443
    プッシュオフセットaLoadconfig
     ebxをプッシュしたす。  hModule
    呌び出しdsGetProcAddress
     mov edi、eax
    テスト゚ディ゚ディ
     jz short loc_58743C
     mov eax、[esp + 220h]; **匕数
    プッシュeax
    ゚ディに電話
     jmp short loc_587443
 loc_58743C
     ebxをプッシュしたす。  hLibModule
    呌び出しdsFreeLibrary
 loc_587443
    ポップEDX
    ポップECX
    ポップEBX
    ポップ゚ディ
    ポップ゚ス
     ESP、208hを远加
     retn
 Loadconfiglib endp 
 
 81 EC 08 02 00 00
 56
 57
 53
 51
 52
 8B 35 E0 51 63 00
 68 C4 B8 67 00
 Ff d6
 8B D8
 85 DB
 74 25
 68 B8 B8 67 00
 53
 FF 15 C8 50 63 00
 8B F8
 85 FF
 74 0C
 8B 84 24 20 02 00 00
 50
 Ff d7
 EB 07

 53
 FF 15 20 51 63 00

 5A
 59
 5B
 5F
 5E
 81 C4 08 02 00 00
 C3 
䞊蚘のコヌドは、いく぀かのラむブラリ関数呌び出しを行いたす。 それらのアドレスは、マシンコヌドに手動で挿入されたした。 次の蚘事気にしない堎合:)では、FASMを䜿甚しお、実行可胜ファむルに挿入する準備が完党に敎ったコヌドを生成する方法を説明したす。

通垞のHEX゚ディタヌを䜿甚しお、元の関数オフセット187400hから開始を新しい関数に眮き換えたす。 新しい関数は元の関数よりもはるかに短いため、残りのバむトをオペレヌションコヌドnop-90hに眮き換えるこずを忘れないでください。 远加のマシンコヌド甚にさらに192バむトの空きバむトを取埗したした。 この堎所は将来䜿甚できたす。

゜ヌスマシンコヌド 受信したマシンコヌド
  81 EC 08 02 00 00 53 56 
 8B 35 E0 51 63 00 57 68
 CC B8 67 00 FF D6 8B D8 
 85 DB 75 0A 5F 5E 5B 81
 C4 08 02 00 00 C3 68 C4 
 B8 67 00 53 FF 15 C8 50
 63 00 8B F8 85 FF 75 13 
 53 FF 15 20 51 63 00 5F
 5E 33 C0 5B 81 C4 08 02 
 00 00 C3 8B 84 24 18 02
 00 00 50 FF D6 8B F0 85
 ... 
  81 EC 08 02 00 00 56 57
 53 51 52 8B 35 E0 51 63
 00 68 C4 B8 67 00 FF D6 
 8B D8 85 DB 74 25 68 B8
 B8 67 00 53 FF 15 C8 50 
 63 00 8B F8 85 FF 74 0C
 8B 84 24 20 02 00 00 50 
 FF D7 EB 07 53 FF 15 20
 51 63 00 5A 59 5B 5F 5E 
 81 C4 08 02 00 00 C3 90
 90 90 90 90 90 90 90 90 90 
 ... 
config.dllモゞュヌルが残りの䜜業を凊理したす。 C / C ++ / Delphiで蚘述できたす。 そのタスクは簡単です-実行可胜ファむルからアプリケヌションコマンドラむンぞのポむンタヌを取埗し、構成ファむルの蚭定に応じお倉曎したす。 ボヌナスずしお、構成ファむルでこれを蚭定するこずにより、远加モゞュヌルをロヌドする機胜を䜿甚できたす。 これを行うには、ゲヌムのアドレス空間にロヌドする必芁があるモゞュヌルファむルの名前でWinAPI関数LoadLibraryを呌び出すだけです。



りィンドりモヌドのサポヌト



りィンドりモヌドのサポヌトは、config.dllによっおロヌドされる独立したモゞュヌルwndmode.dllずしお線成されたす。 このモゞュヌルは、すべおのDirectDraw呌び出しをむンタヌセプトし、プログラムをりィンドり内で実行するようにパラメヌタヌを倉曎したす。その埌、元のDirectDraw関数に制埡を移したす。



これは、むンタヌセプトされた関数を倉曎するこずで実装されたす。 むンタヌセプトされた関数の最初の数バむトは、むンタヌセプト関数コマンドぞの無条件ゞャンプに眮き換えられたす。 このトリックはWinNTに実装するのは非垞に簡単ですWinNTは各プロセスのシステムラむブラリむメヌゞの独自のコピヌを䜜成するため 



wndmode.dllモゞュヌル自䜓は、d3dhook.dllラむブラリの高床に修正されたバヌゞョンであり、実装されおいたす。





これで、このラむブラリは、ほがすべおのDirectDrawゲヌムに統合しおりィンドりゲヌムにする準備ができたした。 だから誰かが他のゲヌムを修正するなら、それは重宝したす。



どうしたの



倉曎に぀いおは倚くの䜜業が行われたしたが、ここではほんのわずかな倉曎に぀いおも考慮したため、わずかな倉曎の説明にも倚くの劎力が必芁です。 必芁に応じお、完成した倉曎枈みファむルをダりンロヌドしお、IDAの残りの倉曎を確認できたす。



䞀般的に、次の結果を達成するこずができたした。





すべおの倉曎は安定しお機胜し、障害は芋぀かりたせんでした。 りィンドりモヌドでは、ゲヌムカヌ゜ルがゲヌムりィンドりの領域を離れお戻った埌にゲヌムカヌ゜ルず同時にシステムカヌ゜ルを衚瀺する問題は未解決のたたです。 ただし、これは、ゲヌム゚ンゞンがりィンドり内で実行されるように蚭蚈されおおらず、カヌ゜ルがゲヌムりィンドりを離れたずきにオプションを提䟛しないずいう事実のみに起因したす。 倉曎の次のバヌゞョンでは、これは修正されたす。

この倉曎の開発に察する論理的な結論は、適切なゲヌムサヌバヌを䜜成しおゲヌムにゲヌムルヌムサポヌトを導入するこずです。これは、ゟヌンの公匏のAge of Empiresゲヌムルヌムが数幎前に閉鎖されたためです。 これはすべお、゜ヌスコヌドを手元に持たずに実装するこずが可胜です。



おわりに



私がしたこずを実際に詊しおみたい堎合は、 Age of Empires IIThe ConquerorsLite Edition 合蚈94MBを私のWebサむトからダりンロヌドできたす。

すべおが䞀床にここに曞かれおおり、あたり詳现に曞かれおいないのが残念です。 䞀般的なスキヌムを説明しようずしたした。 次の蚘事では、修正の各段階を個別に怜蚎したり、アドバむスを䞎えたりできたす。



All Articles