Source Code DirectX11 - How to Hook Direct3D11 & Draw Template

Hexui Undetected CSGO Cheats Sinkicheat PUBG Cheat

Rake

I'm not your friend
Administrator
Jan 21, 2014
12,497
78,998
2,417
How long you been coding/hacking?
7 years
This D3D11 Hook project will hook the DirectX11 Present Function and allow you to draw lines and boxes very easily. It is setup 100% ready to inject into any Direct3D11 x64 game and will perform a test render of one line and one box on the screen. Once you have tested it working, you can simply add ESP code to it. This project does not use DirectX-TK and it does not use deprecated Direct3D Extension libraries but it does use the newer DirectXMath library. I tried to avoid using anything from D3D9 and focus on newer D3D11 functions and structures only, this project does not use any D3D9 header files.

This is a project I was working on for a while. I was basing it off this project from Traxin -> Source Code - D3D11 Barebones hook PoC. His project works great but I thought I could make some improvements for it to be more accessible and easy to read / use by noobs.

I wanted to continue to develop this Direct3D11 Hook and make it even nicer but I think I'm done with it for the time being. Video tutorial to come in a few months showing how to make this.

You can very easily make an internal ESP like this using this template project:
1596838972449.png


DirectX11 - How to Hook Direct3D11 & Draw Template
  • 100% ready to inject into any x64 D3D11 game, Tested on SWBF2
  • Can draw lines and boxes for ESP
  • Includes my screenshot cleaner and is capable of hooking x86 and x64
  • Does not use a disassembler, if stolen bytes include a relative address it won't work
  • Includes everything you need to make an ESP, just add an ESP function and you're good to go
  • Includes WorldToScreen functions, Vec3 class, memory hacking & hooking functions
  • Based off my code from my tutorials so it should be accessible to those who completed the GHB
  • Includes my little logger class, a hook class and allows easy unhook and ejection of the DLL
  • Uses @Broihon's D3D11 dummy device function
When I started working on this project, I was trying to give Traxin's code a facelift but I ended up getting really confused and had to head over to DirectXTutorial.com for a couple weeks to learn everything about DirectX11 from scratch. Now I feel like I have a really good handle on it. Thank you to @mambda, @Traxin, @timb3r & @XdarionX for helping me with some issues I had.

I took Traxin's code and I separated it all out into individual function and removed any redundant or unnecessary code.

The D3D11 class contains these functions:
  • HookD3D() -> Hook Present()
  • DummyDeviceGetPresent() -> Get the address of Present so we can hook it
  • CompileShaders() -> compile pixel & vertex shader (part of the transformation pipeline)
  • GetViewport() -> Grab the game's viewport, if that fails create one automatically
  • SetupOrtho() -> Create a proper XMMatrixOrthographicOffCenterLH view matrix for orthographic 2D drawing
  • GetDeviceContextRenderTarget - > Duh
  • InitD3DDraw() -> This is just a wrapper around the 4 functions above, this is all you have to call inside your hook
  • BeginDraw() -> not necessary with current code, but could be used to remove overhead from draw functions
  • DrawLine()
  • DrawBox()
  • TestRender() -> useful for testing your viewport and ortho matrix, draws diagonally in 4 directions
  • CleanupD3D() -> cleanup after you unhook
  • Unhook()
Basic Idea of How to get setup to draw in D3D11:
  1. Use Dummy device method to get address of DXGI:present()
  2. Trampoline hook it, then inside your hook:
  3. Make a copy of the pDeviice & pSwapChain
  4. Get the device context with GetImmediateContext() & OMGetRenderTargets()
  5. Compile your vertex & pixel shader using D3DCompile
  6. GetViewport using pContext->RSGetViewports()
  7. if that fails, create your own using data returned by GetClientRect()
  8. Create a orthographic projection matrix using XMMatrixOrthographicOffCenterLH
