DXSense 第五人格のプロセスに ImGui デバッグパネルをねじ込む
DXSense は第五人格のプロセスに DLL を注入し、Dear ImGui でゲーム内にデバッグ overlay を一枚描く。プロセスメモリをリアルタイムで覗き、数値を書き換え、フレーム単位でレンダリングを追える。第五人格は DX11 なので、練習台にはちょうどいい。オフラインの demo でしか触っていないし、オンライン対戦には手を出していない。真似してオンラインでやるのもやめておけ。プロジェクトは 2026 年 4 月で止めた。リポジトリはアーカイブとして残してある。以下は当時のメモ。
全体は二つに分かれる。注入される DLL と、injector だ。injector は一番素朴なやり方で通す。VirtualAllocEx でパスを書き込み、CreateRemoteThread で LoadLibraryW を呼び、DXSense.dll をねじ込む。DLL が中に入ってから、当時こだわっていた点がいくつかある。
- DllMain では何もしない。boot スレッドを立ち上げてすぐ return する。loader lock の中で DX11 の初期化一式を走らせると一瞬でデッドロックする。この罠は一度踏めば忘れない。
- vtable のオフセットはハードコードしない。message-only の HWND で dummy swapchain を作り(D3D11CreateDeviceAndSwapChain)、本物の vtable から Present / ResizeBuffers をその場でスキャンして、MinHook で hook する。インデックス表をハードコードすると、SDK が上がった途端に壊れる。
- 入力は WndProc のサブクラス化で通す。SetWindowLongPtrW で swapchain のウィンドウだけ差し替える。グローバルな SetWindowsHookEx は使わない。後者はセッション内のすべてのウィンドウを汚染する。汚すぎる。
- Hook のライフサイクルは RAII で管理する。全部一つの HookManager に押し込み、teardown 時に一括で外す。散らばった MH_* が hook を漏らさないようにするためだ。
- CRT は
/MTで静的リンクする。ホストプロセスの MSVC ランタイムのバージョンと衝突するのを避けるためだ。
自分でわりと気に入っている点が二つ。一つは Procedure Fabric。長時間動き続ける挙動を、その場しのぎのスレッドの山で管理したくなかったので、Loom と型付きの Pin と Tick フローに抽象化した。engage/disengage は完全に宣言的で、挙動一つの on/off がきれいに収まる。もう一つは組み込みの Python ブリッジ。ランタイムで peek / poke / call ができて、アドレスを一つ変えるたびに DLL を再コンパイルしなくていい。パネル上で直接スクリプトを書いて試せるので、デバッグが一段速くなる。
レンダリングバックエンドの層は IRenderBackend で抽象化したが、実際に仕上げたのは DX11 だけ。INSERT で overlay 全体を on/off する。依存は Dear ImGui(docking ブランチ)と MinHook の二つだけ。
コードは All Rights Reserved。公開しているのはアーキテクチャを学びたい人に考え方を見せるためだけだ。DLL 注入、hook のライフサイクル、ImGui の統合、Procedure Fabric、この辺の pattern。オンライン対戦に持ち込んで反チートと張り合うな、二次配布するな、完成品にコンパイルして配るな。何かあっても俺は責任を取らない。メンテしないし、直さないし、PR も受けない。似たものが欲しいなら、kiero / GuidedHacking / MinHook の上流ドキュメントの方が俺より分かりやすく書いてある。自分でゼロから書く方が確実だ。