質問

寄り道したい EndScene 任意の DirectX 9 アプリケーションから小さなオーバーレイを作成します。例として、FRAPS のフレーム カウンター オーバーレイを取り上げます。これは、アクティブ化されたときにゲームに表示されます。

これを行うには次の方法を知っています。

  1. 新しいものを作成する d3d9.dll, 、その後、ゲームのパスにコピーされます。system32 などに移動する前に、現在のフォルダーが最初に検索されるため、変更した DLL がロードされ、追加のコードが実行されます。

    欠点: ゲームを開始する前にそこに置く必要があります。

    • 最初の方法と同じですが、system32 の DLL を直接置き換えます。

    欠点: ゲーム固有のコードを追加することはできません。DLL をロードしたくないアプリケーションを除外することはできません。

    • IDA Pro 4.9 Free などのツールを使用して、DLL から EndScene オフセットを直接取得します。DLL はそのままロードされるため、ゲームにマップされるときにこのオフセットを DLL 開始アドレスに追加して実際のオフセットを取得し、それをフックするだけです。

    欠点: オフセットはすべてのシステムで同じではありません。

    • フッキング Direct3DCreate9 D3D9 を取得してからフッキングします D3D9->デバイスの作成 デバイスポインタを取得してからフックします デバイス -> エンドシーン 仮想テーブルを介して。

    欠点: プロセスがすでに実行されている場合、DLL を挿入することはできません。でプロセスを開始する必要があります CREATE_SUSPENDED イニシャルをフックするフラグ Direct3DCreate9.

    • DLL が挿入されるとすぐに、新しいウィンドウで新しいデバイスを作成します。次に、 EndScene このデバイスからオフセットしてフックすると、ゲームで使用されるデバイスのフックが作成されます。

    欠点: 私が読んだ情報によると、2 番目のデバイスを作成すると既存のデバイスに干渉する可能性があり、ウィンドウ表示とウィンドウ表示ではバグが発生する可能性があります。フルスクリーンモードなど

    • 3番目の方法と同じです。ただし、パターン スキャンを実行して、 EndScene.

    欠点: それほど信頼できるようには見えません。

どうやって引っ掛けることができますか EndScene 挿入された DLL から、ゲームが既に実行されているときにロードされる可能性があり、別の処理を行う必要はありません。 d3d9.dllは他のシステム上で信頼できる方法で実行されますか?たとえば FRAPS は DirectX フックをどのように実行するのでしょうか?DLL はすべてのゲームに適用する必要はなく、DLL を挿入する特定のプロセスにのみ適用する必要があります。 CreateRemoteThread.

役に立ちましたか?

解決

あなたはシステム全体のフックをインストールします。これを行うと、あなたはすべてのプロセスにロードされ得る(は、SetWindowsHookEx)。

フックが呼び出されたときに

さて、あなたはロードされたd3d9.dllを探します。

1がロードされている場合は、一時的なD3D9オブジェクトを作成し、EndSceneメソッドのアドレスを取得するためのvtableを歩いています。