Basic Idea of How to draw a line after you're setup:
  1. Setup your vertex array buffer
  2. Create a buffer in D3D with pDevice->CreateBuffer
  3. Set your constant buffer with your Ortho matrix with VSSetConstantBuffers()
  4. Set D3D to use your vertex buffer with IASetVertexBuffers()
  5. Set your input vertex buffer layout with IASetInputLayout()
  6. Set your primitive type with IASetPrimitiveTopology() for a line just use D3D11_PRIMITIVE_TOPOLOGY_LINELIST
  7. Tell D3D to use your vertex and pixel shader with VSSetShader() & PSSetShader()
  8. Set your viewport with RSSetViewports()
  9. call the draw function: pContext->Draw(2, 0)
Problems I ran into and things to be aware of

#1 This project works great, do not modify it, you will only screw it up and feel stupid. You must know how every single part of D3D11 works to correctly modify this code.

Orthographic Projection Matrix Problems

You must use XMMatrixOrthographicOffCenterLH and use it correctly. It's not intuitive. Your call must look like this:
C++:
 mOrtho = DirectX::XMMatrixOrthographicOffCenterLH(0, myViewport.Width, myViewport.Height, 0, 0.0f, 1.0f);
By doing it like this, 0,0 is the top left, x increases as you go right and Y increases as you go down. This is how you must be setup if you want to draw correctly.

Vertex Shader Problems
C++:
PSI VS( float4 pos : POSITION, float4 color : COLOR )
{
    PSI psi;
    psi.pos = mul( projection, pos  );
    psi.color = color;
    return psi;
}
This is part of the transformation pipeline, every vertex gets multiplied by the orthographic projection matrix at this stage. It must be multiplied in this order, if you don't it will not work.

Vertex Input Layout
This must be perfect or you will not have any fun. This tells Direct3D 11 what format your vertices are using. It's setup with a vertex defined as a 3 floats defining position and and 4 floats defining the color, which includes an alpha value.

C++:
struct Vertex
{
    DirectX::XMFLOAT3 pos;
    D3DCOLORVALUE color;
};

