Video Tutorial OpenGL Hooking, Drawing & Text Rendering Tutorial

Hexui Undetected CSGO Cheats PUBG Accounts

Rake

I'm not your friend
Administrator
Jan 21, 2014
13,031
79,068
2,469
Game Name
Assault Cube
Anticheat
none
How long you been coding/hacking?
5 years
Coding Language
C++
Learn how to render text, draw rectangles and outlines in an OpenGL Swap Buffers hook.

The goal of this video tutorial is to teach you how to do this in an OpenGL Hook:

1580070859269.png


We won't be making an ESP itself, just all the rendering stuff you need to make one and how to make the box itself.

The previous video teaches you how to hook SwapBuffers: Source Code - Simple x86 C++ Trampoline Hook

This video will build upon that, if you're following along, make sure you do the previous video first.

We will make a hook class, teach you how to draw in OpenGL with filled rectangles, outline rectangles & text. Special thank you to @c5 for sharing his OpenGL Font class which this is based on.

OpenGL Hooking, Drawing & Text Rendering Tutorial


dllmain.cpp looks like this:
C++:
#include "stdafx.h"
#include <iostream>
#include "mem.h"
#include "hook.h"
#include "glDraw.h"
#include "gltext.h"

//https://guidedhacking.com/threads/opengl-hooking-drawing-text-rendering.14460/

uintptr_t moduleBase = (uintptr_t)GetModuleHandle(L"ac_client.exe");

bool bHealth = false, bAmmo = false, bRecoil = false;

typedef BOOL(__stdcall* twglSwapBuffers) (HDC hDc);

twglSwapBuffers owglSwapBuffers;
twglSwapBuffers wglSwapBuffersGateway;

GL::Font glFont;
const int FONT_HEIGHT = 15;
const int FONT_WIDTH = 9;

const char* example = "ESP Box";
const char* example2 = "I'm inside fam";

void Draw()
{
    HDC currentHDC = wglGetCurrentDC();

    if (!glFont.bBuilt || currentHDC != glFont.hdc)
    {
        glFont.Build(FONT_HEIGHT);
    }

    GL::SetupOrtho();

    GL::DrawOutline(300, 300, 200, 200, 2.0f, rgb::red);

    float textPointX = glFont.centerText(300, 200, strlen(example) * FONT_WIDTH);
    float textPointY = 300 - FONT_HEIGHT / 2;

    glFont.Print(textPointX, textPointY, rgb::green, "%s", example);

    vec3 insideTextPoint = glFont.centerText(300, 300 + 100, 200, 200, strlen(example2) * FONT_WIDTH, FONT_HEIGHT);
    glFont.Print(insideTextPoint.x, insideTextPoint.y, rgb::green, "%s", example2);

    GL::RestoreGL();
}

BOOL __stdcall hkwglSwapBuffers(HDC hDc)
{
    if (GetAsyncKeyState(VK_NUMPAD1) & 1)
        bHealth = !bHealth;

    if (GetAsyncKeyState(VK_NUMPAD2) & 1)
    {
        bAmmo = !bAmmo;
    }

    //no recoil NOP
    if (GetAsyncKeyState(VK_NUMPAD3) & 1)
    {
        bRecoil = !bRecoil;

        if (bRecoil)
        {
            mem::Nop((BYTE*)(moduleBase + 0x63786), 10);
        }

        else
        {
            //50 8D 4C 24 1C 51 8B CE FF D2 the original stack setup and call
            mem::Patch((BYTE*)(moduleBase + 0x63786), (BYTE*)"\x50\x8D\x4C\x24\x1C\x51\x8B\xCE\xFF\xD2", 10);
        }
    }

    //need to use uintptr_t for pointer arithmetic later
    uintptr_t* localPlayerPtr = (uintptr_t*)(moduleBase + 0x10F4F4);

    //continuous writes / freeze
    if (localPlayerPtr)
    {
        if (bHealth)
        {
            *(int*)(*localPlayerPtr + 0xF8) = 1337;
        }

        if (bAmmo)
        {
            *(int*)mem::FindDMAAddy(moduleBase + 0x10F4F4, { 0x374, 0x14, 0x0 }) = 1337;
        }
    }

    Draw();

    return wglSwapBuffersGateway(hDc);
}

