Search code examples
c++chookhotpatching

Calculating offset for hotpatching/inline function hooking


From http://lastfrag.com/hotpatching-and-inline-hooking-explained/,

Q1) Does code proceed from high memory to low memory or vice versa?

Q2) More importantly, during the calculation of the replacement offset, why is it that you have to minus the function preamble? Is it because the offset starts from the end of the instruction and not the beginning?

DWORD ReplacementAddressOffset = ReplacementAddress - OriginalAddress - 5;

Full Code:

void HookAPI(wchar_t *Module, char *API, DWORD Function)
{
    HMODULE hModule = LoadLibrary(Module);
    DWORD OriginalAddress = (DWORD)GetProcAddress(hModule, API);
    DWORD ReplacementAddress = (DWORD)Function;
    DWORD ReplacementAddressOffset = ReplacementAddress - OriginalAddress - 5;
    LPBYTE pOriginalAddress = (LPBYTE)OriginalAddress;
    LPBYTE pReplacementAddressOffset = (LPBYTE)(&ReplacementAddressOffset);

    DWORD OldProtect = 0;
    DWORD NewProtect = PAGE_EXECUTE_READWRITE;

    VirtualProtect((PVOID)OriginalAddress, 5, NewProtect, &OldProtect);

    for (int i = 0; i < 5; i++)
        Store[i] = pOriginalAddress[i];

    pOriginalAddress[0] = (BYTE)0xE9;

    for (int i = 0; i < 4; i++)
        pOriginalAddress[i + 1] = pReplacementAddressOffset[i];

    VirtualProtect((PVOID)OriginalAddress, 5, OldProtect, &NewProtect);

    FlushInstructionCache(GetCurrentProcess(), NULL, NULL);

    FreeLibrary(hModule);
}

Q3) In this code, the relative address of a jmp instruction is being replaced; relAddrSet is a pointer to the original destination; to is a pointer to the new destination. I don't understand the calculation of the to address, why is it that you have to add the original destination to the functionForHook + opcodeOffset?

DWORD *relAddrSet = (DWORD *)(currentOpcode + 1);
DWORD_PTR to = (*relAddrSet) + ((DWORD_PTR)functionForHook + opcodeOffset);
*relAddrSet = (DWORD)(to - ((DWORD_PTR)originalFunction + opcodeOffset));

Solution

  • Yes, code runs "forward" if I understand this question correctly. One instruction is executed after another if it is not branching.

    An instruction that does a relative jump (JMP, CALL) does the jump relative to the start of the next instruction. That's why you have to subtract the length of the instruction (here: 5) from the difference.

    I can't answer your third question. Please give some context and what the code is supposed to do.