D3D11_INPUT_ELEMENT_DESC layout[2] = {
    {"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0},
    {"COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0}
};
UINT numElements = ARRAYSIZE(layout);

Full source code can be found in the attachments, but I will just show some portions of the code off here

DLLMain Sample Source Code

C++:
rD3D11 rd11;

bool bDrawingEnabled = false;

SShotCleaner sshotCleaner(L"Star Wars Battlefront II", &bDrawingEnabled);

DWORD WINAPI MainThread(HINSTANCE hModule)
{
    if (rd11.HookD3D())
    {
        if (sshotCleaner.Init())
            sshotCleaner.Enable();

        while (true)
        {
            Sleep(20);

            //Test cleaning the screenshots
            if (GetAsyncKeyState(VK_NUMPAD9) & 1)
                sshotCleaner.SaveTestScreenshot(FindWindow(NULL, sshotCleaner.gameWindowTitle.c_str()));

            if (GetAsyncKeyState(VK_END) & 1)
                break;
        }
    }

    sshotCleaner.Disable();
    rd11.UnHook();
    Sleep(500);
    FreeLibraryAndExitThread(hModule, 0);
    return 0;
}

HRESULT __stdcall hkPresent(IDXGISwapChain* pThis, UINT SyncInterval, UINT Flags)
{
    if (!rd11.pDevice || rd11.pSwapchain != pThis)
    {
        rd11.InitD3DDraw(pThis);
    }

    //enable this to test or debug viewport
    rd11.TestRender();

    return rd11.oPresentTramp(pThis, SyncInterval, Flags);
}

BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved)
{
    switch (fdwReason)
    {
    case DLL_PROCESS_ATTACH:
        DisableThreadLibraryCalls(hinstDLL);
        CreateThread(nullptr, 0, (LPTHREAD_START_ROUTINE)MainThread, hinstDLL, 0, nullptr);
        break;
    case DLL_PROCESS_DETACH:

        break;
    }
    return TRUE;
}
rD3D11.h Source Code
C++:
#include <d3d11.h>
#include <d3dcompiler.h>
#include <DirectXMath.h>
#include <DirectXColors.h> // color https://github.com/microsoft/DirectXMath/
#include "shader.h"
#include "rD3D11_VMT_Indices.h"
#include "util.h"
#include "rD3D11helpers.h"
#include "hook.h"

#pragma comment(lib, "d3d11.lib")
#pragma comment(lib, "d3dcompiler.lib")

HRESULT __stdcall hkPresent(IDXGISwapChain* pThis, UINT SyncInterval, UINT Flags);

class rD3D11;

class rD3D11
{
public:
    ID3D11Device* pDevice = nullptr;
    IDXGISwapChain* pSwapchain = nullptr;
    ID3D11DeviceContext* pContext = nullptr;
    ID3D11RenderTargetView* pRenderTargetView = nullptr;
    ID3D11VertexShader* pVertexShader = nullptr;
    ID3D11InputLayout* pVertexLayout = nullptr;
    ID3D11PixelShader* pPixelShader = nullptr;
    ID3D11Buffer* pVertexBuffer = nullptr;
    ID3D11Buffer* pIndexBuffer = nullptr;
    ID3D11Buffer* pConstantBuffer = nullptr;

    HWND hWnd;
    RECT windowRect;

    D3D11_VIEWPORT pViewports[D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE]{ 0 };
    D3D11_VIEWPORT myViewport;
    DirectX::XMMATRIX mOrtho;

    Hook presentHook;

    //hook stuff
    using fnPresent = HRESULT(__stdcall*)(IDXGISwapChain* pThis, UINT SyncInterval, UINT Flags);
    void* oPresent;                    // Pointer to the original Present function
    fnPresent oPresentTramp;        // Pointer to our trampoline

    bool DummyDeviceGetPresent();
    bool HookD3D();
    bool CompileShader(const char* szShader, const char* szEntrypoint, const char* szTarget, ID3D10Blob** pBlob);

    //These are all executed inside InitD3Draw()
    bool GetDeviceContextRenderTarget(IDXGISwapChain* pSwapchain);
    bool CompilerShaders();
    bool GetViewport();
    bool SetupOrtho();

    bool InitD3DDraw(IDXGISwapChain* pSwapchain); //call this inside the Present() hook

    void BeginDraw();
    void DrawLine(float x, float y, float x2, float y2, D3DCOLORVALUE color);
    void DrawLineWH(float x, float y, float width, float height, D3DCOLORVALUE color); //uses 1 vertex + width and height
    void DrawBox(float x, float y, float width, float height, D3DCOLORVALUE color);
    void TestRender();

    void CleanupD3D();
    void UnHook();

    ~rD3D11();
};
D3D11 Draw Line
C++:
void rD3D11::DrawLine(float x, float y, float x2, float y2, D3DCOLORVALUE color)
{
    // Setup vertices
    Vertex pVerts[2] = {
    { DirectX::XMFLOAT3(x, y, 1.0f),        color },
    { DirectX::XMFLOAT3(x2, y2, 1.0f),    color },
    };

    D3D11_BUFFER_DESC buffer_desc_line{ 0 };
    buffer_desc_line.BindFlags = D3D11_BIND_INDEX_BUFFER;
    buffer_desc_line.ByteWidth = sizeof(Vertex) * 2;
    buffer_desc_line.Usage = D3D11_USAGE_DEFAULT;

    D3D11_SUBRESOURCE_DATA subresource_line{ 0 };
    subresource_line.pSysMem = &pVerts;

    pDevice->CreateBuffer(&buffer_desc_line, &subresource_line, &pVertexBuffer);

    pContext->VSSetConstantBuffers(0, 1, &pConstantBuffer);// we do this in init

    // Make sure the input assembler knows how to process our verts/indices
    UINT stride = sizeof(Vertex);
    UINT offset = 0;

    pContext->IASetVertexBuffers(0, 1, &pVertexBuffer, &stride, &offset);
    pContext->IASetInputLayout(pVertexLayout);
    pContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_LINELIST);

    // Set the shaders we need to render our line
    pContext->VSSetShader(pVertexShader, nullptr, 0);
    pContext->PSSetShader(pPixelShader, nullptr, 0);

    // Set viewport to context, unnecessary as we're using the games
    //pContext->OMSetRenderTargets(1, &pRenderTargetView, nullptr);

    pContext->RSSetViewports(1, &myViewport); //not required, it's already set in the game's context

    //In all cases, Width and Height must be positive

    pContext->Draw(2, 0);
}
D3D11 Draw Rectangle ESP Box
C++:
void rD3D11::DrawBox(float x, float y, float width, float height, D3DCOLORVALUE color)
{
    // Setup vertices TL, TR, BR, BL

    Vertex pVerts[5] = {
        { DirectX::XMFLOAT3(x,            y,            1.0f),        color },
        { DirectX::XMFLOAT3(x + width,    y,            1.0f),        color },
        { DirectX::XMFLOAT3(x + width,    y + height, 1.0f),        color },
        { DirectX::XMFLOAT3(x,            y + height, 1.0f),        color },
        { DirectX::XMFLOAT3(x,            y,            1.0f),        color }
    };

    D3D11_BUFFER_DESC buffer_desc_line{ 0 };
    buffer_desc_line.BindFlags = D3D11_BIND_INDEX_BUFFER;
    buffer_desc_line.ByteWidth = sizeof(Vertex) * 5;
    buffer_desc_line.Usage = D3D11_USAGE_DEFAULT;

    D3D11_SUBRESOURCE_DATA subresource_line{ 0 };
    subresource_line.pSysMem = &pVerts;

    pDevice->CreateBuffer(&buffer_desc_line, &subresource_line, &pVertexBuffer);

    pContext->VSSetConstantBuffers(0, 1, &pConstantBuffer);

    // Make sure the input assembler knows how to process our verts/indices
    UINT stride = sizeof(Vertex);
    UINT offset = 0;

    pContext->IASetVertexBuffers(0, 1, &pVertexBuffer, &stride, &offset);
    pContext->IASetInputLayout(pVertexLayout);
    pContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP);

    // Set the shaders we need to render our line
    pContext->VSSetShader(pVertexShader, nullptr, 0);
    pContext->PSSetShader(pPixelShader, nullptr, 0);

    // Set viewport to context, unnecessary so far?
    //pContext->OMSetRenderTargets(1, &pRenderTargetView, nullptr);

    pContext->RSSetViewports(1, &myViewport);

    pContext->Draw(5, 0);
}
Direct3D11 Get DeviceContext and Render Target
C++:
bool rD3D11::GetDeviceContextRenderTarget(IDXGISwapChain* pSwapchain)
{
    //Get the device, context and render target
    HRESULT hr = pSwapchain->GetDevice(__uuidof(ID3D11Device), (void**)&pDevice);
    if (FAILED(hr))
        return false;

    pDevice->GetImmediateContext(&pContext);
    pContext->OMGetRenderTargets(1, &pRenderTargetView, nullptr);

    // If for some reason we fail to get a render target, create one.
    if (!pRenderTargetView)
    {
        // Get a pointer to the back buffer for the render target view
        ID3D11Texture2D* pBackbuffer = nullptr;
        hr = pSwapchain->GetBuffer(0, __uuidof(ID3D11Texture2D), reinterpret_cast<void**>(&pBackbuffer));
        if (FAILED(hr))
            return false;

        // Create render target view
        hr = pDevice->CreateRenderTargetView(pBackbuffer, nullptr, &pRenderTargetView);
        pBackbuffer->Release();
        if (FAILED(hr))
            return false;

        // Make sure our render target is set, only needed if creating our own, if it already exists just use the original
        pContext->OMSetRenderTargets(1, &pRenderTargetView, nullptr);
    }
    return true;
}
Direct3D 11 Compile Shaders
C++:
bool rD3D11::CompileShader(const char* szShader, const char* szEntrypoint, const char* szTarget, ID3D10Blob** pCompiledShaderBlob)
{
    ID3D10Blob* pErrorBlob = nullptr;

    auto hr = D3DCompile(szShader, strlen(szShader), 0, nullptr, nullptr, szEntrypoint, szTarget, D3DCOMPILE_ENABLE_STRICTNESS, 0, pCompiledShaderBlob, &pErrorBlob);
    if (FAILED(hr))
    {
        if (pErrorBlob)
        {
            char szError[256]{ 0 };
            memcpy(szError, pErrorBlob->GetBufferPointer(), pErrorBlob->GetBufferSize());
            MessageBoxA(nullptr, szError, "Error", MB_OK);
        }
        return false;
    }
    return true;
}