DWORD WINAPI HackThread(HMODULE hModule)
{
    //Create Console
    AllocConsole();
    FILE* f;
    freopen_s(&f, "CONOUT$", "w", stdout);

    std::cout << "OG for a fee, stay sippin' fam\n";

    // Hook
    Hook SwapBuffersHook("wglSwapBuffers", "opengl32.dll", (BYTE*)hkwglSwapBuffers, (BYTE*)&wglSwapBuffersGateway, 5);
    SwapBuffersHook.Enable();

    //Sleep(10000);
    //SwapBuffersHook.Disable();

    //

    fclose(f);
    FreeConsole();
    FreeLibraryAndExitThread(hModule, 0);
    return 0;
}

BOOL APIENTRY DllMain(HMODULE hModule,
    DWORD  ul_reason_for_call,
    LPVOID lpReserved
)
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        CloseHandle(CreateThread(nullptr, 0, (LPTHREAD_START_ROUTINE)HackThread, hModule, 0, nullptr));
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}
We have a complete guide to OpenGL here
Guide - How to get started with OpenGL Hacks

Previous Video

After you do this video, do the next one:

Full project in the attachment
 

Attachments

You can download 0 Attachments
Last edited:

Erarnitox

🐅
Dank Tier VIP
Meme Tier VIP
Fleep Tier Donator
Trump Tier Donator
May 11, 2018
163
10,323
3
Love they way how you wrapped the Hook into it's own class... thats beatiful.
Will always do it this way as well from now on.
I feel a destructor like:
Code:
virtual ~Hook() noexcept{
    this->Disable();
}
would be nice to have as well so it automatically unhooks whenever the Hook gets out of scope or destroyed.
Or will as well also be called when the first constructor finished but we get an exception in a derived class if one decides to go down that road.

I also added some simple stuff to the glDraw tools:

glDraw.h
Code:
//...snip
void DrawLine(float fromX, float fromY, float toX, float toY, float lineWidth, const GLubyte color[3]);
bool WorldToScreen(GH_Math::vec3_t pos, GH_Math::vec3_t& screen, float matrix[16], int windowWidth = -1, int windowHeight = -1);
glDraw.cpp
Code:
//...snip
void GL::DrawLine(float fromX, float fromY, float toX, float toY, float lineWidth, const GLubyte color[3]) {
    glLineWidth(lineWidth);
    glBegin(GL_LINES);
    glColor3ub(color[0], color[1], color[2]);
    glVertex2f(fromX, fromY);
    glVertex2f(toX, toY);
    glEnd();
}

void GL::DrawEspBox(float posX, float posY, float distance, const GLubyte color[3], const char* const name, const int healthPercent) {
    float lineWidth = 0.5f;
    GLint viewport[4];
    glGetIntegerv(GL_VIEWPORT, viewport);

    float height = viewport[3]/distance * 8;
    float width = viewport[2] / distance * 2;

    //Outline:
    GL::DrawOutline(posX - (width / 2), posY-height, width, height, lineWidth + 0.4f, rgb::black);
    GL::DrawOutline(posX - (width / 2), posY-height, width, height, lineWidth, color);

    //SnapLines:
    GL::DrawLine(viewport[2] / 2, viewport[3], posX, posY, lineWidth + 0.4f, rgb::black);
    GL::DrawLine(viewport[2] / 2, viewport[3], posX, posY, lineWidth, color);

    //Name:
    if (name != nullptr) {
        HDC currentHDC = wglGetCurrentDC();

        if (!glFont.bBuilt || currentHDC != glFont.hdc){
            glFont.Build(FONT_HEIGHT);
        }

        float textPointX = glFont.centerText(posX - (width/2), posY-height-FONT_HEIGHT, strlen(name) * FONT_WIDTH);
        float textPointY = 300 - FONT_HEIGHT / 2;

        glFont.Print(textPointX, textPointY, rgb::green, "%s", name);
    }

    //Healthbar:
    if (healthPercent != -1) {
        float perc = (width / 100);
        float curr = perc * healthPercent;

        GL::DrawFilledRect(posX - (width / 2), posY - (height / 10), width, height / 10, rgb::lightgray);
        GL::DrawFilledRect(posX - (width / 2), posY - (height / 10), curr, height / 10, rgb::green);
    }
}
here is a small example of the esp box in action:

