Как сделать функцию 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