bool rD3D11::CompilerShaders()
{
    ID3D10Blob* pCompiledShaderBlob = nullptr;

    // create vertex shader
    if (!CompileShader(shader, "VS", "vs_5_0", &pCompiledShaderBlob))
        return false;

    HRESULT hr = pDevice->CreateVertexShader(pCompiledShaderBlob->GetBufferPointer(), pCompiledShaderBlob->GetBufferSize(), nullptr, &pVertexShader);
    if (FAILED(hr))
        return false;

    // Define/create the input layout for the vertex shader
    D3D11_INPUT_ELEMENT_DESC layout[2] = {
    {"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0},
    {"COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0}
    };
    UINT numElements = ARRAYSIZE(layout);

    hr = pDevice->CreateInputLayout(layout, numElements, pCompiledShaderBlob->GetBufferPointer(), pCompiledShaderBlob->GetBufferSize(), &pVertexLayout);
    if (FAILED(hr))
        return false;

    pContext->IASetInputLayout(pVertexLayout); //unnecesary for whatever reason, call it anyways

    safe_release(pCompiledShaderBlob);

    // create pixel shader
    if (!CompileShader(shader, "PS", "ps_5_0", &pCompiledShaderBlob))
        return false;

    hr = pDevice->CreatePixelShader(pCompiledShaderBlob->GetBufferPointer(), pCompiledShaderBlob->GetBufferSize(), nullptr, &pPixelShader);
    if (FAILED(hr))
        return false;

    return true;
}
D3D11 Get Viewport Source Code
C++:
bool rD3D11::GetViewport()
{
    UINT numViewports = D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE;

    // Apparently this isn't universal. Works on most games
    pContext->RSGetViewports(&numViewports, pViewports);

    //if it doesn't work, make your own
    if (!numViewports || !pViewports[0].Width)
    {
        hWnd = FindMainWindow(GetCurrentProcessId());

        if (!GetClientRect(hWnd, &windowRect))
            return false;
        // Setup viewport
        myViewport.Width = windowRect.right;
        myViewport.Height = windowRect.bottom;
        myViewport.TopLeftX = windowRect.left;
        myViewport.TopLeftY = windowRect.top;
        myViewport.MinDepth = 0.0f;
        myViewport.MaxDepth = 1.0f;
        pContext->RSSetViewports(1, &myViewport);
    }
    else
    {
        myViewport = pViewports[0];
        pContext->RSSetViewports(1, &myViewport);
    }
    return true;
}
DirectX 11 Setup Ortho function
C++:
bool rD3D11::SetupOrtho()
{
    //if you don't do offcenter, 0,0 is middle of screen, that's "normal" but we want 0,0 as top left
    // good info: https://www.gamedev.net/forums/topic/671157-dx11-changing-window-coordinate-origin-upper-left-62-lower-left/5248351/
    //https://gamedev.stackexchange.com/questions/66707/directx-11-problem-positioning-a-2d-quad-center-starting-at-bottom-left-and

    mOrtho = DirectX::XMMatrixOrthographicOffCenterLH(0, myViewport.Width, myViewport.Height, 0, 0.0f, 1.0f);

    // Create the constant buffer, this includes our ortho matrix which the vertex shader uses
    D3D11_BUFFER_DESC buffer_desc{ 0 };
    buffer_desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
    buffer_desc.ByteWidth = sizeof(mOrtho);
    buffer_desc.Usage = D3D11_USAGE_DEFAULT;

    D3D11_SUBRESOURCE_DATA subresource_line{ 0 };
    subresource_line.pSysMem = &mOrtho;
    HRESULT hr = pDevice->CreateBuffer(&buffer_desc, &subresource_line, &pConstantBuffer);
    if (FAILED(hr))
        return false;

    pContext->VSSetConstantBuffers(0, 1, &pConstantBuffer);

    return true;
}
InitD3DDraw()
C++:
bool rD3D11::InitD3DDraw(IDXGISwapChain* pSwapchain)
{
    this->pSwapchain = pSwapchain;

    if (!GetDeviceContextRenderTarget(pSwapchain)) return false;

    if (!CompilerShaders()) return false;

    if (!GetViewport()) return false;

    if (!SetupOrtho()) return false;

    return true;
}
D3D11 Dummy Device Get Present Address
C++:
bool rD3D11::DummyDeviceGetPresent()
{
    DXGI_SWAP_CHAIN_DESC sd{ 0 };
    sd.BufferCount = 1;
    sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
    sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
    sd.OutputWindow = GetDesktopWindow();
    sd.Windowed = TRUE;
    sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
    sd.SampleDesc.Count = 1;

    ID3D11Device* pDevice = nullptr; //local
    IDXGISwapChain* pSwapchain = nullptr;

    HRESULT hr = D3D11CreateDeviceAndSwapChain(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, 0, nullptr, 0, D3D11_SDK_VERSION, &sd, &pSwapchain, &pDevice, nullptr, nullptr);

    if (GetLastError() == 0x594) SetLastError(0); //ignore eror related to output window //TODO: fix this little issue with window handle

    if (FAILED(hr)) return false;

    void** pVMT = *(void***)pSwapchain;

    // Get Present's address out of vmt
    oPresent = (fnPresent)(pVMT[(UINT)IDXGISwapChainVMT::Present]);

    // got what we need, we can release device and swapchain now
    //safe_release(pSwapchain);
    safe_release(pDevice);

    return true;
}
Shader.h
C++:
constexpr const char* shader = R"(
// Constant buffer
cbuffer ConstantBuffer : register(b0)
{
    matrix projection;
}

// PSI (PixelShaderInput)
struct PSI
{
    float4 pos : SV_POSITION;
    float4 color : COLOR;
};

// VertexShader
PSI VS( float4 pos : POSITION, float4 color : COLOR )
{
    PSI psi;
    psi.pos = mul( projection, pos  );
    psi.color = color;
    return psi;
}

// PixelShader
float4 PS(PSI psi) : SV_TARGET
{
    return psi.color;
}
)";
Associated Resources
 

Attachments

You can download 0 Attachments
Last edited:

timb3r

Semi-Retired
Dank Tier VIP
Jul 15, 2018
770
24,668
47
Sounds like the frostbite engine. For whatever reason I've not looked into it but if you use manual hooks the performance tanks on frostbite. If you use detours the performance will be improved.

This could be due to multiple thread synchronisation shinanigans or something like that but I've not cared enough to look into it.

Tldr: try using detours to see if the performance improves.
 

mambda

headass
Escobar Tier VIP
Trump Tier Donator
Jun 25, 2014
2,306
37,938
270
your hkPresent has an extra parameter (not_edx), so your SyncInterval is actually flags, which could cause different (slower) drawing approaches, likewise flags will be some random stuff from **r9
 
Last edited:

XdarionX

Dying Light Hacker
Dank Tier VIP
Trump Tier Donator
Dank Tier Donator
Mar 30, 2018
893
24,908
117
in x64 no such __stdcall exists, compiler automaticaly change all calling conventions to __fastcall (__thiscall is basically fastcall but first param is always pThis) and as mambda said you shuffled params, try this:
C++:
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);
}
and also CloseHandle(CreateThread(...)) to prevent handle leak
 