次に、あなた自身の方法で、EndSceneコールにパッチを適用することができます。 (あなたのメソッドの呼び出しによってEndSceneの最初の命令を交換します。

完了したら、

は、元EndSceneメソッドを呼び出すために、コールバックにパッチを適用する必要があります。そして、あなたのパッチを再インストールします。

このはFRAPSはそれをしない方法です。 (リンクする

<時間>

あなたは、インターフェイスのvtableのから関数のアドレスを見つけることができます。

あなたが次のことを行うことができますので(擬似コード):

IDirect3DDevice9* pTempDev = ...;
const int EndSceneIndex = 26 (?);

typedef HRESULT (IDirect3DDevice9::* EndSceneFunc)( void );

BYTE* pVtable = reinterpret_cast<void*>( pTempDev );
EndSceneFunc = pVtable + sizeof(void*) * EndSceneIndex;

EndSceneFuncは今、関数自体へのポインタが含まれていません。私たちは今、どちらかのすべてのコール・サイトにパッチを適用することができますか、我々は関数自体にパッチを適用することができます。

このすべては、WindowsのCOM-インタフェースの実装の知識に依存することに注意してください。しかし、すべてのWindowsバージョン(32または64のいずれかではなく、同時に両方)に、これは作品ます。

他のヒント

少し古い質問ですが、C# でこれを行うことに興味がある人のために、ここに私の例を示します。 C# を使用した Direct3D 9 API のフック. 。これは、マネージ コードからアンマネージ関数にフックを「安全に」インストールできるオープン ソース .NET アセンブリである EasyHook を利用します。(注記:EasyHook は、DLL インジェクションに関するすべての問題に対処します。たとえば、CREATE_SUSPENDED、ACL、32 ビットと 64 ビットなど)

Christopher が述べたものと同様の VTable アプローチを、小さな C++ ヘルパー DLL 経由で使用して、フックする IDirect3DDevice9 関数のアドレスを動的に決定します。これは、一時的なウィンドウ ハンドルを作成し、必要な関数をフックする前に、挿入されたアセンブリ内に使い捨ての IDirect3Device9 を作成することによって行われます。これにより、アプリケーションがすでに実行中のターゲットをフックできるようになります (更新:これは C# 内でも完全に可能であることに注意してください - リンク先のページのコメントを参照してください)。

アップデート:の更新バージョンもあります Direct3D 9、10、11 のフック まだ EasyHook を使用しており、SlimDX の代わりに SharpDX を使用しています

私はこの質問は古いですが、これはDirectX9のを使用して、任意のプログラムのために働く必要があり、あなたは基本的に自分自身のインスタンスを作成して、仮想テーブルへのポインタを取得し、その後、あなたはそれをフックしている知っています。あなたはところで回り道3.Xが必要になります:

//Just some typedefs:
typedef HRESULT (WINAPI* oEndScene) (LPDIRECT3DDEVICE9 D3DDevice);
static oEndScene EndScene;

//Do this in a function or whatever
HMODULE hDLL=GetModuleHandleA("d3d9");
LPDIRECT3D9(__stdcall*pDirect3DCreate9)(UINT) = (LPDIRECT3D9(__stdcall*)(UINT))GetProcAddress( hDLL, "Direct3DCreate9");

LPDIRECT3D9 pD3D = pDirect3DCreate9(D3D_SDK_VERSION);

D3DDISPLAYMODE d3ddm;
HRESULT hRes = pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &d3ddm );
D3DPRESENT_PARAMETERS d3dpp; 
ZeroMemory( &d3dpp, sizeof(d3dpp));
d3dpp.Windowed = true;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.BackBufferFormat = d3ddm.Format;

WNDCLASSEX wc = { sizeof(WNDCLASSEX),CS_CLASSDC,TempWndProc,0L,0L,GetModuleHandle(NULL),NULL,NULL,NULL,NULL,("1"),NULL};
RegisterClassEx(&wc);
HWND hWnd = CreateWindow(("1"),NULL,WS_OVERLAPPEDWINDOW,100,100,300,300,GetDesktopWindow(),NULL,wc.hInstance,NULL);

hRes = pD3D->CreateDevice( 
    D3DADAPTER_DEFAULT,
    D3DDEVTYPE_HAL,
    hWnd,
    D3DCREATE_SOFTWARE_VERTEXPROCESSING | D3DCREATE_DISABLE_DRIVER_MANAGEMENT,
    &d3dpp, &ppReturnedDeviceInterface);

pD3D->Release();
DestroyWindow(hWnd);

if(pD3D == NULL){
    //printf ("WARNING: D3D FAILED");
    return false;
}
pInterface = (unsigned long*)*((unsigned long*)ppReturnedDeviceInterface);


EndScene = (oEndScene) (DWORD) pInterface[42];
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach(&(PVOID&)EndScene, newEndScene);
DetourTransactionCommit();

そして、あなたの関数ます:

HRESULT WINAPI D3D9Hook::newEndScene(LPDIRECT3DDEVICE9 pDevice)
{   
    //Do your stuff here

    //Call the original (if you want)
    return EndScene(pDevice);
}
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top