mirror of https://github.com/r4sas/ExtraMirror
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
80 lines
3.8 KiB
80 lines
3.8 KiB
8 years ago
|
#ifndef EASYHOOK_HPP
|
||
|
#define EASYHOOK_HPP
|
||
|
#include <array>
|
||
|
#include <cstdio>
|
||
|
#include <iostream>
|
||
|
#include <Windows.h>
|
||
|
#include <winternl.h>
|
||
|
|
||
|
/* This macro creates the type, an instance of the type, and a prologue object specific to that function */
|
||
|
#define HOOKINIT(functor_type, function, trampoline_name, prologue_name) \
|
||
|
using functor_type = decltype(&function); \
|
||
|
functor_type trampoline_name = NULL; \
|
||
|
EasyHook::prologue prologue_name;
|
||
|
|
||
|
namespace EasyHook {
|
||
|
/* I googled this... it's supposedly 'equivalent' to __attribute__((packed)) in GCC */
|
||
|
# define PACKED(s) __pragma(pack(push, 1)) s __pragma(pack(pop))
|
||
|
# define FUNCTOR(function) decltype(&function)
|
||
|
|
||
|
union prologue {
|
||
|
PACKED(struct {
|
||
|
CHAR jmp;
|
||
|
ULONG addr;
|
||
|
}) parts;
|
||
|
CHAR bytes[sizeof(ULONGLONG)];
|
||
|
ULONGLONG full = 0;
|
||
|
};
|
||
|
|
||
|
enum opcode {
|
||
|
LONGJUMP_SIZE = 0x05,
|
||
|
RELJUMP = 0xe9,
|
||
|
NOP = 0x90,
|
||
|
};
|
||
|
|
||
|
// TODO: Hook64 at some distant future time when I become smart enough to learn about 64-bit functions...
|
||
|
|
||
|
class Hook32 {
|
||
|
static const SIZE_T jumpSize = 5;
|
||
|
public:
|
||
|
Hook32() {};
|
||
|
|
||
|
LPVOID hook(LPVOID target, prologue &original, LPVOID hook) const {
|
||
|
LPVOID trampoline = NULL;
|
||
|
DWORD oldProtection = 0;
|
||
|
if (jumpSize < 5) return 0; // minimum jump size of 5. Necessary for 32-bit programs
|
||
|
if (!VirtualProtect((LPVOID)target, 1, PAGE_EXECUTE_READWRITE, &oldProtection))
|
||
|
return NULL;
|
||
|
if (!(trampoline = VirtualAlloc(NULL, 1, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE)))
|
||
|
return VirtualProtect((LPVOID)target, 1, oldProtection, &oldProtection), NULL;
|
||
|
|
||
|
// set up the trampoline first so by the time the atomic function is called, it's already set up.
|
||
|
memcpy(trampoline, target, jumpSize); // save the first 5 bytes of the original function in the trampoline
|
||
|
*((PCHAR)((ULONG)trampoline + jumpSize)) = opcode::RELJUMP; // relative jump on the 6th byte...
|
||
|
*((PULONG)((ULONG)trampoline + jumpSize + 1)) = (ULONG)target - (ULONG)trampoline - opcode::LONGJUMP_SIZE; // return back to the target
|
||
|
|
||
|
memcpy(&original, target, sizeof original); // save the full original first 8 bytes from the function in a member variable
|
||
|
prologue tmp = original; // copy the original 8 bytes so we don't overwrite anything important.
|
||
|
tmp.parts.jmp = opcode::RELJUMP; // set the first byte to a relative jmp
|
||
|
*(PULONG)(tmp.bytes + 1) = (ULONG)hook - (ULONG)target - opcode::LONGJUMP_SIZE; // jmp to the trampoline
|
||
|
InterlockedExchange64((PLONGLONG)target, tmp.full); // atomically exchange the first 8 bytes of the original instruction
|
||
|
|
||
|
VirtualProtect((LPVOID)target, 1, oldProtection, &oldProtection); // reset the target permissions
|
||
|
return trampoline;
|
||
|
}
|
||
|
|
||
|
bool unhook(LPVOID trampoline, prologue original) const {
|
||
|
DWORD oldProtection = 0;
|
||
|
prologue origFunc; // a place to restore the original function to retrieve the address
|
||
|
memcpy(&origFunc, (LPVOID)((ULONG)trampoline + jumpSize), sizeof origFunc); // get the 8 bytes from the trampoline
|
||
|
PULONG target = (PULONG)(origFunc.parts.addr + opcode::LONGJUMP_SIZE + (ULONG)trampoline); // get the address and offset it to get the original
|
||
|
if (!VirtualProtect((LPVOID)target, 1, PAGE_EXECUTE_READWRITE, &oldProtection)) // give RWX permissions to the target function
|
||
|
return false;
|
||
|
InterlockedExchange64((PLONGLONG)target, original.full); // replace the 8 bytes of the original function with the original bytes.
|
||
|
VirtualProtect((LPVOID)target, 1, oldProtection, &oldProtection); // restore the original function permissions
|
||
|
VirtualFree(trampoline, 0, MEM_RELEASE); // release the memory
|
||
|
return true;
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
#endif
|