metrix

0x90
Meme Tier VIP
Fleep Tier Donator
Trump Tier Donator
Oct 11, 2013
243
6,918
12
So you fixed __fastcall and the wrong argument.
It's just a wild guess, but could you try to use references? I got the feeling it does copy for some reason. (beside SwapChain)
You must know that frostbite engine was mostly build in australia... you know... :D

C++:
HRESULT __fastcall hkPresent(IDXGISwapChain* pThis, UINT& SyncInterval, UINT& Flags)
{
    return oPresent(pThis, SyncInterval, Flags);
}
It's worth a try. But I don't see any real issue with your implementation overall.
 

Rake

I'm not your friend
Administrator
Jan 21, 2014
12,497
78,998
2,417
See Original Post at the top of the page for completed new project

Game: Star Wars Battlefront II x64

Fixed code here: Source Code - D3D11 X64 Present Hook

I'm doing a x64 trampoline hook after using the dummy device method shared by Broihon. The hook is working fine but my FPS drops from 80 down to 10 and I'm not even drawing anything.

Origin overlay and other overlays are all disabled. compiling in release mode

I assume Present is being called multiple times per frame, but I don't think that would cause such a large drop in FPS considering all I'm doing is 2 extra jmps.

I'm not doing any drawing:
C++:
HRESULT __stdcall hkPresent(IDXGISwapChain* pThis, void* not_edx, UINT SyncInterval, UINT Flags)
{
    return oPresent(pThis, SyncInterval, Flags);
}