had some trouble with the text rendering but that ll be fixed soon....
i guess @Rake will cover this soon in his esp tutorial anyways but i just wanted to share how i approched it.
 
Last edited:
  • Like
Reactions: Rake

a1M

Full Member
Jan 21, 2020
2
132
0
I have a doubt concerning DLL functioning. Does the DLL runs at the same time that the game loop is running? Is the execution of the DLL and the game concurrent? Or first goes the DLL and second goes the game?
Because what if our hkwglSwapBuffers function starts executing and then it gets called by the game loop BEFORE the wglSwapBuffersGateway gets set. That should crash our game right? I'm quite confused with this
 

Rake

I'm not your friend
Administrator
Jan 21, 2014
13,031
79,068
2,469
I have a doubt concerning DLL functioning. Does the DLL runs at the same time that the game loop is running? Is the execution of the DLL and the game concurrent? Or first goes the DLL and second goes the game?
Because what if our hkwglSwapBuffers function starts executing and then it gets called by the game loop BEFORE the wglSwapBuffersGateway gets set. That should crash our game right? I'm quite confused with this
The game is running as normal.
We inject our DLL, whatever your injection method, your DLL gets loaded into memory and then DllMain is called with argument DLL_PROCESS_ATTACH

DLL_PROCESS_ATTACH calls CreateThread which calls HackThread. Once HackThread returns, your DLL is no longer "executing"

HackThread sets up a hook on SwapBuffers. At this point the only code of ours that is executing is the code inside the SwapBuffers hook when that function is called.

SwapBuffers is an exported function by opengl32.dll, as long as this DLL is loaded into memory, it will work fine.

Everything on this forum is a proof of concept, it is your job to handle all exceptions.
 

a1M

Full Member
Jan 21, 2020
2
132
0
The game is running as normal.
We inject our DLL, whatever your injection method, your DLL gets loaded into memory and then DllMain is called with argument DLL_PROCESS_ATTACH

DLL_PROCESS_ATTACH calls CreateThread which calls HackThread. Once HackThread returns, your DLL is no longer "executing"

HackThread sets up a hook on SwapBuffers. At this point the only code of ours that is executing is the code inside the SwapBuffers hook when that function is called.

SwapBuffers is an exported function by opengl32.dll, as long as this DLL is loaded into memory, it will work fine.

Everything on this forum is a proof of concept, it is your job to handle all exceptions.
Correct me if I'm wrong.

I'm just writing this because it has taken me quite a lot of time to "fully" understand how it works, and maybe I can help someone.

I've tested putting a Sleep() in TrampHook32() function right in between "Detour32(src, dst, len)" and "return gateway" (lines 41 and 43 respectively) and a crash occurs all the times I've tried. I assume the crash happens because as our DLL is running for the first time and is calling Detour32() it could also happen that the main game loop calls GlSwapBuffers BUT given that our DLL could possibly be only half-way through Detour32 the gateway has never been set. So GlSwapBuffers has nowhere to come back to, resulting in a crash.

