めいくりぷとのブログ

技術的なことをまったりと。

WDDM Hook

#include "stdafx.h"

#include "CDDIContext.hpp"
#include "CLog.hpp"
#include "utils.hpp"

#pragma warning(disable: 4800)
#include <d3dumddi.h>
#pragma warning(default: 4091)
#include <algorithm>

#include <d3d9.h>
#pragma comment(lib, "d3d9.lib")

HRESULT APIENTRY CreateDeviceInternal(
	_In_	D3D10DDI_HADAPTER		 hAdapter,
	_Inout_ D3D10DDIARG_CREATEDEVICE *pCreateDevice);

CDDIContext::CDDIContext()
{
	this->m_pfnCreateDevice = NULL;
	this->m_hDriverModule = NULL;
}

CDDIContext::~CDDIContext()
{
}

BOOL CDDIContext::InitDrvContext()
{
	IDirect3D9 *pDirect3D = Direct3DCreate9(D3D_SDK_VERSION);
	if (pDirect3D)
	{
		for (int i = 0; i < pDirect3D->GetAdapterCount(); i++)
		{
			D3DADAPTER_IDENTIFIER9 Identifier;
			if (SUCCEEDED(pDirect3D->GetAdapterIdentifier(i, 0, &Identifier)))
			{
				this->m_hDriverModule = LoadModule(Identifier.DriverName);							
				break;
			}
		}
	}

	if (this->m_hDriverModule != NULL)
	{
		PFND3D10DDI_OPENADAPTER _OpenAdapter10_2 = 
			reinterpret_cast<PFND3D10DDI_OPENADAPTER>(GetProcAddress(hDriverModule, "OpenAdapter10_2"));
		if (_OpenAdapter10_2 != NULL)
		{
			return Detour_OpenAdapter10_2();
		}
	}

	return FALSE;
}

HRESULT CDDIContext::SetDevice(
	_In_	PFND3D10DDI_CREATEDEVICE pfnCreateDevice)
{
	this->m_pfnCreateDevice = pfnCreateDevice;
	return this->m_pfnCreateDevice != NULL ? S_OK : E_FAIL;
}

HRESULT CDDIContext::CreateDevice(
	_In_ D3D10DDI_HADAPTER		 hAdapter,
	_Inout_ D3D10DDIARG_CREATEDEVICE *pCreateDevice)
{
	return this->m_pfnCreateDevice(hAdapter, pCreateDevice);
}

HMODULE CDDIContext::GetDriverModule()
{
	return this->m_hDriverModule;
}

BOOL CDDIContext::Detour_OpenAdapter10_2()
{
	typedef HRESULT(APIENTRY *pfnOpenAdapter10_2)(
		_Inout_ D3D10DDIARG_OPENADAPTER *pOpenData
		);

	static pfnOpenAdapter10_2 _OpenAdapter10_2 =
		reinterpret_cast<pfnOpenAdapter10_2>(GetProcAddress(this->GetDriverModule(), "OpenAdapter10_2"));

	pfnOpenAdapter10_2 OpenAdapter10_2_Hook = [](
		_Inout_ D3D10DDIARG_OPENADAPTER *pOpenData) -> HRESULT
	{
		CDDIContext *pDDIContext;
		HRESULT hr;

		hr = _OpenAdapter10_2(pOpenData);
		if (SUCCEEDED(hr) 
			&& pOpenData != NULL 
			&& pOpenData->pAdapterFuncs_2 != NULL)
		{
			pDDIContext = CDDIContext::GetInstance();
			if (SUCCEEDED(pDDIContext->SetDevice(
				pOpenData->pAdapterFuncs_2->pfnCreateDevice))){
				pOpenData->pAdapterFuncs_2->pfnCreateDevice = CreateDeviceInternal;
			//	CLog::Log("driver function => CreateDevice %p\n", pOpenData->pAdapterFuncs_2->pfnCreateDevice);
			}
		}

		return hr;
	};

	return DetourFunction(TRUE, reinterpret_cast<LPVOID*>(&_OpenAdapter10_2), OpenAdapter10_2_Hook);
}

HRESULT APIENTRY CreateDeviceInternal(
	_In_	D3D10DDI_HADAPTER		 hAdapter,
	_Inout_ D3D10DDIARG_CREATEDEVICE *pCreateDevice)
{
	CDDIContext *pDDIContext = CDDIContext::GetInstance();
	HRESULT hr;

	hr = pDDIContext->CreateDevice(hAdapter, pCreateDevice);
	if (SUCCEEDED(hr))
	{
		// code here
	}

	return hr;
}

これで、D3D11 DDI がフックできるのですが、D3D9の場合はnvldumd.OpenAdapter10_2ではなく、nvd3dum.OpenAdapterが呼ばれて初期化される。
pDirect3D->GetAdapterIdentifier で、nvldumd.dllが返される。
nvd3dum.dllはどこから来てるんですかね・・・?

nvd3dum.dllが使われてるゲームから初期化の処理追っていくしかなさそう...?