Full code:

C++:
#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(__stdcall* tPresent)(IDXGISwapChain* pThis, UINT SyncInterval, UINT Flags);
tPresent oPresent = nullptr;

HRESULT __stdcall hkPresent(IDXGISwapChain* pThis, void* not_edx, 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;
}
Any ideas?

This game is nuts performance wise, just sitting in the menu it uses 75% of CPU and 90% of GPU and I have i7-9700k and GTX 1070, whack

So you fixed __fastcall and the wrong argument.
It's just a wild guess, but could you try to use references? I got the feeling it does copy for some reason. (beside SwapChain)
You must know that frostbite engine was mostly build in australia... you know... :D

C++:
HRESULT __fastcall hkPresent(IDXGISwapChain* pThis, UINT& SyncInterval, UINT& Flags)
{
    return oPresent(pThis, SyncInterval, Flags);
}
It's worth a try. But I don't see any real issue with your implementation overall.
thanks but it is fixed now, Visual Studio was not actually building the file, I had been injecting the same file over and over again, had to clean and rebuild to fix it, I have marked the solution
 
Last edited:
  • Haha
Reactions: metrix

Rake

I'm not your friend
Administrator
Jan 21, 2014
12,497
78,998
2,417
I have re-formatted this thread, see the OP

This is my D3D11 hook & drawing library I have been trying to release for the past month. Donate if you love me, I put a lot of effort into making this as easy to use as possible for all you idiots.
 

