私のプロジェクトはターゲット プロセスを起動し、Direct3D 関数をフックするためのライブラリをそこに挿入します。私は過去にこれを成功させましたが、Direct3D インターフェイスのより厳密な仕様に合わせてライブラリを書き直すことにしました。ここでのアイデアは、独自の 1:1 ラッパー クラスのセットを作成し、それぞれが DirectX インターフェイス (つまり、 など) を継承することclass CD3D8 : IDirect3D8
でしclass CD3DDevice8 : IDirect3DDevice8
た。基礎となる各 DirectX COM インターフェイスのすべてのメンバーは純粋な仮想メソッドであるため、簡単にオーバーライドできると思いました...
したがって、ライブラリがフックされると、標準の代わりにDirect3DCreate8
my へのポインタが返されます。そして、私のライブラリは、そのポインターの仮想テーブルを使用してメソッド #15 をフックします。そして、それが呼び出されると、 ではなくへのポインターを返します。オーバーライドされた関数が注入されたアプリケーションによって呼び出されていないことを除けば、すべて問題ないようです。どういうわけか、アプリは自分の代わりに元のインターフェイス関数を呼び出しているようです。ここである種の概念が欠けていますか?たとえば、仮想テーブル ポインタをカスタム ラッパー クラスのポインタに手動で再マッピングする必要がありますか?CDirect3D8
IDirect3D8
IDirect3D8::CreateDevice
CDirect3DDevice8
IDirect3DDevice8
これまでに得たものは次のとおりです(d3d8のみを表示):
D3D.h
#pragma once
#define STDM(method) COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE method
#define STDM_(type,method) COM_DECLSPEC_NOTHROW type STDMETHODCALLTYPE method
template<class IDirect3D8>
class CD3D : public IDirect3D8
{
public:
CD3D();
~CD3D();
/*** IUnknown methods ***/
STDM(QueryInterface)(THIS_ REFIID riid, void** ppvObj);
STDM_(ULONG,AddRef)(THIS);
STDM_(ULONG,Release)(THIS);
/*** IDirect3D8 methods ***/
STDM(RegisterSoftwareDevice)(THIS_ void* pInitializeFunction);
STDM_(UINT, GetAdapterCount)(THIS);
STDM(GetAdapterIdentifier)(THIS_ UINT Adapter,DWORD Flags,D3DADAPTER_IDENTIFIER8* pIdentifier);
STDM_(UINT, GetAdapterModeCount)(THIS_ UINT Adapter);
STDM(EnumAdapterModes)(THIS_ UINT Adapter,UINT Mode,D3DDISPLAYMODE* pMode);
STDM(GetAdapterDisplayMode)(THIS_ UINT Adapter,D3DDISPLAYMODE* pMode);
STDM(CheckDeviceType)(THIS_ UINT Adapter,D3DDEVTYPE CheckType,D3DFORMAT DisplayFormat,D3DFORMAT BackBufferFormat,BOOL Windowed);
STDM(CheckDeviceFormat)(THIS_ UINT Adapter,D3DDEVTYPE DeviceType,D3DFORMAT AdapterFormat,DWORD Usage,D3DRESOURCETYPE RType,D3DFORMAT CheckFormat);
STDM(CheckDeviceMultiSampleType)(THIS_ UINT Adapter,D3DDEVTYPE DeviceType,D3DFORMAT SurfaceFormat,BOOL Windowed,D3DMULTISAMPLE_TYPE MultiSampleType);
STDM(CheckDepthStencilMatch)(THIS_ UINT Adapter,D3DDEVTYPE DeviceType,D3DFORMAT AdapterFormat,D3DFORMAT RenderTargetFormat,D3DFORMAT DepthStencilFormat);
STDM(GetDeviceCaps)(THIS_ UINT Adapter,D3DDEVTYPE DeviceType,D3DCAPS8* pCaps);
STDM_(HMONITOR, GetAdapterMonitor)(THIS_ UINT Adapter);
STDM(CreateDevice)(THIS_ UINT Adapter,D3DDEVTYPE DeviceType,HWND hFocusWindow,DWORD BehaviorFlags,D3DPRESENT_PARAMETERS* pPresentationParameters,IDirect3DDevice8** ppReturnedDeviceInterface);
};
D3D.cpp
#include "stdafx.h"
#define STDIMP(iface, method, ...) COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE CD3D<iface>::method(__VA_ARGS__)
#define STDIMP_(iface, type, method, ...) COM_DECLSPEC_NOTHROW type STDMETHODCALLTYPE CD3D<iface>::method(__VA_ARGS__)
#define STDIMP8(method, ...) STDIMP(IDirect3D8, method, __VA_ARGS__)
#define STDIMP8_(type, method, ...) STDIMP_(IDirect3D8, type, method, __VA_ARGS__)
CD3D<IDirect3D8>::CD3D()
{
}
CD3D<IDirect3D8>::~CD3D()
{
}
STDIMP8(QueryInterface, THIS_ REFIID riid, void** ppvObj) {
return QueryInterface( riid, ppvObj );
}
STDIMP8_(ULONG, AddRef, THIS) {
return AddRef();
}
STDIMP8_(ULONG, Release, THIS) {
return Release();
}
STDIMP8(RegisterSoftwareDevice, THIS_ void* pInitializeFunction) {
return RegisterSoftwareDevice( pInitializeFunction );
}
STDIMP8_(UINT, GetAdapterCount, THIS) {
return GetAdapterCount();
}
STDIMP8(GetAdapterIdentifier, THIS_ UINT Adapter, DWORD Flags, D3DADAPTER_IDENTIFIER8* pIdentifier) {
return GetAdapterIdentifier( Adapter, Flags, pIdentifier );
}
STDIMP8_(UINT, GetAdapterModeCount, THIS_ UINT Adapter) {
return GetAdapterModeCount( Adapter );
}
STDIMP8(EnumAdapterModes, THIS_ UINT Adapter, UINT Mode, D3DDISPLAYMODE* pMode) {
return EnumAdapterModes( Adapter, Mode, pMode );
}
STDIMP8(GetAdapterDisplayMode, THIS_ UINT Adapter, D3DDISPLAYMODE* pMode) {
return GetAdapterDisplayMode( Adapter, pMode );
}
STDIMP8(CheckDeviceType, THIS_ UINT Adapter, D3DDEVTYPE CheckType, D3DFORMAT DisplayFormat, D3DFORMAT BackBufferFormat, BOOL Windowed) {
return CheckDeviceType( Adapter, CheckType, DisplayFormat, BackBufferFormat, Windowed );
}
STDIMP8(CheckDeviceFormat, THIS_ UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT AdapterFormat, DWORD Usage, D3DRESOURCETYPE RType, D3DFORMAT CheckFormat) {
return CheckDeviceFormat( Adapter, DeviceType, AdapterFormat, Usage, RType, CheckFormat );
}
STDIMP8(CheckDeviceMultiSampleType, THIS_ UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT SurfaceFormat, BOOL Windowed, D3DMULTISAMPLE_TYPE MultiSampleType) {
return CheckDeviceMultiSampleType( Adapter, DeviceType, SurfaceFormat, Windowed, MultiSampleType );
}
STDIMP8(CheckDepthStencilMatch, THIS_ UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT AdapterFormat, D3DFORMAT RenderTargetFormat, D3DFORMAT DepthStencilFormat) {
return CheckDepthStencilMatch( Adapter, DeviceType, AdapterFormat, RenderTargetFormat, DepthStencilFormat );
}
STDIMP8(GetDeviceCaps, THIS_ UINT Adapter, D3DDEVTYPE DeviceType, D3DCAPS8* pCaps) {
return GetDeviceCaps( Adapter, DeviceType, pCaps );
}
STDIMP8_(HMONITOR, GetAdapterMonitor, THIS_ UINT Adapter) {
return GetAdapterMonitor( Adapter );
}
STDIMP8(CreateDevice, THIS_ UINT Adapter, D3DDEVTYPE DeviceType, HWND hFocusWindow, DWORD BehaviorFlags, D3DPRESENT_PARAMETERS* pPresentationParameters, IDirect3DDevice8** ppReturnedDeviceInterface) {
return CreateDevice( Adapter, DeviceType, hFocusWindow, BehaviorFlags, pPresentationParameters, ppReturnedDeviceInterface );
}
Main.cpp ( Microsoft Detours 3.0を使用):
#include <detours.h>
#include "D3D.h"
typedef HMODULE (WINAPI * HookLoadLibraryA)( LPCSTR lpFileName );
typedef IDirect3D8 *(WINAPI * HookDirect3DCreate8)( UINT SdkVersion );
typedef HRESULT (WINAPI * HookCreateDevice8)( IDirect3DDevice8* pInterface, UINT Adapter, D3DDEVTYPE DeviceType, HWND hFocusWindow, DWORD BehaviorFlags, D3DPRESENT_PARAMETERS* pPresentationParameters, IDirect3DDevice8** ppReturnedDeviceInterface );
HookLoadLibraryA RealLoadLibraryA;
HookDirect3DCreate8 RealDirect3DCreate8;
HookCreateDevice8 RealCreateDevice8;
//...
CD3D<IDirect3D8> *m_d3d8;
CD3DDevice<IDirect3D8> *m_d3dDev8;
//...
RealLoadLibraryA = (HookLoadLibraryA)GetProcAddress(GetModuleHandleA("kernel32.dll"), "LoadLibraryA");
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach(&(PVOID&)RealLoadLibraryA, FakeLoadLibraryA);
DetourTransactionCommit();
//...
VOID VirtualHook( PVOID pInterface, PVOID pHookProc, PVOID pOldProc, int iIndex )
{
// Hook a procedure within an interface's virtual table
PDWORD pVtable = (PDWORD)*((PDWORD)pInterface);
DWORD lpflOldProtect;
VirtualProtect( (PVOID)&pVtable[iIndex], sizeof(DWORD), PAGE_READWRITE, &lpflOldProtect );
if( pOldProc ) *(DWORD*)pOldProc = pVtable[iIndex];
pVtable[iIndex] = (DWORD)pHookProc;
VirtualProtect( pVtable, sizeof(DWORD), lpflOldProtect, &lpflOldProtect );
}
HRESULT WINAPI FakeCreateDevice8( IDirect3DDevice8* pInterface, UINT Adapter, D3DDEVTYPE DeviceType, HWND hFocusWindow, DWORD BehaviorFlags, D3DPRESENT_PARAMETERS* pPresentationParameters, IDirect3DDevice8** ppReturnedDeviceInterface )
{
HRESULT ret = RealCreateDevice8( pInterface, Adapter, DeviceType, hFocusWindow, BehaviorFlags, pPresentationParameters, ppReturnedDeviceInterface );
// Save the registers
__asm pushad
if(*ppReturnedDeviceInterface != NULL)
m_d3dDev8 = reinterpret_cast<CD3DDevice<IDirect3D8> *>(*ppReturnedDeviceInterface);
// Restore the registers
__asm popad
return ret;
}
IDirect3D8 *WINAPI FakeDirect3DCreate8( UINT SdkVersion )
{
m_d3d8 = reinterpret_cast<CD3D<IDirect3D8> *>(RealDirect3DCreate8( SdkVersion ));
if( m_d3d8 ) {
// Hook CreateDevice (vftable index #15)
VirtualHook( m_d3d8, &FakeCreateDevice8, &RealCreateDevice8, 15 );
}
return m_d3d8;
}
HMODULE WINAPI FakeLoadLibraryA( LPCSTR lpFileName )
{
CStringA strFileName( lpFileName );
int i = strFileName.ReverseFind('\\');
if(i != -1) strFileName = strFileName.Right(i + 1);
if( strFileName.CompareNoCase("d3d8.dll") == 0 )
{
// Hook Direct3DCreate8
HMODULE m_hD3D = RealLoadLibraryA( lpFileName );
RealDirect3DCreate8 = (HookDirect3DCreate8)GetProcAddress(m_hD3D, "Direct3DCreate8");
DetourTransactionBegin();
DetourUpdateThread( GetCurrentThread() );
DetourAttach(&(PVOID&)RealDirect3DCreate8, FakeDirect3DCreate8);
DetourTransactionCommit();
return m_hD3D;
}
}
...フックされた関数が呼び出されますが、ラッパー関数は呼び出されず、注入されたアプリケーションは通常どおりに実行されます。どうしてこれなの?もちろん、すべての DirectX インターフェイス (Direct3D の各バージョン) にあるすべての関数に手動でフックを設定することもできますが、これのポイントは、それを行う必要がないようにして、少しきれいに保つことでした。これを意図したとおりに機能させる方法はありますか?ありがとう!