(In practice without the Sleep() it never crashed on my pc, the sleep is there just for a simulated environment in which GlSwapBuffers executes before return gateway, resulting in a crash)

I have found that removing Detour32(src, dst, len) from TrampHook32 and putting it in Hook::Enable() right after:

*(uintptr_t*)PtrToGatewayFnPtr = (uintptr_t)TrampHook32(src, dst, len) (line 67)

fixes the problem. That way you make sure there's always gonna be a gateway set.

My assumptions could be totally wrong, and if they are just confusing people you can remove my post.
 
Last edited:

Rake

I'm not your friend
Administrator
Jan 21, 2014
13,031
79,068
2,469
@a1M so you broke my code by putting a Sleep in it and now you're asking why you need to fix it? Stop fucking up the code, no fix necessary.
 
  • Haha
Reactions: Petko123

Mikulas

Dank Tier Donator
Mar 3, 2020
3
228
0
Does anyone else get occasional crashing on the final FreeLibraryAndExitThread call? I compiled the source provided since the one I've been writing has a bunch of extra stuff in it, and maybe 50% of the time I get "Win32 Exception: 0xc0000005 [0x7b4c70b0] ()". Not sure if that address is always the same, I'll try and debug it more tomorrow.
 

Rake

I'm not your friend
Administrator
Jan 21, 2014
13,031
79,068
2,469
Does anyone else get occasional crashing on the final FreeLibraryAndExitThread call? I compiled the source provided since the one I've been writing has a bunch of extra stuff in it, and maybe 50% of the time I get "Win32 Exception: 0xc0000005 [0x7b4c70b0] ()". Not sure if that address is always the same, I'll try and debug it more tomorrow.
I never had an issue with it, but it entirely possible that it tries to unhook while the function is executing which would cause this problem. I'm not sure what the best approach is to fix this, as I only make PoCs for teaching, I never make real hacks for distribution
 

XdarionX

Dying Light Hacker
Dank Tier VIP
Trump Tier Donator
Dank Tier Donator
Mar 30, 2018
896
24,908
118
Does anyone else get occasional crashing on the final FreeLibraryAndExitThread call? I compiled the source provided since the one I've been writing has a bunch of extra stuff in it, and maybe 50% of the time I get "Win32 Exception: 0xc0000005 [0x7b4c70b0] ()". Not sure if that address is always the same, I'll try and debug it more tomorrow.
this may occour if some of your hooks is called frequently and executing its code takes some time (like writing cheats in swapbuffers)
1) make sure you unhook everything correctly
2) Sleep(100) <- so you wait until execution leaves all hooks
3) freelibandexitshit
 

Mikulas

Dank Tier Donator
Mar 3, 2020
3
228
0
this may occour if some of your hooks is called frequently and executing its code takes some time (like writing cheats in swapbuffers)
1) make sure you unhook everything correctly
2) Sleep(100) <- so you wait until execution leaves all hooks
3) freelibandexitshit
That did the trick, I just put a sleep(100) before the call to FreeLibraryAndExitThread. After debugging a bit more, I saw that it would crash when trying to execute from a memory location where hkwglSwapBuffers used to reside. So that confirms what you and Rake said, the game was executing the hack code while it was unloading.
 

KF1337

*copies code from tutorials, then breaks it.*
Dank Tier Donator
Full Member
Nobleman
Jan 30, 2020
158
3,603
0
this may occour if some of your hooks is called frequently and executing its code takes some time (like writing cheats in swapbuffers)
1) make sure you unhook everything correctly
2) Sleep(100) <- so you wait until execution leaves all hooks
3) freelibandexitshit
I was glad i found your post, since i had the same problem. BUT, a sleep() does not seem to help, even with a skeleton dll.

