2012年12月22日土曜日

中華MODのしくみ

ゲーム日本語化 Advent Calendar 2012

前回、ゲームプログラムには元々日本語(マルチバイト文字)表示に対応しているものと、Latin-1(1バイト文字)表示にしか対応していないものがあり、対応するにはプログラムの変更が必要という話をした。
ソースコード(実行ファイルの元)がある場合は、ソースコードを変更してそのソースから変更版の実行ファイルを作ればよいが、無い場合はどうするか。

ゲームプログラムの実行ファイルから、文字表示に関する部分を突き止め、その部分を乗っ取って自作のマルチバイト対応コードに置き換える、ということをする。


EXE書き換え


実行ファイルを書き換える。
Morrowind Code Patch
とかたぶんそう。

特殊ローダ


通常、エクスプローラからメニューやダブルクリックすると、ゲームプログラムをメモリにロードして実行する。

しかし特殊なローダを使うと、ロードだけして実行しない。
ここで無理やりDLLを読み込ませ、さらにメモリ上のゲームプログラムの文字表示関連部分を変更して、それから実行する。
ゲームが開始してパラメータやイベントなど文字表示を行う処理になると、変更された文字表示処理に飛ぶ。

通常
+------------+
|            |
| ゲーム.exe |
|            |
|   本体     |
|     |      |
|     |      |
|  テキスト  |
|     |      |
| 1文字取出  |
|     |      |
|     |      |
| 文字表示   |
|            |
+------------+

ローダー経由
+------------+
|            |
| ゲーム.exe |
|            |
|   本体     |
|     |      |
|     |      |
|  テキスト  |
|     |      |
|     *------------+
|     |      |     |
|     |      |     |
|     *---------+  |
|            |  |  |
+------------+  |  |
|自作DLL     |  |  |
|            |  |  |
| 文字表示 --|--+  |
|            |     |
| 1文字取出--|-----+
|            |
+------------
*を書き換える


ゲームプログラムを改変する、というとなんだか怖そうだが、怪しいMODを使わない人でも、実は使ったことがあるはず。

Steamで販売されているゲームには、元々Steamに対応しているものと、していないものがある。
また、「ゲームを追加/非Steamゲームを追加」すると、非steamゲームをsteamのリストに登録してsteam経由でプレイできる。
steam経由でプレイすると、右下にsteamアイコンが出て、画面キャプチャやチャット等のsteam機能を使えるようになる。


これはsteamが特殊ローダとして働き、非steamゲームを改変してsteam機能を追加している。
例えばキー入力を乗っ取ってSHIFT+TABでsteamモードに入ったり、画面描画完了を乗っ取ってsteamアイコンを表示してから本当の画面描画完了をしていると思われる。

※コメントで指摘されましたがOrignの勘違いでした。



※と思ったけどやっぱsteamにもDLLいました



偽DLL


中華MODの中には、XXXX.dll を XXXX.dllとXXXX_ori.dllとかに差し替えるものがある。

ゲームプログラムは通常、Windows DLLやDirect X DLLなど、外部のDLLをロードするように作られている。
差し替えた状態でゲームプログラムがDLLをロードする時、本来のDLLではなく偽DLLを読む。
このタイミングで偽DLLの初期化が呼ばれるので、ここでメモリ上のゲームプログラム本体を書き換える。
また、オリジナルのDLLをロードして、オリジナルDLL内の関数の場所を調べておく。

ゲーム中にDLLが呼ばれたら、偽DLLはオリジナルのDLLの該当関数に飛ばす。

通常
    +------------+
    |            |
    | ゲーム.exe |
    |            |
    |            |
  +--- DLL呼出1  |
  | |            |
+-+--- DLL呼出2  |
| | |            |
| | +------------+
| | | DLL        |
| | |            |
| | | *初期化    |
| | |            |
| +-- DLL関数1   |
|   |            |
+---- DLL関数2   |
    |            |
    +------------|

