From 2ba8cae64e263e55bac074a0a36ad16f980cb067 Mon Sep 17 00:00:00 2001 From: Nemirtingas Date: Thu, 25 Jul 2019 23:21:03 +0200 Subject: [PATCH] Added DirectX hooks Warning: DX9 doesn't support resizing (TODO), DX12 has not beed tested and is not finished. No OpenGL support for now. --- overlay_experimental/Base_Hook.cpp | 40 +++ overlay_experimental/Base_Hook.h | 43 ++++ overlay_experimental/DX10_Hook.cpp | 208 ++++++++++++++++ overlay_experimental/DX10_Hook.h | 49 ++++ overlay_experimental/DX11_Hook.cpp | 224 +++++++++++++++++ overlay_experimental/DX11_Hook.h | 49 ++++ overlay_experimental/DX12_Hook.cpp | 186 ++++++++++++++ overlay_experimental/DX12_Hook.h | 49 ++++ overlay_experimental/DX9_Hook.cpp | 204 +++++++++++++++ overlay_experimental/DX9_Hook.h | 50 ++++ overlay_experimental/DirectX_VTables.h | 330 +++++++++++++++++++++++++ overlay_experimental/Hook_Manager.cpp | 178 +++++++++++++ overlay_experimental/Hook_Manager.h | 46 ++++ 13 files changed, 1656 insertions(+) create mode 100644 overlay_experimental/Base_Hook.cpp create mode 100644 overlay_experimental/Base_Hook.h create mode 100644 overlay_experimental/DX10_Hook.cpp create mode 100644 overlay_experimental/DX10_Hook.h create mode 100644 overlay_experimental/DX11_Hook.cpp create mode 100644 overlay_experimental/DX11_Hook.h create mode 100644 overlay_experimental/DX12_Hook.cpp create mode 100644 overlay_experimental/DX12_Hook.h create mode 100644 overlay_experimental/DX9_Hook.cpp create mode 100644 overlay_experimental/DX9_Hook.h create mode 100644 overlay_experimental/DirectX_VTables.h create mode 100644 overlay_experimental/Hook_Manager.cpp create mode 100644 overlay_experimental/Hook_Manager.h diff --git a/overlay_experimental/Base_Hook.cpp b/overlay_experimental/Base_Hook.cpp new file mode 100644 index 0000000..24d39b5 --- /dev/null +++ b/overlay_experimental/Base_Hook.cpp @@ -0,0 +1,40 @@ +#include "Base_Hook.h" + +#include +#include "Hook_Manager.h" + +#include "../detours/detours.h" + +Base_Hook::~Base_Hook() +{ + UnhookAll(); +} + +void Base_Hook::BeginHook() +{ + DetourTransactionBegin(); + DetourUpdateThread(GetCurrentThread()); +} + +void Base_Hook::EndHook() +{ + DetourTransactionCommit(); +} + +void Base_Hook::UnhookAll() +{ + if (_hooked_funcs.size()) + { + BeginHook(); + std::for_each(_hooked_funcs.begin(), _hooked_funcs.end(), [](std::pair& hook) { + DetourDetach(hook.first, hook.second); + }); + EndHook(); + _hooked_funcs.clear(); + } +} + +void Base_Hook::HookFuncs(std::pair hook) +{ + DetourAttach(hook.first, hook.second); +} \ No newline at end of file diff --git a/overlay_experimental/Base_Hook.h b/overlay_experimental/Base_Hook.h new file mode 100644 index 0000000..7fb9281 --- /dev/null +++ b/overlay_experimental/Base_Hook.h @@ -0,0 +1,43 @@ +#ifndef __INCLUDED_BASE_HOOK_H__ +#define __INCLUDED_BASE_HOOK_H__ + +#define WIN32_LEAN_AND_MEAN +#define VC_EXTRALEAN +#include + +#include +#include + +class Base_Hook +{ +protected: + std::vector> _hooked_funcs; + + HMODULE _dll; + bool _hooked; + + Base_Hook(const Base_Hook&) = delete; + Base_Hook(Base_Hook&&) = delete; + Base_Hook& operator =(const Base_Hook&) = delete; + Base_Hook& operator =(Base_Hook&&) = delete; + +public: + Base_Hook() {} + virtual ~Base_Hook(); + + void BeginHook(); + void EndHook(); + void UnhookAll(); + + void HookFuncs(std::pair hook); + + template + void HookFuncs(std::pair funcs, Args... args) + { + _hooked_funcs.emplace_back(std::move(funcs)); + HookFuncs(funcs); + HookFuncs(args...); + } +}; + +#endif//__INCLUDED_BASE_HOOK_H__ \ No newline at end of file diff --git a/overlay_experimental/DX10_Hook.cpp b/overlay_experimental/DX10_Hook.cpp new file mode 100644 index 0000000..47d9bf8 --- /dev/null +++ b/overlay_experimental/DX10_Hook.cpp @@ -0,0 +1,208 @@ +#include "../dll/base.h" +#include "DX10_Hook.h" +#include "Hook_Manager.h" + +#include "../detours/detours.h" + +#include +#include +#include + +// This is created by DX10_Hook::Create, and deleted by the Hook_Manager if not used +static DX10_Hook* hook; + +void DX10_Hook::hook_dx10(UINT SDKVersion) +{ + if (!_hooked) + { + PRINT_DEBUG("Hooked DirectX 10\n"); + _hooked = true; + Hook_Manager::Inst().FoundHook(this); + + IDXGISwapChain* pSwapChain; + ID3D10Device* pDevice; + DXGI_SWAP_CHAIN_DESC SwapChainDesc = {}; + SwapChainDesc.BufferCount = 2; + SwapChainDesc.BufferDesc.Width = 800; + SwapChainDesc.BufferDesc.Height = 600; + SwapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + SwapChainDesc.BufferDesc.RefreshRate.Numerator = 60; + SwapChainDesc.BufferDesc.RefreshRate.Denominator = 1; + SwapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + SwapChainDesc.OutputWindow = GetForegroundWindow(); + SwapChainDesc.SampleDesc.Count = 1; + SwapChainDesc.SampleDesc.Quality = 0; + SwapChainDesc.Windowed = TRUE; + + D3D10CreateDeviceAndSwapChain(NULL, D3D10_DRIVER_TYPE_HARDWARE, NULL, 0, SDKVersion, &SwapChainDesc, &pSwapChain, &pDevice); + + loadFunctions(pDevice, pSwapChain); + + UnhookAll(); + BeginHook(); + HookFuncs( + std::make_pair(&(PVOID&)DX10_Hook::Present , &DX10_Hook::MyPresent), + std::make_pair(&(PVOID&)DX10_Hook::ResizeTarget , &DX10_Hook::MyResizeTarget), + std::make_pair(&(PVOID&)DX10_Hook::ResizeBuffers, &DX10_Hook::MyResizeBuffers) + ); + EndHook(); + + pDevice->Release(); + pSwapChain->Release(); + } +} + +void DX10_Hook::resetRenderState() +{ + if (initialized) + { + mainRenderTargetView->Release(); + + ImGui_ImplDX10_Shutdown(); + + initialized = false; + } +} + +void DX10_Hook::prepareForOverlay(IDXGISwapChain* pSwapChain) +{ + DXGI_SWAP_CHAIN_DESC desc; + pSwapChain->GetDesc(&desc); + + if (!initialized) + { + if (FAILED(pSwapChain->GetDevice(__uuidof(ID3D10Device), (PVOID*)& pDevice))) + return; + + ImGui::CreateContext(); + ImGuiIO& io = ImGui::GetIO(); + io.IniFilename = NULL; + + ID3D10Texture2D* pBackBuffer; + + pSwapChain->GetBuffer(0, __uuidof(ID3D10Texture2D), (LPVOID*)& pBackBuffer); + pDevice->CreateRenderTargetView(pBackBuffer, NULL, &mainRenderTargetView); + pBackBuffer->Release(); + + Hook_Manager::Inst().ChangeGameWindow(desc.OutputWindow); + ImGui_ImplWin32_Init(desc.OutputWindow); + ImGui_ImplDX10_Init(pDevice); + initialized = true; + } + + ImGui_ImplDX10_NewFrame(); + ImGui_ImplWin32_NewFrame(); + + ImGui::NewFrame(); + + Hook_Manager::Inst().CallOverlayProc(desc.BufferDesc.Width, desc.BufferDesc.Height); + + ImGui::EndFrame(); + + ImGui::Render(); + + pDevice->OMSetRenderTargets(1, &mainRenderTargetView, NULL); + ImGui_ImplDX10_RenderDrawData(ImGui::GetDrawData()); +} + +///////////////////////////////////////////////////////////////////////////////////// +// DirectX 10 Initialization functions +//HRESULT WINAPI DX10_Hook::MyD3D10CreateDevice(IDXGIAdapter* pAdapter, D3D10_DRIVER_TYPE DriverType, HMODULE Software, UINT Flags, UINT SDKVersion, ID3D10Device** ppDevice) +//{ +// auto res = _D3D10CreateDevice(pAdapter, DriverType, Software, Flags, SDKVersion, ppDevice); +// +// if (SUCCEEDED(res)) +// hook->hook_dx10(SDKVersion); +// +// return res; +//} + +HRESULT WINAPI DX10_Hook::MyD3D10CreateDeviceAndSwapChain(IDXGIAdapter* pAdapter, D3D10_DRIVER_TYPE DriverType, HMODULE Software, UINT Flags, UINT SDKVersion, + DXGI_SWAP_CHAIN_DESC* pSwapChainDesc, IDXGISwapChain** ppSwapChain, ID3D10Device** ppDevice) +{ + auto res = hook->D3D10CreateDeviceAndSwapChain(pAdapter, DriverType, Software, Flags, SDKVersion, pSwapChainDesc, ppSwapChain, ppDevice); + + if (SUCCEEDED(res)) + hook->hook_dx10(SDKVersion); + + return res; +} +///////////////////////////////////////////////////////////////////////////////////// + +HRESULT STDMETHODCALLTYPE DX10_Hook::MyPresent(IDXGISwapChain *_this, UINT SyncInterval, UINT Flags) +{ + hook->prepareForOverlay(_this); + return (_this->*hook->Present)(SyncInterval, Flags); +} + +HRESULT STDMETHODCALLTYPE DX10_Hook::MyResizeTarget(IDXGISwapChain* _this, const DXGI_MODE_DESC* pNewTargetParameters) +{ + hook->resetRenderState(); + return (_this->*hook->ResizeTarget)(pNewTargetParameters); +} + +HRESULT STDMETHODCALLTYPE DX10_Hook::MyResizeBuffers(IDXGISwapChain* _this, UINT BufferCount, UINT Width, UINT Height, DXGI_FORMAT NewFormat, UINT SwapChainFlags) +{ + hook->resetRenderState(); + return (_this->*hook->ResizeBuffers)(BufferCount, Width, Height, NewFormat, SwapChainFlags); +} + +DX10_Hook::DX10_Hook(): + initialized(false), + pDevice(nullptr), + mainRenderTargetView(nullptr) +{ + _dll = GetModuleHandle(DLL_NAME); + _hooked = false; + // Hook to D3D10CreateDevice and D3D10CreateDeviceAndSwapChain so we know when it gets called. + // If its called, then DX10 will be used to render the overlay. + //_D3D10CreateDevice = (decltype(_D3D10CreateDevice))GetProcAddress(_dll, "D3D10CreateDevice"); + D3D10CreateDeviceAndSwapChain = (decltype(D3D10CreateDeviceAndSwapChain))GetProcAddress(_dll, "D3D10CreateDeviceAndSwapChain"); + + BeginHook(); + HookFuncs( + //std::make_pair(&(PVOID&)_D3D10CreateDevice, &DX10_Hook::MyD3D10CreateDevice), + std::make_pair(&(PVOID&)D3D10CreateDeviceAndSwapChain, &DX10_Hook::MyD3D10CreateDeviceAndSwapChain) + ); + EndHook(); +} + +DX10_Hook::~DX10_Hook() +{ + PRINT_DEBUG("DX10 Hook removed\n"); + + if (_hooked) + { + ImGui_ImplDX10_Shutdown(); + ImGui_ImplWin32_Shutdown(); + ImGui::DestroyContext(); + } + + hook = nullptr; +} + +void DX10_Hook::Create() +{ + if (hook == nullptr) + { + hook = new DX10_Hook; + // Register the hook to the Hook Manager + Hook_Manager::Inst().AddHook(hook); + } +} + +void DX10_Hook::loadFunctions(ID3D10Device *pDevice, IDXGISwapChain *pSwapChain) +{ + void** vTable = *reinterpret_cast(pDevice); + +#define LOAD_FUNC(X) (void*&)X = vTable[(int)ID3D10DeviceVTable::X] + +#undef LOAD_FUNC + + vTable = *reinterpret_cast(pSwapChain); +#define LOAD_FUNC(X) (void*&)X = vTable[(int)IDXGISwapChainVTable::X] + LOAD_FUNC(Present); + LOAD_FUNC(ResizeBuffers); + LOAD_FUNC(ResizeTarget); +#undef LOAD_FUNC +} \ No newline at end of file diff --git a/overlay_experimental/DX10_Hook.h b/overlay_experimental/DX10_Hook.h new file mode 100644 index 0000000..35d6b68 --- /dev/null +++ b/overlay_experimental/DX10_Hook.h @@ -0,0 +1,49 @@ +#ifndef __INCLUDED_DX10_HOOK_H__ +#define __INCLUDED_DX10_HOOK_H__ + +#include +#include "DirectX_VTables.h" +#include "Base_Hook.h" + +class DX10_Hook : public Base_Hook +{ +public: + static constexpr const char DLL_NAME[] = "d3d10.dll"; + +private: + // Variables + bool initialized; + ID3D10Device* pDevice; + ID3D10RenderTargetView* mainRenderTargetView; + + // Functions + DX10_Hook(); + virtual ~DX10_Hook(); + + void hook_dx10(UINT SDKVersion); + void resetRenderState(); + void prepareForOverlay(IDXGISwapChain *pSwapChain); + + // Hook to render functions + static HRESULT STDMETHODCALLTYPE MyPresent(IDXGISwapChain* _this, UINT SyncInterval, UINT Flags); + static HRESULT STDMETHODCALLTYPE MyResizeTarget(IDXGISwapChain* _this, const DXGI_MODE_DESC* pNewTargetParameters); + static HRESULT STDMETHODCALLTYPE MyResizeBuffers(IDXGISwapChain* _this, UINT BufferCount, UINT Width, UINT Height, DXGI_FORMAT NewFormat, UINT SwapChainFlags); + + decltype(&IDXGISwapChain::Present) Present; + decltype(&IDXGISwapChain::ResizeBuffers) ResizeBuffers; + decltype(&IDXGISwapChain::ResizeTarget) ResizeTarget; + + // Hook functions so we know we use DX10 + //static decltype(D3D10CreateDevice) MyD3D10CreateDevice; + static decltype(D3D10CreateDeviceAndSwapChain) MyD3D10CreateDeviceAndSwapChain; + + //decltype(D3D10CreateDevice)* _D3D10CreateDevice; + decltype(D3D10CreateDeviceAndSwapChain)* D3D10CreateDeviceAndSwapChain; + +public: + static void Create(); // Initialize DX10 Hook. + + void loadFunctions(ID3D10Device *pDevice, IDXGISwapChain *pSwapChain); +}; + +#endif//__INCLUDED_DX10_HOOK_H__ \ No newline at end of file diff --git a/overlay_experimental/DX11_Hook.cpp b/overlay_experimental/DX11_Hook.cpp new file mode 100644 index 0000000..7c044d5 --- /dev/null +++ b/overlay_experimental/DX11_Hook.cpp @@ -0,0 +1,224 @@ +#include "../dll/base.h" +#include "DX11_Hook.h" +#include "Hook_Manager.h" + +#include +#include +#include + +// This is created by DX11_Hook::Create, and deleted by the Hook_Manager if not used +static DX11_Hook* hook; + +HRESULT GetDeviceAndCtxFromSwapchain(IDXGISwapChain* pSwapChain, ID3D11Device** ppDevice, ID3D11DeviceContext** ppContext) +{ + HRESULT ret = pSwapChain->GetDevice(__uuidof(ID3D11Device), (PVOID*)ppDevice); + + if (SUCCEEDED(ret)) + (*ppDevice)->GetImmediateContext(ppContext); + + return ret; +} + +void DX11_Hook::hook_dx11(UINT SDKVersion) +{ + if (!_hooked) + { + PRINT_DEBUG("Hooked DirectX 11\n"); + _hooked = true; + Hook_Manager::Inst().FoundHook(this); + + IDXGISwapChain* pSwapChain; + ID3D11Device* pDevice; + DXGI_SWAP_CHAIN_DESC SwapChainDesc = {}; + SwapChainDesc.BufferCount = 2; + SwapChainDesc.BufferDesc.Width = 800; + SwapChainDesc.BufferDesc.Height = 600; + SwapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + SwapChainDesc.BufferDesc.RefreshRate.Numerator = 60; + SwapChainDesc.BufferDesc.RefreshRate.Denominator = 1; + SwapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + SwapChainDesc.OutputWindow = GetForegroundWindow(); + SwapChainDesc.SampleDesc.Count = 1; + SwapChainDesc.SampleDesc.Quality = 0; + SwapChainDesc.Windowed = TRUE; + + D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, 0, NULL, NULL, SDKVersion, &SwapChainDesc, &pSwapChain, &pDevice, NULL, NULL); + + loadFunctions(pDevice, pSwapChain); + + UnhookAll(); + BeginHook(); + HookFuncs( + std::make_pair(&(PVOID&)DX11_Hook::Present , &DX11_Hook::MyPresent), + std::make_pair(&(PVOID&)DX11_Hook::ResizeTarget , &DX11_Hook::MyResizeTarget), + std::make_pair(&(PVOID&)DX11_Hook::ResizeBuffers, &DX11_Hook::MyResizeBuffers) + ); + EndHook(); + + pDevice->Release(); + pSwapChain->Release(); + } +} + +void DX11_Hook::resetRenderState() +{ + if (initialized) + { + mainRenderTargetView->Release(); + pContext->Release(); + + ImGui_ImplDX11_Shutdown(); + + initialized = false; + } +} + +void DX11_Hook::prepareForOverlay(IDXGISwapChain* pSwapChain) +{ + DXGI_SWAP_CHAIN_DESC desc; + pSwapChain->GetDesc(&desc); + + if (!initialized) + { + ID3D11Device* pDevice = nullptr; + if (FAILED(GetDeviceAndCtxFromSwapchain(pSwapChain, &pDevice, &pContext))) + return; + + ImGui::CreateContext(); + ImGuiIO& io = ImGui::GetIO(); + io.IniFilename = NULL; + + ID3D11Texture2D* pBackBuffer; + + pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)& pBackBuffer); + pDevice->CreateRenderTargetView(pBackBuffer, NULL, &mainRenderTargetView); + pBackBuffer->Release(); + + Hook_Manager::Inst().ChangeGameWindow(desc.OutputWindow); + ImGui_ImplWin32_Init(desc.OutputWindow); + ImGui_ImplDX11_Init(pDevice, pContext); + initialized = true; + } + + ImGui_ImplDX11_NewFrame(); + ImGui_ImplWin32_NewFrame(); + + ImGui::NewFrame(); + + Hook_Manager::Inst().CallOverlayProc(desc.BufferDesc.Width, desc.BufferDesc.Height); + + ImGui::EndFrame(); + + ImGui::Render(); + + pContext->OMSetRenderTargets(1, &mainRenderTargetView, NULL); + ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData()); +} + +///////////////////////////////////////////////////////////////////////////////////// +// DirectX 11 Initialization functions +//HRESULT WINAPI DX11_Hook::MyD3D11CreateDevice(__in_opt IDXGIAdapter* pAdapter, D3D_DRIVER_TYPE DriverType, HMODULE Software, UINT Flags, +// __in_ecount_opt(FeatureLevels) CONST D3D_FEATURE_LEVEL* pFeatureLevels, UINT FeatureLevels, UINT SDKVersion, __out_opt ID3D11Device** ppDevice, +// __out_opt D3D_FEATURE_LEVEL* pFeatureLevel, __out_opt ID3D11DeviceContext** ppImmediateContext) +//{ +// auto res = _D3D11CreateDevice(pAdapter, DriverType, Software, Flags, pFeatureLevels, FeatureLevels, SDKVersion, ppDevice, pFeatureLevel, ppImmediateContext); +// +// if (SUCCEEDED(res)) +// hook->hook_dx11(SDKVersion); +// +// return res; +//} + +HRESULT WINAPI DX11_Hook::MyD3D11CreateDeviceAndSwapChain(__in_opt IDXGIAdapter* pAdapter, D3D_DRIVER_TYPE DriverType, HMODULE Software, UINT Flags, + __in_ecount_opt(FeatureLevels) CONST D3D_FEATURE_LEVEL* pFeatureLevels, UINT FeatureLevels, UINT SDKVersion, + __in_opt CONST DXGI_SWAP_CHAIN_DESC* pSwapChainDesc, __out_opt IDXGISwapChain** ppSwapChain, __out_opt ID3D11Device** ppDevice, + __out_opt D3D_FEATURE_LEVEL* pFeatureLevel, __out_opt ID3D11DeviceContext** ppImmediateContext) +{ + auto res = hook->D3D11CreateDeviceAndSwapChain(pAdapter, DriverType, Software, Flags, pFeatureLevels, FeatureLevels, SDKVersion, pSwapChainDesc, ppSwapChain, ppDevice, pFeatureLevel, ppImmediateContext); + + if (SUCCEEDED(res)) + hook->hook_dx11(SDKVersion); + + return res; +} +///////////////////////////////////////////////////////////////////////////////////// + +HRESULT STDMETHODCALLTYPE DX11_Hook::MyPresent(IDXGISwapChain *_this, UINT SyncInterval, UINT Flags) +{ + hook->prepareForOverlay(_this); + + return (_this->*hook->Present)(SyncInterval, Flags); +} + +HRESULT STDMETHODCALLTYPE DX11_Hook::MyResizeTarget(IDXGISwapChain* _this, const DXGI_MODE_DESC* pNewTargetParameters) +{ + hook->resetRenderState(); + return (_this->*hook->ResizeTarget)(pNewTargetParameters); +} + +HRESULT STDMETHODCALLTYPE DX11_Hook::MyResizeBuffers(IDXGISwapChain* _this, UINT BufferCount, UINT Width, UINT Height, DXGI_FORMAT NewFormat, UINT SwapChainFlags) +{ + hook->resetRenderState(); + return (_this->*hook->ResizeBuffers)(BufferCount, Width, Height, NewFormat, SwapChainFlags); +} + +DX11_Hook::DX11_Hook(): + initialized(false), + pContext(nullptr), + mainRenderTargetView(nullptr) +{ + _dll = GetModuleHandle(DLL_NAME); + _hooked = false; + // Hook to D3D11CreateDevice and D3D11CreateDeviceAndSwapChain so we know when it gets called. + // If its called, then DX11 will be used to render the overlay. + //_D3D11CreateDevice = (decltype(_D3D11CreateDevice))GetProcAddress(_dll, "D3D11CreateDevice"); + D3D11CreateDeviceAndSwapChain = (decltype(D3D11CreateDeviceAndSwapChain))GetProcAddress(_dll, "D3D11CreateDeviceAndSwapChain"); + + BeginHook(); + HookFuncs( + //std::make_pair(&(PVOID&)_D3D11CreateDevice, &DX11_Hook::MyD3D11CreateDevice), + std::make_pair(&(PVOID&)D3D11CreateDeviceAndSwapChain, &DX11_Hook::MyD3D11CreateDeviceAndSwapChain) + ); + EndHook(); + +} + +DX11_Hook::~DX11_Hook() +{ + PRINT_DEBUG("DX11 Hook removed\n"); + + if (_hooked) + { + ImGui_ImplDX11_Shutdown(); + ImGui_ImplWin32_Shutdown(); + ImGui::DestroyContext(); + } + + hook = nullptr; +} + +void DX11_Hook::Create() +{ + if (hook == nullptr) + { + hook = new DX11_Hook; + // Register the hook to the Hook Manager + Hook_Manager::Inst().AddHook(hook); + } +} + +void DX11_Hook::loadFunctions(ID3D11Device *pDevice, IDXGISwapChain *pSwapChain) +{ + void** vTable = *reinterpret_cast(pDevice); + +#define LOAD_FUNC(X) (void*&)X = vTable[(int)ID3D11DeviceVTable::X] + +#undef LOAD_FUNC + + vTable = *reinterpret_cast(pSwapChain); +#define LOAD_FUNC(X) (void*&)X = vTable[(int)IDXGISwapChainVTable::X] + LOAD_FUNC(Present); + LOAD_FUNC(ResizeBuffers); + LOAD_FUNC(ResizeTarget); +#undef LOAD_FUNC +} \ No newline at end of file diff --git a/overlay_experimental/DX11_Hook.h b/overlay_experimental/DX11_Hook.h new file mode 100644 index 0000000..5f44f7d --- /dev/null +++ b/overlay_experimental/DX11_Hook.h @@ -0,0 +1,49 @@ +#ifndef __INCLUDED_DX11_HOOK_H__ +#define __INCLUDED_DX11_HOOK_H__ + +#include +#include "DirectX_VTables.h" +#include "Base_Hook.h" + +class DX11_Hook : public Base_Hook +{ +public: + static constexpr const char DLL_NAME[] = "d3d11.dll"; + +private: + // Variables + bool initialized; + ID3D11DeviceContext* pContext; + ID3D11RenderTargetView* mainRenderTargetView; + + // Functions + DX11_Hook(); + virtual ~DX11_Hook(); + + void hook_dx11(UINT SDKVersion); + void resetRenderState(); + void prepareForOverlay(IDXGISwapChain* pSwapChain); + + // Hook to render functions + static HRESULT STDMETHODCALLTYPE MyPresent(IDXGISwapChain* _this, UINT SyncInterval, UINT Flags); + static HRESULT STDMETHODCALLTYPE MyResizeTarget(IDXGISwapChain* _this, const DXGI_MODE_DESC* pNewTargetParameters); + static HRESULT STDMETHODCALLTYPE MyResizeBuffers(IDXGISwapChain* _this, UINT BufferCount, UINT Width, UINT Height, DXGI_FORMAT NewFormat, UINT SwapChainFlags); + + decltype(&IDXGISwapChain::Present) Present; + decltype(&IDXGISwapChain::ResizeBuffers) ResizeBuffers; + decltype(&IDXGISwapChain::ResizeTarget) ResizeTarget; + + // Hook functions so we know we use DX11 + //static decltype(D3D11CreateDevice) MyD3D11CreateDevice; + static decltype(D3D11CreateDeviceAndSwapChain) MyD3D11CreateDeviceAndSwapChain; + + //decltype(D3D11CreateDevice)* D3D11CreateDevice; + decltype(D3D11CreateDeviceAndSwapChain)* D3D11CreateDeviceAndSwapChain; + +public: + static void Create(); // Initialize DX11 Hook. + + void loadFunctions(ID3D11Device *pDevice, IDXGISwapChain *pSwapChain); +}; + +#endif//__INCLUDED_DX11_HOOK_H__ \ No newline at end of file diff --git a/overlay_experimental/DX12_Hook.cpp b/overlay_experimental/DX12_Hook.cpp new file mode 100644 index 0000000..7e74c5b --- /dev/null +++ b/overlay_experimental/DX12_Hook.cpp @@ -0,0 +1,186 @@ +#include "../dll/base.h" +#include "DX12_Hook.h" +#include "Hook_Manager.h" + +#include +#include +#include + +// This is created by DX12_Hook::Create, and deleted by the Hook_Manager if not used +static DX12_Hook* hook; + +void DX12_Hook::hook_dx12(D3D_FEATURE_LEVEL MinimumFeatureLevel) +{ + if (!_hooked) + { + PRINT_DEBUG("Hooked DirectX 12\n"); + } +} + +void DX12_Hook::resetRenderState() +{ + if (initialized) + { + pCmdAlloc->Release(); + pCmdList->Release(); + pDescriptorHeap->Release(); + + ImGui_ImplDX12_Shutdown(); + + initialized = false; + } +} + +void DX12_Hook::prepareForOverlay(IDXGISwapChain* pSwapChain) +{ + DXGI_SWAP_CHAIN_DESC desc; + pSwapChain->GetDesc(&desc); + + if (!initialized) + { + D3D12_DESCRIPTOR_HEAP_DESC d3d12_desc = {}; + ID3D12Device* pDevice; + + HRESULT ret = pSwapChain->GetDevice(__uuidof(ID3D12Device), (PVOID*)&pDevice); + + d3d12_desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV; + d3d12_desc.NumDescriptors = 1; + d3d12_desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE; + d3d12_desc.NodeMask = 1; + if (pDevice->CreateDescriptorHeap(&d3d12_desc, IID_PPV_ARGS(&pDescriptorHeap)) != S_OK) + { + pDevice->Release(); + return; + } + + SIZE_T rtvDescriptorSize = pDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV); + D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = pDescriptorHeap->GetCPUDescriptorHandleForHeapStart(); + mainRenderTargetDescriptor = rtvHandle; + + pDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&pCmdAlloc)); + + pDevice->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, pCmdAlloc, NULL, IID_PPV_ARGS(&pCmdList)); + + Hook_Manager::Inst().ChangeGameWindow(desc.OutputWindow); + ImGui_ImplWin32_Init(desc.OutputWindow); + ImGui_ImplDX12_Init(pDevice, 1, DXGI_FORMAT_R8G8B8A8_UNORM, + pDescriptorHeap->GetCPUDescriptorHandleForHeapStart(), + pDescriptorHeap->GetGPUDescriptorHandleForHeapStart()); + initialized = true; + } + + ImGui_ImplDX12_NewFrame(); + ImGui_ImplWin32_NewFrame(); + + ImGui::NewFrame(); + + Hook_Manager::Inst().CallOverlayProc(desc.BufferDesc.Width, desc.BufferDesc.Height); + + ImGui::EndFrame(); + + ImGui::Render(); + + pCmdAlloc->Reset(); + pCmdList->Reset(pCmdAlloc, NULL); + //pCmdList->ClearRenderTargetView(mainRenderTargetDescriptor, (float*)& clear_color, 0, NULL); + pCmdList->OMSetRenderTargets(1, &mainRenderTargetDescriptor, FALSE, NULL); + pCmdList->SetDescriptorHeaps(1, &pDescriptorHeap); + ImGui_ImplDX12_RenderDrawData(ImGui::GetDrawData(), pCmdList); +} + +///////////////////////////////////////////////////////////////////////////////////// +// DirectX 12 Initialization functions +HRESULT WINAPI DX12_Hook::MyD3D12CreateDevice( + _In_opt_ IUnknown* pAdapter, + D3D_FEATURE_LEVEL MinimumFeatureLevel, + _In_ REFIID riid, // Expected: ID3D12Device + _COM_Outptr_opt_ void** ppDevice) +{ + auto res = hook->D3D12CreateDevice(pAdapter, MinimumFeatureLevel, riid, ppDevice); + + if (SUCCEEDED(res)) + hook->hook_dx12(MinimumFeatureLevel); + + return res; +} +///////////////////////////////////////////////////////////////////////////////////// + +HRESULT STDMETHODCALLTYPE DX12_Hook::MyPresent(IDXGISwapChain *_this, UINT SyncInterval, UINT Flags) +{ + hook->prepareForOverlay(_this); + + return (_this->*hook->Present)(SyncInterval, Flags); +} + +HRESULT STDMETHODCALLTYPE DX12_Hook::MyResizeTarget(IDXGISwapChain* _this, const DXGI_MODE_DESC* pNewTargetParameters) +{ + hook->resetRenderState(); + return (_this->*hook->ResizeTarget)(pNewTargetParameters); +} + +HRESULT STDMETHODCALLTYPE DX12_Hook::MyResizeBuffers(IDXGISwapChain* _this, UINT BufferCount, UINT Width, UINT Height, DXGI_FORMAT NewFormat, UINT SwapChainFlags) +{ + hook->resetRenderState(); + return (_this->*hook->ResizeBuffers)(BufferCount, Width, Height, NewFormat, SwapChainFlags); +} + +DX12_Hook::DX12_Hook(): + initialized(false), + pCmdAlloc(nullptr), + pCmdList(nullptr), + pDescriptorHeap(nullptr) +{ + _dll = GetModuleHandle(DLL_NAME); + _hooked = false; + // Hook to D3D11CreateDevice and D3D11CreateDeviceAndSwapChain so we know when it gets called. + // If its called, then DX11 will be used to render the overlay. + D3D12CreateDevice = (decltype(D3D12CreateDevice))GetProcAddress(_dll, "D3D12CreateDevice"); + + BeginHook(); + HookFuncs( + std::make_pair(&(PVOID&)D3D12CreateDevice, &DX12_Hook::MyD3D12CreateDevice) + ); + EndHook(); + +} + +DX12_Hook::~DX12_Hook() +{ + PRINT_DEBUG("DX11 Hook removed\n"); + + if (_hooked) + { + ImGui_ImplDX12_Shutdown(); + ImGui_ImplWin32_Shutdown(); + ImGui::DestroyContext(); + } + + hook = nullptr; +} + +void DX12_Hook::Create() +{ + if (hook == nullptr) + { + hook = new DX12_Hook; + // Register the hook to the Hook Manager + Hook_Manager::Inst().AddHook(hook); + } +} + +void DX12_Hook::loadFunctions(ID3D12Device *pDevice, IDXGISwapChain *pSwapChain) +{ + void** vTable = *reinterpret_cast(pDevice); + + /* +#define LOAD_FUNC(X) (void*&)X = vTable[(int)ID3D12DeviceVTable::X] + +#undef LOAD_FUNC + */ + vTable = *reinterpret_cast(pSwapChain); +#define LOAD_FUNC(X) (void*&)X = vTable[(int)IDXGISwapChainVTable::X] + LOAD_FUNC(Present); + LOAD_FUNC(ResizeBuffers); + LOAD_FUNC(ResizeTarget); +#undef LOAD_FUNC +} \ No newline at end of file diff --git a/overlay_experimental/DX12_Hook.h b/overlay_experimental/DX12_Hook.h new file mode 100644 index 0000000..5851bbd --- /dev/null +++ b/overlay_experimental/DX12_Hook.h @@ -0,0 +1,49 @@ +#ifndef __INCLUDED_DX12_HOOK_H__ +#define __INCLUDED_DX12_HOOK_H__ + +#include +#include "DirectX_VTables.h" +#include "Base_Hook.h" + +class DX12_Hook : public Base_Hook +{ +public: + static constexpr const char DLL_NAME[] = "d3d12.dll"; + +private: + // Variables + bool initialized; + ID3D12CommandAllocator* pCmdAlloc; + ID3D12GraphicsCommandList* pCmdList; + ID3D12DescriptorHeap* pDescriptorHeap; + D3D12_CPU_DESCRIPTOR_HANDLE mainRenderTargetDescriptor; + + // Functions + DX12_Hook(); + virtual ~DX12_Hook(); + + void hook_dx12(D3D_FEATURE_LEVEL MinimumFeatureLevel); + void resetRenderState(); + void prepareForOverlay(IDXGISwapChain* pSwapChain); + + // Hook to render functions + static HRESULT STDMETHODCALLTYPE MyPresent(IDXGISwapChain* _this, UINT SyncInterval, UINT Flags); + static HRESULT STDMETHODCALLTYPE MyResizeTarget(IDXGISwapChain* _this, const DXGI_MODE_DESC* pNewTargetParameters); + static HRESULT STDMETHODCALLTYPE MyResizeBuffers(IDXGISwapChain* _this, UINT BufferCount, UINT Width, UINT Height, DXGI_FORMAT NewFormat, UINT SwapChainFlags); + + decltype(&IDXGISwapChain::Present) Present; + decltype(&IDXGISwapChain::ResizeBuffers) ResizeBuffers; + decltype(&IDXGISwapChain::ResizeTarget) ResizeTarget; + + // Hook functions so we know we use DX11 + static decltype(D3D12CreateDevice) MyD3D12CreateDevice; + + decltype(D3D12CreateDevice)* D3D12CreateDevice; + +public: + static void Create(); // Initialize DX11 Hook. + + void loadFunctions(ID3D12Device *pDevice, IDXGISwapChain *pSwapChain); +}; + +#endif//__INCLUDED_DX12_HOOK_H__ \ No newline at end of file diff --git a/overlay_experimental/DX9_Hook.cpp b/overlay_experimental/DX9_Hook.cpp new file mode 100644 index 0000000..210e301 --- /dev/null +++ b/overlay_experimental/DX9_Hook.cpp @@ -0,0 +1,204 @@ +#include "../dll/base.h" +#include "DX9_Hook.h" +#include "Hook_Manager.h" + +#include +#include +#include + +static DX9_Hook* hook; + +////////////////////////////////////////////////////////////////// +///////// ///////// +///////// This hook doesn't support game resize for now ///////// +///////// ///////// +////////////////////////////////////////////////////////////////// + +void DX9_Hook::hook_dx9(UINT SDKVersion) +{ + if (!_hooked) + { + PRINT_DEBUG("Hooked DirectX 9\n"); + _hooked = true; + Hook_Manager::Inst().FoundHook(this); + + IDirect3D9Ex* pD3D; + IDirect3DDevice9Ex* pDevice; + + Direct3DCreate9Ex(SDKVersion, &pD3D); + + D3DPRESENT_PARAMETERS params = {}; + params.BackBufferWidth = 1; + params.BackBufferHeight = 1; + params.hDeviceWindow = GetForegroundWindow(); + + pD3D->CreateDeviceEx(D3DADAPTER_DEFAULT, D3DDEVTYPE_NULLREF, NULL, D3DCREATE_HARDWARE_VERTEXPROCESSING, ¶ms, NULL, &pDevice); + + loadFunctions(pDevice); + + UnhookAll(); + BeginHook(); + HookFuncs( + //std::make_pair(&(PVOID&)Reset, &DX9_Hook::MyReset), + std::make_pair(&(PVOID&)Present, &DX9_Hook::MyPresent), + std::make_pair(&(PVOID&)PresentEx, &DX9_Hook::MyPresentEx) + //std::make_pair(&(PVOID&)EndScene, &DX9_Hook::MyEndScene) + ); + EndHook(); + + pDevice->Release(); + pD3D->Release(); + } +} + +void DX9_Hook::resetRenderState() +{ + if (initialized) + { + initialized = false; + + ImGui_ImplDX9_Shutdown(); + } +} + +void DX9_Hook::prepareForOverlay(IDirect3DDevice9 *pDevice) +{ + IDirect3DSwapChain9* pSwapChain; + pDevice->GetSwapChain(0, &pSwapChain); + D3DPRESENT_PARAMETERS PresentParameters; + pSwapChain->GetPresentParameters(&PresentParameters); + + pSwapChain->Release(); + + if (!initialized) + { + ImGui::CreateContext(); + ImGuiIO& io = ImGui::GetIO(); + io.IniFilename = NULL; + + D3DDEVICE_CREATION_PARAMETERS param; + pDevice->GetCreationParameters(¶m); + + Hook_Manager::Inst().ChangeGameWindow(param.hFocusWindow); + ImGui_ImplWin32_Init(param.hFocusWindow); + ImGui_ImplDX9_Init(pDevice); + initialized = true; + } + + ImGui_ImplDX9_NewFrame(); + ImGui_ImplWin32_NewFrame(); + + ImGui::NewFrame(); + + Hook_Manager::Inst().CallOverlayProc(PresentParameters.BackBufferWidth, PresentParameters.BackBufferHeight); + + ImGui::EndFrame(); + + ImGui::Render(); + + ImGui_ImplDX9_RenderDrawData(ImGui::GetDrawData()); +} + +///////////////////////////////////////////////////////////////////////////////////// +// DirectX 9 Initialization functions +IDirect3D9* DX9_Hook::MyDirect3DCreate9(UINT SDKVersion) +{ + auto res = hook->Direct3DCreate9(SDKVersion); + + if( res != nullptr ) + hook->hook_dx9(SDKVersion); + + return res; +} + +HRESULT DX9_Hook::MyDirect3DCreate9Ex(UINT SDKVersion, IDirect3D9Ex** ppDevice) +{ + auto res = hook->Direct3DCreate9Ex(SDKVersion, ppDevice); + + if (SUCCEEDED(res)) + hook->hook_dx9(SDKVersion); + + return res; +} +///////////////////////////////////////////////////////////////////////////////////// + +HRESULT STDMETHODCALLTYPE DX9_Hook::MyReset(IDirect3DDevice9* _this, D3DPRESENT_PARAMETERS* pPresentationParameters) +{ + hook->resetRenderState(); + return (_this->*hook->Reset)(pPresentationParameters); +} + +HRESULT STDMETHODCALLTYPE DX9_Hook::MyEndScene(IDirect3DDevice9* _this) +{ + //if( !hook->uses_present ) + hook->prepareForOverlay(_this); + return (_this->*hook->EndScene)(); +} + +HRESULT STDMETHODCALLTYPE DX9_Hook::MyPresent(IDirect3DDevice9* _this, CONST RECT* pSourceRect, CONST RECT* pDestRect, HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) +{ + hook->prepareForOverlay(_this); + return (_this->*hook->Present)(pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion); +} + +HRESULT STDMETHODCALLTYPE DX9_Hook::MyPresentEx(IDirect3DDevice9Ex* _this, CONST RECT* pSourceRect, CONST RECT* pDestRect, HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion, DWORD dwFlags) +{ + hook->prepareForOverlay(_this); + return (_this->*hook->PresentEx)(pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, dwFlags); +} + + +DX9_Hook::DX9_Hook(): + initialized(false), + uses_present(false) +{ + _dll = GetModuleHandle(DLL_NAME); + _hooked = false; + // Hook to Direct3DCreate9 and Direct3DCreate9Ex so we know when it gets called. + // If its called, then DX9 will be used to render the overlay. + Direct3DCreate9 = (decltype(Direct3DCreate9))GetProcAddress(_dll, "Direct3DCreate9"); + Direct3DCreate9Ex = (decltype(Direct3DCreate9Ex))GetProcAddress(_dll, "Direct3DCreate9Ex"); + + BeginHook(); + HookFuncs( + std::make_pair(&(PVOID&)Direct3DCreate9, &DX9_Hook::MyDirect3DCreate9), + std::make_pair(&(PVOID&)Direct3DCreate9Ex, &DX9_Hook::MyDirect3DCreate9Ex) + ); + EndHook(); +} + +DX9_Hook::~DX9_Hook() +{ + PRINT_DEBUG("DX9 Hook removed\n"); + + if (_hooked) + { + ImGui_ImplDX9_Shutdown(); + ImGui_ImplWin32_Shutdown(); + ImGui::DestroyContext(); + } + + hook = nullptr; +} + +void DX9_Hook::Create() +{ + if( hook == nullptr ) + { + hook = new DX9_Hook; + // Register the hook to the Hook Manager + Hook_Manager::Inst().AddHook(hook); + } +} + +void DX9_Hook::loadFunctions(IDirect3DDevice9Ex* obj) +{ + void** vTable = *reinterpret_cast(obj); + +#define LOAD_FUNC(X) (void*&)X = vTable[(int)IDirect3DDevice9VTable::X] + LOAD_FUNC(Reset); + LOAD_FUNC(EndScene); + LOAD_FUNC(Present); + LOAD_FUNC(PresentEx); +#undef LOAD_FUNC +} \ No newline at end of file diff --git a/overlay_experimental/DX9_Hook.h b/overlay_experimental/DX9_Hook.h new file mode 100644 index 0000000..18b8ffb --- /dev/null +++ b/overlay_experimental/DX9_Hook.h @@ -0,0 +1,50 @@ +#ifndef __INCLUDED_DX9_HOOK_H__ +#define __INCLUDED_DX9_HOOK_H__ + +#include +#include "DirectX_VTables.h" +#include "Base_Hook.h" + +class DX9_Hook : public Base_Hook +{ +public: + static constexpr const char DLL_NAME[] = "d3d9.dll"; + +private: + // Variables + bool initialized; + bool uses_present; + + // Functions + DX9_Hook(); + virtual ~DX9_Hook(); + + void hook_dx9(UINT SDKVersion); + void resetRenderState(); + void prepareForOverlay(IDirect3DDevice9* pDevice); + + // Hook to render functions + decltype(&IDirect3DDevice9::Reset) Reset; + decltype(&IDirect3DDevice9::EndScene) EndScene; + decltype(&IDirect3DDevice9::Present) Present; + decltype(&IDirect3DDevice9Ex::PresentEx) PresentEx; + + static HRESULT STDMETHODCALLTYPE MyReset(IDirect3DDevice9* _this, D3DPRESENT_PARAMETERS* pPresentationParameters); + static HRESULT STDMETHODCALLTYPE MyEndScene(IDirect3DDevice9 *_this); + static HRESULT STDMETHODCALLTYPE MyPresent(IDirect3DDevice9* _this, CONST RECT* pSourceRect, CONST RECT* pDestRect, HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion); + static HRESULT STDMETHODCALLTYPE MyPresentEx(IDirect3DDevice9Ex* _this, CONST RECT* pSourceRect, CONST RECT* pDestRect, HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion, DWORD dwFlags); + + // Hook functions so we know we use DX9 + static decltype(Direct3DCreate9) MyDirect3DCreate9; + static decltype(Direct3DCreate9Ex) MyDirect3DCreate9Ex; + + decltype(Direct3DCreate9)* Direct3DCreate9; + decltype(Direct3DCreate9Ex)* Direct3DCreate9Ex; + +public: + static void Create(); // Initialize DX9 Hook. + + void loadFunctions(IDirect3DDevice9Ex *obj); +}; + +#endif//__INCLUDED_DX9_HOOK_H__ \ No newline at end of file diff --git a/overlay_experimental/DirectX_VTables.h b/overlay_experimental/DirectX_VTables.h new file mode 100644 index 0000000..43cddfb --- /dev/null +++ b/overlay_experimental/DirectX_VTables.h @@ -0,0 +1,330 @@ +#pragma once + +#include + +enum class IDXGISwapChainVTable +{ + // IUnknown + QueryInterface, + AddRef, + Release, + + // IDXGIObject + SetPrivateData, + SetPrivateDataInterface, + GetPrivateData, + GetParent, + + // IDXGIDeviceSubObject + GetDevice, + + // IDXGISwapChain + Present, + GetBuffer, + SetFullscreenState, + GetFullscreenState, + GetDesc, + ResizeBuffers, + ResizeTarget, + GetContainingOutput, + GetFrameStatistics, + GetLastPresentCount, +}; + +enum class ID3D11DeviceVTable +{ + // IUnknown + QueryInterface, + AddRef, + Release, + + // ID3D11Device + CreateBuffer, + CreateTexture1D, + CreateTexture2D, + CreateTexture3D, + CreateShaderResourceView, + CreateUnorderedAccessView, + CreateRenderTargetView, + CreateDepthStencilView, + CreateInputLayout, + CreateVertexShader, + CreateGeometryShader, + CreateGeometryShaderWithStreamOutput, + CreatePixelShader, + CreateHullShader, + CreateDomainShader, + CreateComputeShader, + CreateClassLinkage, + CreateBlendState, + CreateDepthStencilState, + CreateRasterizerState, + CreateSamplerState, + CreateQuery, + CreatePredicate, + CreateCounter, + CreateDeferredContext, + OpenSharedResource, + CheckFormatSupport, + CheckMultisampleQualityLevels, + CheckCounterInfo, + CheckCounter, + CheckFeatureSupport, + GetPrivateData, + SetPrivateData, + SetPrivateDataInterface, + GetFeatureLevel, + GetCreationFlags, + GetDeviceRemovedReason, + GetImmediateContext, + SetExceptionMode, + GetExceptionMode, +}; + +enum class ID3D10DeviceVTable +{ + // IUnknown + QueryInterface, + AddRef, + Release, + + // ID3D10Device + VSSetConstantBuffers, + PSSetShaderResources, + PSSetShader, + PSSetSamplers, + VSSetShader, + DrawIndexed, + Draw, + PSSetConstantBuffers, + IASetInputLayout, + IASetVertexBuffers, + IASetIndexBuffer, + DrawIndexedInstanced, + DrawInstanced, + GSSetConstantBuffers, + GSSetShader, + IASetPrimitiveTopology, + VSSetShaderResources, + VSSetSamplers, + SetPredication, + GSSetShaderResources, + GSSetSamplers, + OMSetRenderTargets, + OMSetBlendState, + OMSetDepthStencilState, + SOSetTargets, + DrawAuto, + RSSetState, + RSSetViewports, + RSSetScissorRects, + CopySubresourceRegion, + CopyResource, + UpdateSubresource, + ClearRenderTargetView, + ClearDepthStencilView, + GenerateMips, + ResolveSubresource, + VSGetConstantBuffers, + PSGetShaderResources, + PSGetShader, + PSGetSamplers, + VSGetShader, + PSGetConstantBuffers, + IAGetInputLayout, + IAGetVertexBuffers, + IAGetIndexBuffer, + GSGetConstantBuffers, + GSGetShader, + IAGetPrimitiveTopology, + VSGetShaderResources, + VSGetSamplers, + GetPredication, + GSGetShaderResources, + GSGetSamplers, + OMGetRenderTargets, + OMGetBlendState, + OMGetDepthStencilState, + SOGetTargets, + RSGetState, + RSGetViewports, + RSGetScissorRects, + GetDeviceRemovedReason, + SetExceptionMode, + GetExceptionMode, + GetPrivateData, + SetPrivateData, + SetPrivateDataInterface, + ClearState, + Flush, + CreateBuffer, + CreateTexture1D, + CreateTexture2D, + CreateTexture3D, + CreateShaderResourceView, + CreateRenderTargetView, + CreateDepthStencilView, + CreateInputLayout, + CreateVertexShader, + CreateGeometryShader, + CreateGeometryShaderWithStreamOutput, + CreatePixelShader, + CreateBlendState, + CreateDepthStencilState, + CreateRasterizerState, + CreateSamplerState, + CreateQuery, + CreatePredicate, + CreateCounter, + CheckFormatSupport, + CheckMultisampleQualityLevels, + CheckCounterInfo, + CheckCounter, + GetCreationFlags, + OpenSharedResource, + SetTextFilterSize, + GetTextFilterSize, +}; + +enum class IDirect3DDevice9VTable +{ + // IUnknown + QueryInterface, + AddRef, + Release, + + // IDirect3DDevice9 + TestCooperativeLevel, + GetAvailableTextureMem, + EvictManagedResources, + GetDirect3D, + GetDeviceCaps, + GetDisplayMode, + GetCreationParameters, + SetCursorProperties, + SetCursorPosition, + ShowCursor, + CreateAdditionalSwapChain, + GetSwapChain, + GetNumberOfSwapChains, + Reset, + Present, + GetBackBuffer, + GetRasterStatus, + SetDialogBoxMode, + SetGammaRamp, + GetGammaRamp, + CreateTexture, + CreateVolumeTexture, + CreateCubeTexture, + CreateVertexBuffer, + CreateIndexBuffer, + CreateRenderTarget, + CreateDepthStencilSurface, + UpdateSurface, + UpdateTexture, + GetRenderTargetData, + GetFrontBufferData, + StretchRect, + ColorFill, + CreateOffscreenPlainSurface, + SetRenderTarget, + GetRenderTarget, + SetDepthStencilSurface, + GetDepthStencilSurface, + BeginScene, + EndScene, + Clear, + SetTransform, + GetTransform, + MultiplyTransform, + SetViewport, + GetViewport, + SetMaterial, + GetMaterial, + SetLight, + GetLight, + LightEnable, + GetLightEnable, + SetClipPlane, + GetClipPlane, + SetRenderState, + GetRenderState, + CreateStateBlock, + BeginStateBlock, + EndStateBlock, + SetClipStatus, + GetClipStatus, + GetTexture, + SetTexture, + GetTextureStageState, + SetTextureStageState, + GetSamplerState, + SetSamplerState, + ValidateDevice, + SetPaletteEntries, + GetPaletteEntries, + SetCurrentTexturePalette, + GetCurrentTexturePalette, + SetScissorRect, + GetScissorRect, + SetSoftwareVertexProcessing, + GetSoftwareVertexProcessing, + SetNPatchMode, + GetNPatchMode, + DrawPrimitive, + DrawIndexedPrimitive, + DrawPrimitiveUP, + DrawIndexedPrimitiveUP, + ProcessVertices, + CreateVertexDeclaration, + SetVertexDeclaration, + GetVertexDeclaration, + SetFVF, + GetFVF, + CreateVertexShader, + SetVertexShader, + GetVertexShader, + SetVertexShaderConstantF, + GetVertexShaderConstantF, + SetVertexShaderConstantI, + GetVertexShaderConstantI, + SetVertexShaderConstantB, + GetVertexShaderConstantB, + SetStreamSource, + GetStreamSource, + SetStreamSourceFreq, + GetStreamSourceFreq, + SetIndices, + GetIndices, + CreatePixelShader, + SetPixelShader, + GetPixelShader, + SetPixelShaderConstantF, + GetPixelShaderConstantF, + SetPixelShaderConstantI, + GetPixelShaderConstantI, + SetPixelShaderConstantB, + GetPixelShaderConstantB, + DrawRectPatch, + DrawTriPatch, + DeletePatch, + CreateQuery, + + // IDirect3DDevice9Ex + SetConvolutionMonoKernel, + ComposeRects, + PresentEx, + GetGPUThreadPriority, + SetGPUThreadPriority, + WaitForVBlank, + CheckResourceResidency, + SetMaximumFrameLatency, + GetMaximumFrameLatency, + CheckDeviceState, + CreateRenderTargetEx, + CreateOffscreenPlainSurfaceEx, + CreateDepthStencilSurfaceEx, + ResetEx, + GetDisplayModeEx, +}; diff --git a/overlay_experimental/Hook_Manager.cpp b/overlay_experimental/Hook_Manager.cpp new file mode 100644 index 0000000..d3d2d9c --- /dev/null +++ b/overlay_experimental/Hook_Manager.cpp @@ -0,0 +1,178 @@ +#include "../dll/dll.h" +#include "Hook_Manager.h" + +#include "../detours/detours.h" + +#include "DX12_Hook.h" +#include "DX11_Hook.h" +#include "DX10_Hook.h" +#include "DX9_Hook.h" + +#include + +decltype(LoadLibraryA )* _LoadLibraryA = LoadLibraryA; +decltype(LoadLibraryW )* _LoadLibraryW = LoadLibraryW; +decltype(LoadLibraryExA )* _LoadLibraryExA = LoadLibraryExA; +decltype(LoadLibraryExW )* _LoadLibraryExW = LoadLibraryExW; + +void create_hookA(const char* libname) +{ + if (!strcmp(libname, "d3d9.dll")) + DX9_Hook::Create(); + else if (!strcmp(libname, "d3d10.dll")) + DX10_Hook::Create(); + else if (!strcmp(libname, "d3d11.dll")) + DX11_Hook::Create(); + else if (!strcmp(libname, "d3d12.dll")) + DX12_Hook::Create(); +} + +void create_hookW(const wchar_t *libname) +{ + if (!wcscmp(libname, L"d3d9.dll")) + DX9_Hook::Create(); + else if (!wcscmp(libname, L"d3d10.dll")) + DX10_Hook::Create(); + else if (!wcscmp(libname, L"d3d11.dll")) + DX11_Hook::Create(); + else if (!wcscmp(libname, L"d3d12.dll")) + DX12_Hook::Create(); +} + +HMODULE WINAPI mLoadLibraryA(LPCTSTR lpLibFileName) +{ + auto res = _LoadLibraryA(lpLibFileName); + create_hookA(lpLibFileName); + return res; +} + +HMODULE WINAPI mLoadLibraryW(LPCWSTR lpLibFileName) +{ + auto res = _LoadLibraryW(lpLibFileName); + create_hookW(lpLibFileName); + return res; +} + +HMODULE WINAPI mLoadLibraryExA(LPCTSTR lpLibFileName, HANDLE hFile, DWORD dwFlags) +{ + auto res = _LoadLibraryA(lpLibFileName); + create_hookA(lpLibFileName); + return res; +} + +HMODULE WINAPI mLoadLibraryExW(LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags) +{ + auto res = _LoadLibraryExW(lpLibFileName, hFile, dwFlags); + create_hookW(lpLibFileName); + return res; +} + +Hook_Manager::Hook_Manager(): + _isSet(false), + _LoadLibraryHooked(false) +{} + +Hook_Manager::~Hook_Manager() +{ + for (auto& i : _hooks) + delete i; +} + +Hook_Manager& Hook_Manager::Inst() +{ + static Hook_Manager hook; + return hook; +} + +void Hook_Manager::HookRenderer(Steam_Overlay *ovlay) +{ + overlay = ovlay; + HookLoadLibrary(); + std::vector const libraries = { "d3d12.dll", "d3d11.dll", "d3d10.dll", "d3d9.dll" }; + std::vector::const_iterator it = libraries.begin(); + while (it != libraries.end()) + { + it = std::find_if(it, libraries.end(), [](std::string const& name) { + auto x = GetModuleHandle(name.c_str()); + if (x != 0 && x != INVALID_HANDLE_VALUE) + return true; + return false; + }); + + if (it == libraries.end()) + break; + + if (*it == "d3d9.dll") + DX9_Hook::Create(); + else if (*it == "d3d10.dll") + DX10_Hook::Create(); + else if (*it == "d3d11.dll") + DX11_Hook::Create(); + else if (*it == "d3d12.dll") + DX12_Hook::Create(); + + ++it; + } +} + +void Hook_Manager::UnHookLoadLibrary() +{ + _LoadLibraryHooked = false; + DetourTransactionBegin(); + DetourUpdateThread(GetCurrentThread()); + + DetourDetach((PVOID*)& _LoadLibraryA, mLoadLibraryA); + DetourDetach((PVOID*)& _LoadLibraryW, mLoadLibraryW); + DetourDetach((PVOID*)& _LoadLibraryExA, mLoadLibraryExA); + DetourDetach((PVOID*)& _LoadLibraryExW, mLoadLibraryExW); + + DetourTransactionCommit(); +} + +void Hook_Manager::HookLoadLibrary() +{ + if (!_isSet && !_LoadLibraryHooked) + { + _LoadLibraryHooked = true; + + DetourTransactionBegin(); + DetourUpdateThread(GetCurrentThread()); + + DetourAttach((PVOID*)& _LoadLibraryA, mLoadLibraryA); + DetourAttach((PVOID*)& _LoadLibraryW, mLoadLibraryW); + DetourAttach((PVOID*)& _LoadLibraryExA, mLoadLibraryExA); + DetourAttach((PVOID*)& _LoadLibraryExW, mLoadLibraryExW); + + DetourTransactionCommit(); + } +} + +void Hook_Manager::FoundHook(Base_Hook* hook) +{ + if (!_isSet) + { + _isSet = true; + + UnHookLoadLibrary(); + + // Remove all hooks that are unused + _hooks.erase(std::remove_if(_hooks.begin(), _hooks.end(), [&hook](Base_Hook* it_hook) { + if (hook != it_hook) + { + delete it_hook; + return true; + } + return false; + }), _hooks.end()); + } +} + +void Hook_Manager::ChangeGameWindow(HWND hWnd) const +{ + overlay->HookReady(hWnd); +} + +void Hook_Manager::CallOverlayProc(int width, int height) const +{ + overlay->OverlayProc(width, height); +} \ No newline at end of file diff --git a/overlay_experimental/Hook_Manager.h b/overlay_experimental/Hook_Manager.h new file mode 100644 index 0000000..5451d78 --- /dev/null +++ b/overlay_experimental/Hook_Manager.h @@ -0,0 +1,46 @@ +#ifndef __INCLUDED_HOOK_BASE_H__ +#define __INCLUDED_HOOK_BASE_H__ + +#include +#include +#include "Base_Hook.h" + +class Hook_Manager +{ + friend class Base_Hook; +public: + using overlayProc_t = void(*)(int,int); + using hookReady_t = void(*)(void*); + +protected: + std::vector _hooks; + + WNDPROC _gameWndProc; // The game main windows proc + HWND _gameHWnd; // The game main window + bool _showOverlay; // Should we render the overlay + bool _isSet; // Is the renderer hooked ? + bool _LoadLibraryHooked; // Are the LoadLibrary functions hooked ? + class Steam_Overlay* overlay; + + Hook_Manager(); + virtual ~Hook_Manager(); + + void HookLoadLibrary(); + void UnHookLoadLibrary(); + +public: + static Hook_Manager& Inst(); + + void HookRenderer(Steam_Overlay *overlay); + + // Set the found hook and free all other hooks + void FoundHook(Base_Hook *hook); + + inline void AddHook(Base_Hook* hook) { _hooks.push_back(hook); } + void ChangeGameWindow(HWND hWnd) const; + void CallOverlayProc(int width, int height) const; + Steam_Overlay* GetOverlay() const { return overlay; } +}; + + +#endif//__INCLUDED_HOOK_BASE_H__ \ No newline at end of file