This code literally just prints the module addresses. When exiting the loop in Menu (line 11) and returning code execution to Setup (lines 29-34), the game still crashes (note the 1 second sleep before FreeLibraryAndExitThread:
skeleton dll:
void Menu()
{
    bool bEnabled{ true };
    while (bEnabled)
    {
        std::this_thread::sleep_for(std::chrono::milliseconds(1));
        if (GetAsyncKeyState(VK_INSERT) & 1)
        {

        }
        if (GetAsyncKeyState(VK_DELETE) & 1)
        {
            bEnabled = false;
        }
    }
}


void Setup(HMODULE hModule)
{
    //Init stuff
    AllocConsole();
    FILE* con;
    freopen_s(&con, "CONOUT$", "w", stdout);

    //Starting cheat
    GetModuleBaseAddress(); //prints module base address
    Menu();

    //Unload/Dealloc stuff
    fclose(con);
    FreeConsole();
    std::this_thread::sleep_for(std::chrono::milliseconds(1000));
    FreeLibraryAndExitThread(hModule, 0);
}


BOOL APIENTRY DllMain(HMODULE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved)
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        CloseHandle(CreateThread(0, 0, (LPTHREAD_START_ROUTINE)Setup, hModule, 0, 0));
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}
This crashes with:
crash.png


Any idea why this occurs?
 

XdarionX

Dying Light Hacker
Dank Tier VIP
Trump Tier Donator
Dank Tier Donator
Mar 30, 2018
896
24,908
118
I was glad i found your post, since i had the same problem. BUT, a sleep() does not seem to help, even with a skeleton dll.

This code literally just prints the module addresses. When exiting the loop in Menu (line 11) and returning code execution to Setup (lines 29-34), the game still crashes (note the 1 second sleep before FreeLibraryAndExitThread:
skeleton dll:
void Menu()
{
    bool bEnabled{ true };
    while (bEnabled)
    {
        std::this_thread::sleep_for(std::chrono::milliseconds(1));
        if (GetAsyncKeyState(VK_INSERT) & 1)
        {

        }
        if (GetAsyncKeyState(VK_DELETE) & 1)
        {
            bEnabled = false;
        }
    }
}


void Setup(HMODULE hModule)
{
    //Init stuff
    AllocConsole();
    FILE* con;
    freopen_s(&con, "CONOUT$", "w", stdout);

    //Starting cheat
    GetModuleBaseAddress(); //prints module base address
    Menu();

    //Unload/Dealloc stuff
    fclose(con);
    FreeConsole();
    std::this_thread::sleep_for(std::chrono::milliseconds(1000));
    FreeLibraryAndExitThread(hModule, 0);
}


BOOL APIENTRY DllMain(HMODULE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved)
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        CloseHandle(CreateThread(0, 0, (LPTHREAD_START_ROUTINE)Setup, hModule, 0, 0));
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}
This crashes with:
crash.png

Any idea why this occurs?
i have just tested this code builded x86 release and everything is working:
C++:
void Nothing()
{
    bool bEnabled = true;
    while (bEnabled)
    {
        Sleep(10);
        if (GetAsyncKeyState(VK_INSERT) & 1)
        {
            printf("Im here!\n");
        }
        if (GetAsyncKeyState(VK_DELETE) & 1)
        {
            bEnabled = false;
        }
    }
}


void Setup(HMODULE hModule)
{
    //Init stuff
    AllocConsole();
    FILE* con;
    freopen_s(&con, "CONOUT$", "w", stdout);

    Nothing();

    //Unload/Dealloc stuff
    fclose(con);
    FreeConsole();
    Sleep(1000);
    FreeLibraryAndExitThread(hModule, 0);
}


BOOL APIENTRY DllMain(HMODULE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved)
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        CloseHandle(CreateThread(0, 0, (LPTHREAD_START_ROUTINE)Setup, hModule, 0, 0));
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}
 
  • Like
Reactions: KF1337

Chucky

