diff --git a/Makefile b/Makefile index 4733eac..6328c9f 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ INCLUDES=-Isrc/include/sdk/common -Isrc/include/sdk/public -Isrc/include/sdk/pm_ CFLAGS=-Wall -Wextra -Wno-write-strings -m32 -fPIC $(INCLUDES) LDFLAGS=-lm -OBJS=obj/main.c.o obj/globals.c.o obj/cvars.c.o obj/hooks.c.o obj/util.c.o obj/features/movement.c.o obj/features/esp.c.o obj/features/chams.c.o +OBJS=obj/main.c.o obj/globals.c.o obj/cvars.c.o obj/hooks.c.o obj/detour.c.o obj/util.c.o obj/features/movement.c.o obj/features/esp.c.o obj/features/chams.c.o BIN=libhlcheat.so .PHONY: clean all inject diff --git a/src/detour.c b/src/detour.c new file mode 100644 index 0000000..d443862 --- /dev/null +++ b/src/detour.c @@ -0,0 +1,110 @@ +/** + * @file detour.c + * @brief Detour hooking library source + * @author 8dcc + * + * https://github.com/8dcc/detour-lib + */ + +#include +#include +#include +#include /* getpagesize */ +#include /* mprotect */ + +#include "include/detour.h" + +#define PAGE_SIZE getpagesize() +#define PAGE_MASK (~(PAGE_SIZE - 1)) +#define PAGE_ALIGN(x) ((x + PAGE_SIZE - 1) & PAGE_MASK) +#define PAGE_ALIGN_DOWN(x) (PAGE_ALIGN(x) - PAGE_SIZE) + +static bool protect_addr(void* ptr, int new_flags) { + void* p = (void*)PAGE_ALIGN_DOWN((detour_ptr_t)ptr); + int pgsz = getpagesize(); + + if (mprotect(p, pgsz, new_flags) == -1) + return false; + + return true; +} + +/* + * 64 bits: + * 0: 48 b8 45 55 46 84 45 movabs rax,0x454584465545 + * 7: 45 00 00 + * a: ff e0 jmp rax + * + * 32 bits: + * 0: b8 01 00 00 00 mov eax,0x1 + * 5: ff e0 jmp eax + */ +#ifdef __i386__ +static uint8_t def_jmp_bytes[] = { 0xB8, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xE0 }; +#define JMP_BYTES_PTR 1 /* Offset inside the array where the ptr should go */ +#else +static uint8_t def_jmp_bytes[] = { 0x48, 0xB8, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xE0 }; +#define JMP_BYTES_PTR 2 /* Offset inside the array where the ptr should go */ +#endif + +void detour_init(detour_data_t* data, void* orig, void* hook) { + data->detoured = false; + data->orig = orig; + data->hook = hook; + + /* Store the first N bytes of the original function, where N is the size of + * the jmp instructions */ + memcpy(data->saved_bytes, orig, sizeof(data->saved_bytes)); + + /* Default jmp bytes */ + memcpy(data->jmp_bytes, &def_jmp_bytes, sizeof(def_jmp_bytes)); + + /* JMP_BYTES_PTR is defined bellow def_jmp_bytes, and it changes depending + * on the arch. + * We use "&hook" and not "hook" because we want the address of + * the func, not the first bytes of it like before. */ + memcpy(&data->jmp_bytes[JMP_BYTES_PTR], &hook, sizeof(detour_ptr_t)); +} + +bool detour_add(detour_data_t* d) { + /* Already detoured, nothing to do */ + if (d->detoured) + return true; + + /* See util.c */ + if (!protect_addr(d->orig, PROT_READ | PROT_WRITE | PROT_EXEC)) + return false; + + /* Copy our jmp instruction with our hook address to the orig */ + memcpy(d->orig, d->jmp_bytes, sizeof(d->jmp_bytes)); + + /* Restore old protection */ + if (protect_addr(d->orig, PROT_READ | PROT_EXEC)) { + d->detoured = true; + return true; + } + + return false; +} + +bool detour_del(detour_data_t* d) { + /* Not detoured, nothing to do */ + if (!d->detoured) + return true; + + /* See util.c */ + if (!protect_addr(d->orig, PROT_READ | PROT_WRITE | PROT_EXEC)) + return false; + + /* Restore the bytes that were at the start of orig (we saved on init) */ + memcpy(d->orig, d->saved_bytes, sizeof(d->saved_bytes)); + + /* Restore old protection */ + if (protect_addr(d->orig, PROT_READ | PROT_EXEC)) { + d->detoured = false; + return true; + } + + return false; +} diff --git a/src/include/detour.h b/src/include/detour.h new file mode 100644 index 0000000..107336c --- /dev/null +++ b/src/include/detour.h @@ -0,0 +1,48 @@ +/** + * @file detour.h + * @brief Detour hooking library header + * @author 8dcc + * + * https://github.com/8dcc/detour-lib + */ + +#ifndef DETOUR_H_ +#define DETOUR_H_ + +#ifdef __i386__ +typedef uint32_t detour_ptr_t; +#define JMP_SZ_ 7 /* Size of jmp instructions in 32bit */ +#else +typedef uint64_t detour_ptr_t; +#define JMP_SZ_ 12 /* Size of jmp instructions in 64bit */ +#endif + +typedef struct { + bool detoured; + void* orig; + void* hook; + uint8_t jmp_bytes[JMP_SZ_]; + uint8_t saved_bytes[JMP_SZ_]; +} detour_data_t; + +/*----------------------------------------------------------------------------*/ + +void detour_init(detour_data_t* data, void* orig, void* hook); +bool detour_add(detour_data_t* d); +bool detour_del(detour_data_t* d); + +/*----------------------------------------------------------------------------*/ + +/* Declare the type for the original function */ +#define DECL_DETOUR_TYPE(funcRet, funcName, ...) \ + typedef funcRet (*funcName##_t)(__VA_ARGS__); + +/* Reset original bytes, call original, detour again. detourData is NOT a ptr */ +#define CALL_ORIGINAL(detourData, funcName, ...) \ + { \ + detour_del(&detourData); \ + ((funcName##_t)detourData.orig)(__VA_ARGS__); \ + detour_add(&detourData); \ + } + +#endif /* DETOUR_H_ */