Как сделать функцию Hook and Trampoline в одном для перехвата WinAPI

Итак, я изучал концепцию перехвата и использования трамплинов для обхода / выполнения данных в функции перехвата WinAPI (в другом исполняемом файле с использованием внедрения DLL). До сих пор я знаю, как сделать это (батут и крюк), используя смесь сборки и C, но я не могу сделать это просто с помощью C, так как мне кажется, что-то не хватает. Буду признателен, если кто-нибудь скажет мне, что я делаю неправильно и как это исправить.

Прямо сейчас мой код:

#include <Windows.h>

unsigned char* address = 0;

__declspec(naked) int __stdcall MessageBoxAHookTrampoline(HWND Window, char* Message, char* Title, int Type) {
    __asm
    {
        push ebp
        mov ebp, esp
        mov eax, address
        add eax, 5
        jmp eax
    }
}

int __stdcall MessageBoxAHook(HWND Window, char* Message, char* Title, int Type) {
    wchar_t* WMessage = L"Hooked!";
    wchar_t* WTitle = L"Success!";
    MessageBoxW(0, WMessage, WTitle, 0);
    return MessageBoxAHookTrampoline(Window, Message, Title, Type);
}

unsigned long __stdcall Thread(void* Context) {
    address = (unsigned char*)GetProcAddress(LoadLibraryA("user32"), "MessageBoxA");
    ULONG OP = 0;
    if (VirtualProtect(address, 1, PAGE_EXECUTE_READWRITE, &OP)) {
        memset(address, 0x90, 5);
        *address = 0xE9;
        *(unsigned long*)(address + 1) = (unsigned long)MessageBoxAHook - (unsigned long)address - 5;
    }
    else {
        MessageBoxA(0, "Failed to change protection", "RIP", 0);
    }
    return 1;
}

// Entry point.
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved) {
    if (fdwReason == DLL_PROCESS_ATTACH) {
        CreateThread(0, 0, Thread, 0, 0, 0);
    }
    else if (fdwReason == DLL_PROCESS_DETACH) {

    }
    return true;
}

Итак, вопрос в том, как бы я сделал функцию сказать InstallHook что установит крюк и вернет батут, чтобы я мог легко им пользоваться? Функцией прототипа, вероятно, будет: void* InstallHook(void* originalFunc, void* targetFunc, int jumpsize)или я так понял, читая онлайн, но не уверен, что jumpsize будет использоваться для.

До сих пор я знаю, что первые 5 байтов должны быть сохранены и восстановлены, а затем происходит переход к адресу исходной перехваченной функции. Так что мне пришлось бы использовать malloc для выделения памяти, memcpy для копирования байтов, 0xE9 это значение инструкции перехода и тому подобное, но я просто не знаю, как реализовать ее, используя только чистый C. Я полагаю, что это будет что-то похожее на код в этом вопросе. Так, как я могу написать функцию ловушки, которая возвращает батут, используя чистый C для функций WinAPI?

1 ответ

Решение

Если я правильно понял вопрос, вы хотите избежать "жесткого кодирования" функции батута в сборке, предположительно, чтобы можно было использовать несколько батутов одновременно, не дублируя код. Вы можете добиться этого, используя VirtualAlloc (malloc не будет работать, так как возвращаемая память не будет исполняемой).

Я написал это из памяти без доступа к компилятору, чтобы он мог иметь некоторые незначительные ошибки, но общая идея здесь. Обычно вы также используете VirtualProtect изменить права доступа к странице r-x вместо rwx как только вы закончите изменять его, но я упустил это для простоты:

void *CreateTrampoline(void *originalFunc)
{
    /* Allocate the trampoline function */
    uint8_t *trampoline = VirtualAlloc(
        NULL,
        5 + 5, /* 5 for the prologue, 5 for the JMP */
        MEM_COMMIT | MEM_RESERVE,
        PAGE_EXECUTE_READWRITE); /* Make trampoline executable */

    /* Copy the original function's prologue */
    memcpy(trampoline, originalFunc, 5);

    /* JMP rel/32 opcode */
    trampoline[5] = 0xE9;

    /* JMP rel/32 operand */
    uint32_t jmpDest = (uint32_t)originalFunc + 5; /* Skip original prologue */
    uint32_t jmpSrc = (uint32_t)trampoline + 10; /* Starting after the JMP */
    uint32_t delta = jmpDest - jmpSrc;
    memcpy(trampoline + 6, &delta, 4);

    return trampoline;
}

Ваш InstallHook функция будет тогда просто вызвать CreateTrampoline чтобы создать батут, а затем залатать первые 5 байтов исходной функции JMP rel/32 на крючок

Имейте в виду, это работает только для функций WinAPI, потому что Microsoft требует, чтобы у них был 5-байтовый пролог для включения оперативного исправления (что вы и делаете здесь). Нормальные функции не имеют этого требования - обычно они начинаются только с push ebp; mov ebp, esp что составляет всего 3 байта (а иногда даже и того, если компилятор решает оптимизировать его).

Редактировать: вот как работает математика:

                          _______________delta______________
                         |                                  |
trampoline               |                  originalFunc    |
    |                    |                        |         |
    v                    |                        v         v
    [prologue][jmp delta]                         [prologue][rest of func]
    |________||_________|                         |________|
         5    +    5                                   5
Другие вопросы по тегам