Troublemaker
Meme Tier VIP
Trump Tier Donator
Jan 23, 2018
364
6,348
24
Off:
@Rake your typing is worse than Fleeps (and my english). :whistle:
One day i`ll make good vid from your tuts. :devilish:

Good tut btw.
Thanks
 

KF1337

*copies code from tutorials, then breaks it.*
Dank Tier Donator
Full Member
Nobleman
Jan 30, 2020
158
3,603
0
i have just tested this code builded x86 release and everything is working:
C++:
void Nothing()
{
    bool bEnabled = true;
    while (bEnabled)
    {
        Sleep(10);
        if (GetAsyncKeyState(VK_INSERT) & 1)
        {
            printf("Im here!\n");
        }
        if (GetAsyncKeyState(VK_DELETE) & 1)
        {
            bEnabled = false;
        }
    }
}


void Setup(HMODULE hModule)
{
    //Init stuff
    AllocConsole();
    FILE* con;
    freopen_s(&con, "CONOUT$", "w", stdout);

    Nothing();

    //Unload/Dealloc stuff
    fclose(con);
    FreeConsole();
    Sleep(1000);
    FreeLibraryAndExitThread(hModule, 0);
}


BOOL APIENTRY DllMain(HMODULE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved)
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        CloseHandle(CreateThread(0, 0, (LPTHREAD_START_ROUTINE)Setup, hModule, 0, 0));
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}
Still crashes the application on my machine, even with your code. (x86 - Release config)
Tested games: CSGO, CoD4
Injector: GH Injector (default settings)

I was suspecting the project's settings, but I'm basically using default settings (except no pre-compiled headers).
Anything i am missing in regards to project/Visual Studio/Windows settings?
 

XdarionX

Dying Light Hacker
Dank Tier VIP
Trump Tier Donator
Dank Tier Donator
Mar 30, 2018
896
24,908
118
Still crashes the application on my machine, even with your code. (x86 - Release config)
Tested games: CSGO, CoD4
Injector: GH Injector (default settings)

I was suspecting the project's settings, but I'm basically using default settings (except no pre-compiled headers).
Anything i am missing in regards to project/Visual Studio/Windows settings?
i have no idea what might went wrong, i was testing it on assaultcube and injected with cheat engine but game and injector shouldnt be a problem
 
  • Like
Reactions: KF1337

Kekz

Maybe Pasting
Meme Tier VIP
Trump Tier Donator
Dank Tier Donator
Jan 10, 2020
220
6,703
29
I was glad i found your post, since i had the same problem. BUT, a sleep() does not seem to help, even with a skeleton dll.

This crashes with:
crash.png

Any idea why this occurs?
I have the exact same issue with the same Exception. It only happens when using the GH Injector Version 3.3 (default settings).
I'm doing the CSGO ESP guide and it crashes even if I download and use the sample code, and also if I add a Sleep(1000) before FreeLibraryAndExit(...)
At the moment I'm using this instead of the GH Injector, it gets the job done and I'm currently not worried about detection and it works fine, I can uninject without crashing the game.
 
  • Like
Reactions: KF1337

KF1337

*copies code from tutorials, then breaks it.*
Dank Tier Donator
Full Member
Nobleman
Jan 30, 2020
158
3,603
0
Fixed the error. Pretty sure it was me messing around too much, so i just forgot some setting that had to be toggled or whatever.

Solution:
Reset everything to default: VS, dll project, injector....(also windows, monitor settings, brain....)
 

Kekz

Maybe Pasting
Meme Tier VIP
Trump Tier Donator
Dank Tier Donator
Jan 10, 2020
220
6,703
29
Fixed the error. Pretty sure it was me messing around too much, so i just forgot some setting that had to be toggled or whatever.

Solution:
Reset everything to default: VS, dll project, injector....(also windows, monitor settings, brain....)
I've fixed it aswell now. For me it wasn't anything in VS, but apparently I messed with some settings in the Advanced section and then forgot about them. :retard:
After clicking "Reset settings" in the Injector I can now uninject without crashing
 
Community Mods