pop↑ push↓

☆ (ゝω・)v

中国チームのEU4の中文化手法について

はじめに

 52pcgame内でEU4の中文化を開発している中国チームより、プロダクトを掲載する許可を戴いたため、ここでご紹介をしたいと思います。プロダクトのレポジトリは下記になります。

Bitbucket

どのようなものか

 上記のレポジトリのReadMeにもありますが、この方式には素晴らしい点がたくさんありますので、順を追って説明したいと思います。

① exeを改竄しなくてよい

 exeを改竄しないで、UTF-8表示が可能になっています。したがってたとえアップデートがあっても、再度パッチを当てる必要がありません。これをどのように実現しているかは後述したいと思います。

② 変更箇所のパターン認識

 これはパッチを作っている私からすると大変に助かることなのですが、プログラムが登録されているパターンを探して、マルチバイト文字の表示に必要な変更を自動で加えるため、アップデートがあっても、1からパッチを作り直す必要がありません。

③ 文字データがUTF-8

 文字データをUTF-8としてそのままで扱っているため、保存したセーブデータやログなどはそのままテキストエディタで読むことができます。また、翻訳ファイルを変換することなく、扱うことができます。

④ フォントデータに制限がない

私の作ったパッチだと、一部使えない文字範囲があるのですが、このパッチはすべてのUTF-8の範囲を扱うことができます。

どのように実現しているか

プロキシDLL

まず、①についてです。これはプロキシDLLという仕組みを使っています。詳細は下記を見てください。

D3D9プロキシDLLの作り方 · GitHub

 解説しますと、Windowsのプログラムファイルは、実行時に必要なDLLをロードする際、まず最初にexeがあるディレクトリ(カレントディレクトリ)を見て、なければ共有のDLLフォルダを見に行くという仕様があります。

 ここでその名前の、ほとんどの処理は元のDLLに丸投げするが、一部の処理のみを変更したDLLを作り、カレントディレクトリに置いておくと、プログラムはそのDLLを読み込みますから、プログラムに対して処理を変更させることができます。

プロキシDLLは更に別のDLLを読み込む

 今回のプロキシDLLのターゲットはd3d9.dllで、これはDirectXの描画に使われれているものです。面白いのはDirectXの動作は変更せず、初期化の部分だけを変更し、そこでLoadLibraryWを使って、他のDLLを更にインポートしている点です。これにより拡張性と見通しが良くなっています。今回はpluginフォルダ以下のDLL(plugin.dll)を読み込むようになっていました。

f:id:saito-matanki:20180618230622p:plain

動的プログラム変更

 ここからがまた面白いです。plugin.dll内でGetModuleHandleA(NULL)を実行することで、eu4.exeのマッピングアドレスを取得しています。

モジュールのマッピング

[PE(Portable Executable)ファイルフォーマットの概要

f:id:saito-matanki:20180618234020p:plain

そこにはPIMAGE_SECTION_HEADERがありますから、RVAを取得して、.textと.rdataの位置を割り出しています。つまり、IDAで見えるようなセグメントを実行時に取得できたことになります。

f:id:saito-matanki:20180618234528p:plain

そして、.textにはプログラムのコードが存在していますので、ここから、特定のバイトパターンを検索して、メモリを書き換えることで、パッチを使わずに動的にexeの動作を変更できるというわけです。

f:id:saito-matanki:20180618235041p:plain