Pregunta

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));
¿Fue útil?

Solución 3

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.

Otros consejos

Yes the relative address is the the offset after the instructions, that's why you have to substract 5.

But, in my opinion, you should just forget the idea of the relative jump and try absolute jump.
Why ? Because it is a lot easier and x86-64 compatible (relative jumps are limited to +/-2GB).

The absolute jump is (x64) :

48 b8 ef cd ab 89 67 45 23 01   mov rax, 0x0123456789abcdef
ff e0                           jmp rax

And for x86 :

b8 67 45 23 01   mov eax, 0x01234567
ff e0            jmp eax

Here is the modified code (the loader is now 7 bytes instead of 5):

void HookAPI(wchar_t *Module, char *API, DWORD Function)
{
    HMODULE hModule = LoadLibrary(Module);
    DWORD OriginalAddress = (DWORD)GetProcAddress(hModule, API);

    DWORD OldProtect = 0;
    DWORD NewProtect = PAGE_EXECUTE_READWRITE;

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

    memcpy(Store, OriginalAddress, 7);

    memcpy(OriginalAddress, "\xb8\x00\x00\x00\x00\xff\xe0", 7);
    memcpy(OriginalAddress+1, &ReplacementAddress, sizeof(void*));

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

    FlushInstructionCache(GetCurrentProcess(), NULL, NULL);

    FreeLibrary(hModule);
}

The code is the same for x64 but you have to add 2 nops (90) at the beginning or the end in order match the size of the following instructions, so the loader is "\x48\xb8<8-bytes addr>\xff\xe0\x90\x90" (14 bytes)

Q1) The program runs from lower to highest addresses (i.e. the program counter gets increased by the size of each instruction, unless in case of jumps, calls or ret). But I am probably missing the point of the question.

Q2) Yes, on x86 the jumps are executed after the program counter has been increased by the size of the jump instruction (5 bytes); when the CPU adds the jump offset to the program counter to calculate the target address, the program counter has already been increased of 5.

Q3) This code is quite weird, but it may work. I suppose that *relAddrset initially contains a jump offset to originalFunction (i.e. *relAddSet==originalFunction-relativeOffset). If this is true, the final result is that *reladdrSet contains a jump offset to functionFoHook. Indeed the last instruction becomes:

*relAddrSet=(originalFunction-relativeOffset)+functionForHook-originalFunction

== functionForHook-relativeOffset

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top