Source Code Simple x86 C++ Trampoline Hook

Hexui Undetected CSGO Cheats PUBG Accounts

Rake

I'm not your friend
Administrator
Jan 21, 2014
13,031
79,068
2,469
How long you been coding/hacking?
5 years
What is a detour?

The word detour describes the act of changing the assembly instructions to jump to a different location, essentially re-directing the flow of execution. Typically you are doing this to detour the code into a memory region where your own code exists. Thus you're forcing the game to execute your code.

The key to doing this is to make sure you do not corrupt the stack, you execute the bytes that you overwrote and you jump back to the proper position after your code executes.

Basic x86 Internal Detour Code
C++:
bool Detour32(char* src, char* dst, const intptr_t len)
{
    if (len < 5) return false;

    DWORD  curProtection;
    VirtualProtect(src, len, PAGE_EXECUTE_READWRITE, &curProtection);

    intptr_t  relativeAddress = (intptr_t)(dst - (intptr_t)src) - 5;

    *src = (char)'\xE9';
    *(intptr_t*)((intptr_t)src + 1) = relativeAddress;

    VirtualProtect(src, len, curProtection, &curProtection);
    return true;
}
x86 Trampoline Hook

A detour can be placed anywhere and all it does is jump. In my mind, hooking better describes the art of hooking an entire function and directing it to your own function. What I have just described is what I think is best referred to as a trampoline hook. First off, a trampoline hook is typically internal. You inject your DLL which contains a function with the same declaration as the function you're hooking. It has the same arguments, return type and calling convention. In this function you have your own code you want to execute and at the end of your function, you call the original function.

But if you execute the original function, it just jumps to your own function again, so you get an infinite loop from hell.

Thus, the trampoline hook was born. Instead of jumping back to the original function after your function executes, you jump to a trampoline or gateway. The is gateway then jumps back to the original function, but it jumps at the byte after your jump occurs, thus evading the infinite loop.

To do a trampoline hook, you create a regular detour which detours the target function to your function. In your function you execute your code, and then instead of returning to the original function, you jump to the gateway, execute your stolen bytes and then proceed to jump to the original function, a few bytes later after your detour, thus skipping the original detour.


C++:
char* TrampHook32(char* src, char* dst, const intptr_t len)
{
    // Make sure the length is greater than 5
    if (len < 5) return 0;

    // Create the gateway (len + 5 for the overwritten bytes + the jmp)
    void* gateway = VirtualAlloc(0, len + 5, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);

    //Write the stolen bytes into the gateway
    memcpy(gateway, src, len);

    // Get the gateway to destination addy
    intptr_t  gatewayRelativeAddr = ((intptr_t)src - (intptr_t)gateway) - 5;

    // Add the jmp opcode to the end of the gateway
    *(char*)((intptr_t)gateway + len) = 0xE9;

    // Add the address to the jmp
    *(intptr_t*)((intptr_t)gateway + len + 1) = gatewayRelativeAddr;

    // Perform the detour
    Detour32(src, dst, len);

    return (char*)gateway;
}
The secret to using this function is you must set the original function pointer to point at the address of the gateway, which this function returns. Then in your hook, at the end, call the original function pointer, which now points at the gateway.

How to use it
You don't need any inline ASM or any declspec naked functions, define your function prototypes, create function pointers, create your function, then use your trampoline hook function to hook the original function and detour or to your own function. The TrampHook function will handle the creation of the gateway for you.

Here's the basic concept:

C++:
typedef HRESULT(APIENTRY* tEndScene)(LPDIRECT3DDEVICE9 pDevice);
tEndScene oEndScene = nullptr;

HRESULT APIENTRY hkEndScene(LPDIRECT3DDEVICE9 pDevice)
{
    //do stuff in here
    return oEndScene(pDevice);
}

//just an example
int main()
{
    oEndScene = (tEndScene)TrampHook((char*)d3d9Device[42], (char*)hkEndScene, 7);
}
Complete Example Project
The simplest example we have a trampoline hook in action that is 100% ready to compile and inject is this one:
https://guidedhacking.com/threads/d3d9-endscene-hook-template-using-dummy-device.14008/

This is what you want to be doing when hooking anything internally, it's just too easy.

For more information, stay tuned for our complete detouring / hooking guide. Shoutout to Solaire, he is the original creator of this code and he is an OG.
 
Last edited:

TorCracker

Full Member
Nobleman
Jul 13, 2019
58
1,213
1
im trying to hook MessageBoxA ( I CAN DO IT with detours but i want use this).
C++:
typedef int(__stdcall *_MessageBox)(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType);
_MessageBox _MSG = nullptr;

int _stdcall _MessageBoxA_(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType)
{
    return _MSG(hWnd, L"HOOK", lpCaption, uType);
}
on the thread i put

