2

我的项目启动了一个目标进程,向其中注入了一个库,用于挂钩 Direct3D 函数。我过去成功地做到了这一点,但决定将库重写为更接近 Direct3D 接口的规范。这里的想法是创建一组我自己的 1:1 包装类,每个类都继承一个 DirectX 接口(即 ,class CD3D8 : IDirect3D8等等class CD3DDevice8 : IDirect3DDevice8)。由于每个底层 DirectX COM 接口的所有成员都是纯虚拟方法,我想我可以轻松地覆盖它们......

因此,当我的库挂钩时Direct3DCreate8,我返回一个指向 myCDirect3D8而不是标准的指针IDirect3D8。然后我的库使用该指针的虚拟表来挂钩方法 #15,即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 版本)中找到的每个函数手动设置挂钩,但这样做的目的是尽量避免这样做,并使其保持清洁。那么有没有办法让它按我的预期工作?谢谢!

4

1 回答 1

0

您正在使用reinterpret_cast,它不会做太多事情,因为底层对象仍然有一个指向“真实”IDirect3D8IDirect3DDevice8COM vtable 的指针,它将用于调用。

Instead, instantiate your custom CD3D or CD3DDevice by passing it the original object instance. Then modify all your calls to call back the correct method on the original object -- your class effectively acting as a transparent proxy.

I mean something such as:

STDIMP8_(ULONG, AddRef, THIS) {
    return realObject->AddRef();
}

with realObject being the original IDirect3D8*.

于 2012-11-22T14:10:18.033 回答