noobToken

Dank Tier Donator
Nov 28, 2019
4
322
0
I'm trying to use this for one game (path of exile), the hook is successful and the test render draws for 1 frame, but then it disappears. I tested and the hook was still up and running but it didn't render anything anymore.

How would I go about debugging this, do you have any idea?
 

noobToken

Dank Tier Donator
Nov 28, 2019
4
322
0
I'm trying to use this for one game (path of exile), the hook is successful and the test render draws for 1 frame, but then it disappears. I tested and the hook was still up and running but it didn't render anything anymore.

How would I go about debugging this, do you have any idea?
In the end I got the drawing to stay on the screen by commenting out these checks, but now it's crashing the game when unloading the dll. (Fixed the crashing by doing a check so we don't unload the dll when we're in InitD3Draw() or TestRenderer())


Comment out checks to make it work on Path of Exile:
HRESULT __stdcall hkPresent(IDXGISwapChain* pThis, UINT SyncInterval, UINT Flags)
{
    //if (!rd11.pDevice || rd11.pSwapchain != pThis)
    //{
        rd11.InitD3DDraw(pThis);
    //}

    //enable this to test or debug viewport
    rd11.TestRender();

    return rd11.oPresentTramp(pThis, SyncInterval, Flags);
}
 
Last edited:

