REPO 向けに DX11 overlay を書く: RepoDLL
RepoDLL は REPO プロセスに注入する overlay DLL だ。DX11 のスワップチェインを hook し、画面の上に ImGui を一枚重ねることで、プレイしながらメモリを読んで数値をいじれる。REPO は Unity/Mono の協力型搬入ゲームで、体力・座標・通貨といった値はすべてマネージド層にあり、読めるし描ける。
生アドレスのスキャン方式は取っていない。脆すぎて、ゲームが更新されるとオフセットが全部無効になるからだ。REPO は Mono なので、マネージド層はシンボル情報を持ち、実行時に解決できる。だから注入後はまず Mono ランタイムを特定し、Assembly-CSharp の中のクラス・フィールド・メソッドを名前で解決する。読み取れるのは意味を持ったものであって、生アドレスの羅列ではない。対象のクラス名 SemiFunc、PlayerAvatar、PhysGrabber、ExtractionPoint、ValuableDiscover、PunManager はすべて config.h に詰め込んであり、別のゲームに切り替えるなら理論上はこの一ファイルを変えるだけでいい。
エントリポイントは dllmain.cpp にある。attach 時にまず例外フィルタを保険として仕込み、メインスレッドを起こして HookDx11() を呼ぶ。ここで MinHook を使って DXGI の Present と ResizeBuffers を横取りする。以降は hook した Present の中で毎フレーム ImGui を描き、ついでにウィンドウの WndProc をサブクラス化して入力を奪い、Insert でメニューを呼び出す。ESP は Unity Camera から View/Projection 行列を取って WorldToScreen を行い、プレイヤー・貴重品・敵を画面に投影する。
いちばん厄介だったのはクラッシュだ。アイテムや敵を列挙するとき、マネージドオブジェクトはいつでも無効になり得る。レンダリングスレッドがダングリングポインタを読むとゲームごと落ちる。後からこれらの読み取りをすべて SEH で包んだ Safe ラッパーで包んだら、かなり安定した。協力プレイではさらにルームとホスト権限を判定する必要がある。すべての値が書けるわけではないので、read only にすべきものは read only にする。おもちゃ的な機能もいろいろ積んである。移動速度の上書き、多段ジャンプ、無敵、グラブ範囲、三人称視点、それに ValuableDiscover のネイティブなハイライトを hook して常時点灯にしている。
プロジェクトは C++20 の MSBuild ソリューションで、MinHook の部分は C だ。v145 + Win10 SDK でビルドし、d3d11.lib、dxgi.lib をリンクする。ImGui と MinHook はパッケージマネージャを使わず third_party/ に直接 vendored している。VS で Release | x64 を選べば RepoDLL.dll が出る。生成するのは DLL だけで、インジェクタはリポジトリに入っていない。初期の実験なので、当時のあの版の REPO に前提が数多く縛り付けられており、環境が変わればまず間違いなく手を入れる必要がある。MIT。