はじめに
x64化にあたってDLLの技術を再調査しました。下記の記事の続きにあたると思ってください。
DLLインジェクション
DLLインジェクションについての概要は参考1を参照のこと。EU4/CK2マルチバイト化ではexeディレクトリにカスタムしたd3d9.dllを置いて、インターセプトを実現している。 カスタムしたd3d9.dllを作るコードは下記にある。
EU4dll/d3d9 at master · matanki-saito/EU4dll · GitHub
このDLLはdefファイルを使ってDirect3DCreate9とDirect3DCreate9Exをエクスポートしている。
EU4dll/d3d9.def at master · matanki-saito/EU4dll · GitHub
その実態は__declspec(naked)された関数であり、インラインアセンブラのjmpによって本来のd3d9.dllの関数に転送される。
EU4dll/dllmain.cpp at cebec8e139b69d3fe0b4e4c461ffb541f36960e9 · matanki-saito/EU4dll · GitHub
この転送先となる関数だが、これはDLLを読み込んだ時(DllMain)に設定される。SHGetKnownFolderPathでd3d9.dllの場所を特定して、LoadLibraryで読み込み、その中からGetProcAddressで必要となる二つの関数(Direct3DCreate9とDirect3DCreate9Ex)を見つけている。
EU4dll/dllmain.cpp at cebec8e139b69d3fe0b4e4c461ffb541f36960e9 · matanki-saito/EU4dll · GitHub
これでインターセプトは完成するので、あとはDllMainで必要なdllを読んだりすればよい。
EU4dll/dllmain.cpp at cebec8e139b69d3fe0b4e4c461ffb541f36960e9 · matanki-saito/EU4dll · GitHub
x64における問題
x64ではdeclspec(naked)とasm(インラインアセンブラ)が使えない(参考2,3)。
解決法
__declspec(naked)とインラインアセンブラは消してしまうしかない。ただしアセンブラはasmファイルで記述可能である。asmにハイライトをつけるために、下記のプラグインを入れる。 marketplace.visualstudio.com
ビルドするプラットフォームをx64にしたら、参考2を見てmasmを使えるようにしておく。
srcフォルダにhook.asmを作り、ビルドに含める。
asmは後にして、dllmain.cppを先に修正する。asmから参照できるように参照する変数はextern "C" で囲む必要がある(参考4)。同様にasmに共有したい変数があれば入れておく。asmにあって呼び出す必要がある関数もこの中に入れておく。
hook.asmも中身を作っていく。最初のSTRUCTはC++側にある定義と同じにする。構造体をasm側で読み込むために必要になる。
EXTERNを使って、C++側にある構造体と変数を読み込む。STRUCTを使えば構造体も読み込める。
.CODE以下はcodeセグメント。PUBLIC nameとname: を使うと関数を定義できるが、これは使わないでname proc ~ name endpを使うこと。なぜかPUBLICだとブレークポイントが有効にならない。
構造体は最初のSTRUCTにキャストして使う(参考5)
こんな感じでやると、ブレークポイントを置いてdllをinjectionできるようになる(画像はHOI4にd3d9.dllをinjectionしたもの)。