2007年10月15日

アスペクト比固定拡大ツールの仕組み

アスペクト比固定拡大ツールは、フックを仕込んでアプリケーションからDirect3Dへのアクセスをトラップしています。

ただし、DirectXは全てCOMクラスで実装されているので、よくあるAPIフックのようにDLLのインポートアクセステーブル(IAT)を書き換える方法ではフックすることができません。

そこで、まずはプロキシDLLを使ってDirect3DCreate9(8)の呼び出しをトラップし、そこから返されるIDirect3D9のVtblを書き換えています。プロキシDLLを使ったフックはD3DSpyでも使われています。

Direct3DCreate9にフックを仕込む手段は、アプリケーションのエントリポイントで一度停止させてからd3d9.dllのIATを書き換える等の方法もありますが、その方法ではアプリケーションをランチャーから起動させる必要があって面倒なので、今回はプロキシDLLを採用しました。(元になったのがネトゲ用に作った窓化ツールだったというのも理由)

COMクラスは、各メソッドへのポインタが並んだテーブルへのポインタを持っています。これはVisualC++の仮想関数と互換性のある形式で、C++からはこのテーブルの存在は意識する必要がないのですが、CでCOMクラスを扱う場合はlpVtblというメンバを持った構造体として定義されます。例えばBeginSceneをCから呼ぶ場合は、lpD3DDev->lpVtbl->BeginScene(lpD3DDev)となります。(引数のlpD3DDevはC++の暗黙の引数thisに相当する)

C++の形式ではVtblに直接アクセスする手段が無いので、C形式の方がフックしやすいです。C++の場合でも、d3d9.hをインクルードする前に#define CINTERFACEと書いておくと、定義がC形式に切り替わります。

メインの処理は大雑把に言うと、CreateDeviceをフックして指定された解像度のレンダーターゲットテクスチャを作成して、それをバックバッファのように見せかけています。Presentの段階で本物のバックバッファに比率を調節して拡大コピーします。

ただし、BeginStateBlockとEndStateBlockがVtblを書き換えるという方法で実装されているので注意が必要です。せっかくVtblを書き換えてフックを仕込んでも、これらのメソッドが呼ばれるとVtblが初期化されてしまいます。対策として、BeginStateBlockが呼ばれた時点でEndStateBlockにフックを仕掛け、EndStateBlockの後でVtblを元にもどすようにしました。

また、マウスカーソルは最初はGetCursorPos等をフックして座標変換するつもりでしたが、その方法では上手く動作しなかったので、本物のカーソルは非表示にして座標変換した位置に自分でカーソルを描画しています。しかし、いくら調べてもアニメーションカーソルに関する資料が見つからなかったので、今はカーソルはアニメーションしません。

Posted by 新坂 | Comment(0) | TrackBack(0) | プログラミング | このブログの読者になる | 更新情報をチェックする
この記事へのコメント
コメントを書く
お名前: [必須入力]

メールアドレス:

ホームページアドレス:

コメント: [必須入力]

この記事へのトラックバックURL

※ブログオーナーが承認したトラックバックのみ表示されます。

※言及リンクのないトラックバックは受信されません。


この記事へのトラックバック