Function Hooking

Table of content

Definition

A hook is a callback added to a method that will redirect program execution flow. For example, EDR can add hooks to sensitive functions to check the different parameters used.

The hook can be implemented easily with a JMP added at the beginning of the function or through specific callback functions such as NtSetProcessInformation.

Hook example

x86 : Add JMP patch

The following x86 code hooks the MessageBoxA function and redirect the execution flow to another function:

#include <windows.h>
#include <stdio.h>

#define BYTES_REQUIRED 6

// Function where the execution flow will be redirected
int __stdcall HookedMessageBoxA(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType){
    printf("\n[ HOOKED MESSAGEBOXA ]\n");
    printf("Arguments:\n");
    printf("  1. lpText: %s\n", lpText);
    printf("  2. lpCaption: %s\n", lpCaption);
    printf("  3. uType: %ld\n", uType);
    return 1;
}

int main()
{

    SIZE_T lpNumberOfBytesRead = 0;
    HMODULE hModule = NULL;
    FARPROC pMessageBoxAFunc = NULL;
    char pMessageBoxABytes[BYTES_REQUIRED];

    void* pHookedMessageBoxFunc = &HookedMessageBoxA;

    hModule = LoadLibraryA("user32.dll");
    if (!hModule){
        return -1;
    }

    pMessageBoxAFunc = GetProcAddress(hModule, "MessageBoxA");

    if (ReadProcessMemory(GetCurrentProcess(), pMessageBoxAFunc, pMessageBoxABytes, BYTES_REQUIRED, &lpNumberOfBytesRead) == FALSE){
        printf("[!] ReadProcessMemory: %ld\n", GetLastError());
        return -1;
    }

    // Add the hook :
    //      JMP HookedMessageBoxFunc
    //      RET
    char patch[BYTES_REQUIRED] = { 0 };
    // JMP OPCODE
    memcpy_s(patch, 1, "\x68", 1);
    // Function address where the execution flow will be redirect
    memcpy_s(patch + 1, 4, &pHookedMessageBoxFunc, 4);
    // RET OPCODE
    memcpy_s(patch + 5, 1, "\xC3", 1);

    // Write the patch
    if (WriteProcessMemory(GetCurrentProcess(), (LPVOID)pMessageBoxAFunc, patch, sizeof(patch), &lpNumberOfBytesRead) == FALSE){
        printf("[!] WriteProcessMemory: %ld\n", GetLastError());
        return -1;
    }

    // Call the hooked function
    MessageBoxA(NULL, "AAAAA", "BBBBB", MB_OK);
    return 0;
}

/*
Result :
[ HOOKED MESSAGEBOXA ]
-> Arguments:
  1. lpText: AAAAA
  2. lpCaption: BBBBB
  3. uType: 0
*/

For x64 the patch's OPCODE must be changed

x86 : NtSetProcessInformation - Hook syscall results

The NtSetProcessInformation is called every time the kernel sent back a value to the usermode. When a syscall is performed, the kernel send back the result to the usermode function and call the NtSetProcessInformation function first.

The NtSetProcessInformation takes as an argument a function pointer used as a callback function. Thus, this function will be executed each time the kernel communicates with the usermode. It then can be used to intercept any system calls performed, any process or thread created etc...

Before calling the callback, the registers must be saved in the stack. Then the callback function is called and the registers are popped out from the stack. this this for more explanations. R10 contains the last instruction pointer. When the callback is finished, just jump to R10 to continue the normal execution flow.

This is summarized in the following ASM code :

include ksamd64.inc

; the callback function that will be called and defined in the C file
EXTERN hook:NEAR

.code
medium  PROC

    ; https://docs.microsoft.com/en-us/cpp/build/caller-callee-saved-registers

    push rax ; return value if system call
    push rcx
    push RBX
    push RBP
    push RDI
    push RSI
    push RSP
    push R12
    push R13
    push R14
    push R15 

    ; allocate stack
    sub rsp, 1000h

    ; set parameters for the hook function
    mov rdx, rax
    mov rcx, r10

    ; call the hook function
    call hook

    ; erase the allocated stack
    add rsp, 1000h

    ; repop registers
    pop R15 
    pop R14
    pop R13
    pop R12
    pop RSP
    pop RSI
    pop RDI
    pop RBP
    pop RBX
    pop rcx
    pop rax

    ; jump to the normal execution flow
    jmp R10
medium  ENDP

END

Resource

results matching ""

    No results matching ""

    results matching ""

      No results matching ""