Hi there!
A few months ago i have been working on a c++ library called LiquidHookEx.
This is a External VTable, CallSite and Detour hooking library using Shellcode Injection.
Now i decided that it is time for me do something amazing.
But what is even amazing? What are people in the Game Hacking Scene are dreaming about?
Then it came to my head: I need a DX11 ImGui Fullscreen Overlay which works without DLL Injection ( PresentHookEx on GitHub )
So that's what i did.
How does it work?
This project uses the DX11 Dummy SwapChain method as every DLL Injected Present hook is also using, but without the DLL injection.
It is creating remote Threads to obtain a dummy swapchain, writes a new hook function the remote process using LiquidHookEx, makes it Executable and replaces the original VTable method with it.
A simple Detour hook but without the DLL injection.
After shellcode injection and VTable hooking the dummy swapchain gets released.
It's pretty easy to use as you can see in this main.cpp
#include <Example/Include.h>
std::string szExe = R"(PROCESS.exe)";
int main() {
SetConsoleTitle("PresentHookEx - External DX11 Fullscreen hook");
LiquidHookEx::INIT(szExe);
RenderObjectManager renderObjectManager{ {} };
OverlayAPI::InitImGuiContext();
HeadlessRenderer::Start(&renderObjectManager, LiquidHookEx::proc->GetHwnd(), 1920, 1080);
while (!HeadlessRenderer::IsReady()) Sleep(1);
if (!LiquidHookEx::Present::Hook()) {
printf("Couldn't hook DX11::Present!!\n");
return -1;
}
while (!GetAsyncKeyState(VK_DELETE)) {
Sleep(500);
}
if (!LiquidHookEx::Present::Unhook()) {
printf("Couldn't unhook DX11::Present!!\nIt's better to restart the process now!\n");
return -1;
}
HeadlessRenderer::Stop();
return 0;
}
How does rendering work?
PresentHookEx keeps ImGui rendering outside the target process. The HeadlessRenderer runs in the injector process, while LiquidHookEx installs a hook in the target process to composite the rendered overlay during Direct3D 11 Present calls.
The renderer and hook share the overlay through a D3D11 texture:
-
HeadlessRenderercreates a D3D11 device and shared texture, then publishes the texture handle and dimensions through a named Windows file mapping. - On the hook’s first Present call, it reads the mapping and opens the shared texture in the target process. It creates the D3D11 resources needed to draw the texture.
- Each renderer frame,
HeadlessRendererdraws the ImGui interface into the shared texture. - Each Present call, the hook composites that texture onto the target’s back buffer, restores the D3D11 state it changed, and calls the original Present function.
The two processes coordinate access to the shared texture with an IDXGIKeyedMutex. The renderer and hook take turns owning the texture, preventing one side from drawing into it while the other is reading it. This keeps UI rendering separate from the target’s frame presentation while allowing the overlay to appear in the target’s output.
If you got some questions, feel free to ask :-)
Top comments (0)