[ACCEPTED]-How to create a trampoline function for hook-trampolines

Accepted answer
Score: 11

If you want your hook to be safe when called 31 by multiple threads, you don't want to be 30 constantly unhooking and rehooking the original 29 API.

A trampoline is simply a bit of code 28 you generate that replicates the functionality 27 of the first few bytes of the original API 26 (which you overwrote with your jump), then 25 jumps into the API after the bytes you overwrote.

Rather 24 than unhooking the API, calling it and rehooking 23 it you simply call the trampoline.

This is 22 moderately complicated to do on x86 because 21 you need (a fairly minimal) disassembler 20 to find the instruction boundaries. You 19 also need to check that the code you copy 18 into your trampoline doesn't do anything 17 relative to the instruction pointer (like 16 a jmp, branch or call).

This is sufficient 15 to make calls to the hook thread-safe, but 14 you can't create the hook if multiple threads 13 are using the API. For this, you need to 12 hook the function with a two-byte near jump 11 (which can be written atomically). Windows 10 APIs are frequently preceded by a few NOPs 9 (which can be overwritten with a far jump) to 8 provide a target for this near jump.

Doing 7 this on x64 is much more complicated. You can't 6 simply patch the function with a 64-bit 5 far jump (because there isn't one, and instructions 4 to simulate it are often too long). And, depending 3 on what your trampoline does, you may need 2 to add it to the OS's stack unwind information.

I 1 hope this isn't too general.

Score: 0

The defacto standard hooking tutorial is 4 from jbremer and available here

Here is a simple 3 x86 detour and trampoline hook based on 2 this tutorial using Direct3D's EndScene() function 1 as a example:

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 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)TrampHook32((char*)d3d9Device[42], (char*)hkEndScene, 7);
}

More Related questions