dwgx@blog:~$dwgx
> cd ../posts

thcrap: メモリ patch を JSON フレームワークにする

// created

thcrap は Touhou Patch Center コミュニティが作った汎用の Windows メモリ patch フレームワークで、原作者は brliron 一味だ。このコピーは上流から fork したもので、純粋に内部がどう動いているのか中身を開けて見たかった。本業は東方の日本語同人ゲームを翻訳することだが、土台は特定のゲームに依存しない注入式の patch エンジンになっている。

コアは DLL 注入に頼っていて、エンジンとプラグインをターゲットプロセスに注入し、さらに子プロセスへ伝播させる。だから vpatch のような同じく注入で動く patch と共存できる。設定はすべて JSON なので patch は生まれつきオープンで読みやすい。JSON の再帰的マージで重ねがけを実現していて、優先度に従って patch を積み上げ、ワイルドカードのブラックリストでファイルを遮断でき、翻訳・BGM・画像 patch はそれぞれ独立しつつ一緒に組み合わせられる。

低レイヤーには、自分が fork して主に研究したかった数種類の hook がある:

  • binary hack: メモリに直接書き換えを流し込む、ほぼ手書きアセンブリ;
  • breakpoint: 任意の命令に hook を仕掛けて自分の DLL 内の関数を呼び出し、その時点の CPU レジスタを読み書きできる;
  • この二つはグループ化して順に適用でき、EXE のパッカーや DRM を専門に相手にする;
  • file breakpoint: メモリ内でデータファイルを patch 版に直接差し替え、ファイル形式の hook も同様に JSON で記述して重ねられる。

分解して見るとどれも逆向の定番操作だが、それが「JSON で記述、重ねがけ可能」という一つのフレームワークに組み上げられているのが面白い。もう一つ細かい点: win32_utf8 という独立したライブラリを使っていて、Win32 の ANSI 関数を使う古いプログラムに透過的に UTF-8 ファイル名サポートを付け足す。もう AppLocale を入れる必要はない。このライブラリは単独で切り出されているので、他のプロジェクトでも使える。バージョン識別は SHA-256 と EXE のファイルサイズに頼っていて、同じゲームの異なるバージョンがそれぞれ対応する patch に合致する。

始めるには git clone --recursive でサブモジュールを全部引っ張ってきて、VS でビルドして動かし、thcrap_tsa(上海アリスの STG エンジン)と thcrap_tasofro(黄昏フロンティアのもの)を辿って hook の書き方を読めばいい。プロジェクト全体が Public Domain なので、読んでいて心理的な負担がない。fork は github.com/dwgx/thcrap、上流は thpatch/thcrap。