* はロード時に自動で呼ばれる

偽DLL
    +------------+
    |            |
    | ゲーム.exe |
    |            |
    |            |
  +--- DLL呼出1  |
  | |            |
+-+--- DLL呼出2  |
| | |            |
| | +------------+
| | | 偽DLL      |
| | |            |
| | | *本体改変  |
| | |  元DLLロード
| | |            | 
| +----------------+
+--------------------+
    |            | | |
    +------------| | |
    | 元DLL      | | |
    |            | | |
    | *初期化    | | |
    |            | | |
    | DLL関数1 ----+ |
    |            |   |
    | DLL関数2 ------+
    |            |
    +------------|

ここでのポイントは「元々ゲームプログラムがロードするDLL」という点である。
どのDLLを差し替えるかはさしたる問題ではない。
「ゲーム中にDLLが呼ばれたら、オリジナルのDLLの該当関数に飛ばす」処理を書くのが、関数がたくさんあるDLLだと面倒なので、関数が少ないDLLが好まれる。

Direct X のDLLを差し替えているからといって、 Direct X の機能を変更しているとは限らない。


これらの「ゲームプログラム改変MOD」は、技術的にはウィルスの類と同じである。
乗っ取った後、キー入力や通信を盗み見たりの悪さをするか、文字を表示するかの違いでしかない。
改変してプロテクトやDRMのチェックを無効にするのも同様である。

他にも書き換える手段はあるが、ウィルスと異なり、見つからないようこっそり書き換えたり、書き換えたあと存在を隠すことが目的ではないので、詳細は述べない。


「ゲームプログラムの実行ファイルから、文字表示に関する部分を突き止め、その部分を乗っ取って自作のマルチバイト対応コードに置き換える」と言ったが、

  1. 既存プログラムの該当処理部分を突き止める、つまりDRMクラックできる技量と、
  2. さらにそれを乗っ取る、つまりウィルスを作れる技量と、
  3. 自作のマルチバイト対応コードを書く、つまりゲームプログラム(の一部)を作れる技量とを併せもっている必要があり、
  4. なおかつ、ゲーム本体のバージョンが変わると置き換える場所も変わるので、面倒くさい。
(ソースコードがあれば3.だけでよい)

日本にもそこまでやっている人が何人かいる(逆に言えば何人かしかいないと思われ)。

TObject
Obvilion日本語化パッチ
FOJP

俺はヘタレなので、置き換え場所を探すのが簡単なものしかやったことは無い。

ところでFOJPのソースコードが公開されていた。
ゲームプログラムの文字表示部分を突き止めるのではなく、変態(ほめ言葉)的なことをしている。

6 件のコメント:

  1. なるほどなー。技術的には相当困難+相当手間がかかるって感じですか?

    返信削除
  2. Steamの場合はDLLインジェクションではないですよ
    一般的な技術ではないですけど、DLLインジェクション自体は難しくないです
    サンプルのソースは検索すればごろごろ出てきます

    差し替えたい処理が外部DLLに書かれているかどうか、
    そのAPIの関数(の引数とかIFとか)が公開されているかで
    難易度は変わってくるでしょうね

    返信削除
  3. ご指摘ありがとうございます。steamの件追記しました

    おっしゃるようにDLLインジェクションより非公開のexeの中から該当箇所を探すほうが面倒くさい

    返信削除
  4. と思ったけどやっぱdllいました

    返信削除
  5. いやいや、それはインジェクション用のDLLでなく復号化やSteamWorkへ実績や認証結果を送るためのDLL。つまり単なるライブラリ(SteamWork SDKとして開発者へ提供されているものです)。

    返信削除
  6. 非steamゲームをsteam経由で実行した画面で、GameOverlayRender.dllってまんまの名前です

    SteamWork実績等は元々Steamに対応しているものが自前で呼ぶsteamclientだかsteam_apiだが

    返信削除