This is a D3D11 Present x64 trampoline hook project I was just working with. You can draw inside hkPresent()
before returning and whatever you draw will show up on the screen.
#include <Windows.h>
#include <d3d11.h>
#include <d3dcompiler.h>
#include <DirectXMath.h>
#pragma comment(lib, "d3d11.lib")
#pragma comment(lib, "d3dcompiler.lib")
#define SAFE_RELEASE(p) if (p) { p->Release(); p = nullptr; }
void* Tramp64(void* src, void* dst, int len)
{
int MinLen = 14;
if (len < MinLen) return NULL;
BYTE stub[] = {
0xFF, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp qword ptr [$+6]
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // ptr
};
void* pTrampoline = VirtualAlloc(0, len + sizeof(stub), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
DWORD dwOld = 0;
VirtualProtect(src, len, PAGE_EXECUTE_READWRITE, &dwOld);
uintptr_t retto = (uintptr_t)src + len;
// trampoline
memcpy(stub + 6, &retto, 8);
memcpy((void*)((uintptr_t)pTrampoline), src, len);
memcpy((void*)((uintptr_t)pTrampoline + len), stub, sizeof(stub));
// orig
memcpy(stub + 6, &dst, 8);
memcpy(src, stub, sizeof(stub));
for (int i = MinLen; i < len; i++)
{
*(BYTE*)((uintptr_t)src + i) = 0x90;
}
VirtualProtect(src, len, dwOld, &dwOld);
return (void*)((uintptr_t)pTrampoline);
}
bool GetD3D11SwapchainDeviceContext(void** pSwapchainTable, size_t Size_Swapchain, void** pDeviceTable, size_t Size_Device, void** pContextTable, size_t Size_Context)
{
WNDCLASSEX wc{ 0 };
wc.cbSize = sizeof(wc);
wc.lpfnWndProc = DefWindowProc;
wc.lpszClassName = TEXT("dummy class");
if (!RegisterClassEx(&wc))
{
return false;
}
DXGI_SWAP_CHAIN_DESC swapChainDesc{ 0 };
swapChainDesc.BufferCount = 1;
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
swapChainDesc.OutputWindow = GetForegroundWindow();
swapChainDesc.SampleDesc.Count = 1;
swapChainDesc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
swapChainDesc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
swapChainDesc.Windowed = TRUE;
D3D_FEATURE_LEVEL featureLevel;
IDXGISwapChain* pDummySwapChain = nullptr;
ID3D11Device* pDummyDevice = nullptr;
ID3D11DeviceContext* pDummyContext = nullptr;
HRESULT hr = D3D11CreateDeviceAndSwapChain(nullptr, D3D_DRIVER_TYPE_REFERENCE, nullptr, 0, nullptr, 0, D3D11_SDK_VERSION, &swapChainDesc, &pDummySwapChain, &pDummyDevice, &featureLevel, nullptr);
if (FAILED(hr))
{
DestroyWindow(swapChainDesc.OutputWindow);
UnregisterClass(wc.lpszClassName, GetModuleHandle(nullptr));
return false;
}
if (pSwapchainTable && pDummySwapChain)
{
memcpy(pSwapchainTable, *reinterpret_cast<void***>(pDummySwapChain), Size_Swapchain);
}
if (pDeviceTable && pDummyDevice)
{
memcpy(pDeviceTable, *reinterpret_cast<void***>(pDummyDevice), Size_Device);
}
if (pContextTable && pDummyContext)
{
memcpy(pContextTable, *reinterpret_cast<void***>(pDummyContext), Size_Context);
}
SAFE_RELEASE(pDummySwapChain);
SAFE_RELEASE(pDummyDevice);
SAFE_RELEASE(pDummyContext);
DestroyWindow(swapChainDesc.OutputWindow);
UnregisterClass(wc.lpszClassName, GetModuleHandle(nullptr));
return true;
}
void* SwapChain[18];
void* Device[40];
void* Context[108];
typedef HRESULT(__fastcall* tPresent)(IDXGISwapChain* pThis, UINT SyncInterval, UINT Flags);
tPresent oPresent = nullptr;
HRESULT __fastcall hkPresent(IDXGISwapChain* pThis, UINT SyncInterval, UINT Flags)
{
return oPresent(pThis, SyncInterval, Flags);
}
DWORD WINAPI MainThread(HMODULE hModule)
{
if (GetD3D11SwapchainDeviceContext(SwapChain, sizeof(SwapChain), Device, sizeof(Device), Context, sizeof(Context)))
{
oPresent = (tPresent)Tramp64(SwapChain[8], hkPresent, 19);
}
return 0;
}
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
CreateThread(nullptr, 0, (LPTHREAD_START_ROUTINE)MainThread, hModule, 0, nullptr);
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
This is a combination of code from several people: me, Broihon, Traxin & A200K