Guppi

Dank Tier Donator
Oct 27, 2020
4
218
0
Hi! Im begginer and new here, just wanted to appreciate for work - very interesting content: Reverse Engineering, Low-level coding, Hooking, Bypassing. I have wanted to get to know all these things for a long time.

Also I guess I found mistyping in SshotCleaner.cpp file at line 94 and 117. There &BitBltTramp is casting into (BYTE*), but should be (uintptr_t*) to build library at x86 version. After changing this it works fine. Thank you for your source code.
1604676074065.png
 

Rake

I'm not your friend
Administrator
Jan 21, 2014
12,497
78,998
2,417
Hi! Im begginer and new here, just wanted to appreciate for work - very interesting content: Reverse Engineering, Low-level coding, Hooking, Bypassing. I have wanted to get to know all these things for a long time.

Also I guess I found mistyping in SshotCleaner.cpp file at line 94 and 117. There &BitBltTramp is casting into (BYTE*), but should be (uintptr_t*) to build library at x86 version. After changing this it works fine. Thank you for your source code.
1604676074065.png
thank you, I updated it
 
  • Like
Reactions: Guppi

Rake

I'm not your friend
Administrator
Jan 21, 2014
12,497
78,998
2,417
Want to hook origin overlay x64 D3D11 using this?

Go to rD3D11::HookD3D()

and change it to:

C++:
bool rD3D11::HookD3D()

    oPresent = PatternScan("4C 8B DC 56 57 41 56 48 83 EC 60 49 C7 43 ? ? ? ? ? 49 89 5B 08 49 89 6B 10 41 8B F8 8B EA 48 8B D9 48 8D 05 ? ? ? ? 49 89 43");

    presentHook = Hook((BYTE*)oPresent, (BYTE*)hkPresent, (uintptr_t*)&oPresentTramp, 19);

    presentHook.Enable();

    return true;
}
For reference:

The hook they place on Present looks like this:

C++:
dxgi.CDXGISwapChain::Present - E9 9B1A22BB - jmp igo64.dll+36A20
So we just hook their hook at igo64.dll+36A20, length is 19.

the beginning of their function looks like this:

C++:
7FFAD2936A20 - 4C 8B DC              - mov r11,rsp
7FFAD2936A23 - 56                    - push rsi
7FFAD2936A24 - 57                    - push rdi
7FFAD2936A25 - 41 56                 - push r14
7FFAD2936A27 - 48 83 EC 60           - sub rsp,60
7FFAD2936A2B - 49 C7 43 C0 FEFFFFFF  - mov qword ptr [r11-40],FFFFFFFFFFFFFFFE
7FFAD2936A33 - 49 89 5B 08           - mov [r11+08],rbx
7FFAD2936A37 - 49 89 6B 10           - mov [r11+10],rbp
7FFAD2936A3B - 41 8B F8              - mov edi,r8d
19 stolen bytes
 
Attention! Before you post:

Read the How to Ask Questions Guide
99% of questions are answered in the Beginner's Guide, do it before asking a question.

No Hack Requests. Post in the correct section.  Search the forum first. Read the rules.

How to make a good post:

  • Fill out the form correctly
  • Tell us the game name & coding language
  • Post everything we need to know to help you
  • Ask specific questions, be descriptive
  • Post errors, line numbers & screenshots
  • Post code snippets using code tags
  • If it's a large project, zip it up and attach it

If you do not comply, your post may be deleted.  We want to help, please make a good post and we will do our best to help you.

Community Mods