C++:
       Org_DeleteFileA = (uintptr_t)GetProcAddress(GetModuleHandleA("user32.dll"), "MessageBoxA");

       _MSG = (_MessageBox)TrampHook32((char*)Org_DeleteFileA, (char*)_MessageBoxA_, size);
but the program don't show the MessageBox, WHAT DO YOU SEE WRONG?
 

Kage

Fleep Tier Donator
Trump Tier Donator
Dank Tier Donator
Nobleman
Jan 26, 2019
61
2,853
1
Are you using x86 and started with admin rights?
What are you using for size?
 

TorCracker

Full Member
Nobleman
Jul 13, 2019
58
1,213
1
Are you using x86 and started with admin rights?
What are you using for size?
Yes, the size is the problem i put 7 but i don't know how i can get it. i think it
C++:
int size = sizeof((int)_MessageBoxA_);
 
Last edited:

Kage

Fleep Tier Donator
Trump Tier Donator
Dank Tier Donator
Nobleman
Jan 26, 2019
61
2,853
1
i think in this case 7 should be fine for TrampHook.
What happens if you debug it? Have you take a loke in the memory?
Are you using Unicode or Multi-Byte?
 
Last edited:

Kage

Fleep Tier Donator
Trump Tier Donator
Dank Tier Donator
Nobleman
Jan 26, 2019
61
2,853
1
typedef int(__stdcall *_MessageBox)(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType);
int MessageBoxA(
HWND hWnd,
LPCSTR lpText,
LPCSTR lpCaption,
UINT uType
);

You have the wrong Function defination. You define for Multi-Byte but try to hook the Unicode Version.

EDIT: This comment was bullshit
 
Last edited:

TorCracker

Full Member
Nobleman
Jul 13, 2019
58
1,213
1
i think in this case 7 should be fine for TrampHook.
What happens if you debug it? Have you take a loke in the memory?
Are you using Unicode or Multi-Byte?
im using unicode, when i put size = 7 whe i inject the dll thow me a error from memory.
 

Rake

I'm not your friend
Administrator
Jan 21, 2014
13,031
79,068
2,469
@TorCracker here is the working code

C++:
#include <iostream>
#include <Windows.h>


bool Detour32(char* src, char* dst, const intptr_t len)
{
    if (len < 5) return false;

    DWORD  curProtection;
    VirtualProtect(src, len, PAGE_EXECUTE_READWRITE, &curProtection);

    intptr_t  relativeAddress = (intptr_t)(dst - (intptr_t)src) - 5;

    *src = (char)'\xE9';
    *(intptr_t*)((intptr_t)src + 1) = relativeAddress;

    VirtualProtect(src, len, curProtection, &curProtection);
    return true;
}

char* TrampHook32(char* src, char* dst, const intptr_t len)
{
    // Make sure the length is greater than 5
    if (len < 5) return 0;

    // Create the gateway (len + 5 for the overwritten bytes + the jmp)
    void* gateway = VirtualAlloc(0, len + 5, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);

    //Write the stolen bytes into the gateway
    memcpy(gateway, src, len);

    // Get the gateway to destination addy
    intptr_t  gatewayRelativeAddr = ((intptr_t)src - (intptr_t)gateway) - 5;

    // Add the jmp opcode to the end of the gateway
    *(char*)((intptr_t)gateway + len) = 0xE9;

    // Add the address to the jmp
    *(intptr_t*)((intptr_t)gateway + len + 1) = gatewayRelativeAddr;

    // Perform the detour
    Detour32(src, dst, len);

    return (char*)gateway;
}

typedef int (__stdcall* tMessageBoxA)(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType);
tMessageBoxA oMessageBoxA = nullptr;

int __stdcall hkMessageBoxA(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType)
{

    lpText = "hax0red";

    return oMessageBoxA(hWnd, lpText, lpCaption, uType);
}

int main()
{
    oMessageBoxA = (tMessageBoxA)GetProcAddress(GetModuleHandleA("user32.dll"), "MessageBoxA");

    oMessageBoxA = (tMessageBoxA)TrampHook32((char*)oMessageBoxA, (char*)hkMessageBoxA, 5);

    MessageBoxA(NULL,"Body Message","Title Here", MB_OK);

    return 0;
}
1576651850622.png


our relative jump is 5 bytes, that's the minimum number of bytes we need for the stolen bytes. In this function the first 3 instructions are 5 bytes in total, so this is fine. If the third instruction was 5 bytes instead of 2, then the total bytes would have been 8. Had you only executed 5 of these 8 bytes it would have been a problem. This is why we set the number of bytes manually, you can't grantee it will always be 5. but it is indeed 5 for this function
 
Last edited:
  • Like
Reactions: Wany and Kage

Rake

I'm not your friend
Administrator
Jan 21, 2014
13,031
79,068
2,469
I‘m very confused about why ourFunct can jmp to gateway ?
this tutorial is very good, and if you did the GHB correctly it should be very easy to understand, if you don't understand it, you either didn't do the GHB correctly or you're an idiot
 
Community Mods