#pragma once #include #include #include #include #define __arm__ #include #include "sys/mman.h" #define ARM_JMP_CODE 0xE51FF004 // LDR PC, [PC, #-4] #define PAGE_START(ptr) reinterpret_cast(reinterpret_cast(ptr) >> 12 << 12) namespace hook { class detour { public: detour(void* addr_to_hook, void* jmp_to, bool enable = true) : hook_addr(addr_to_hook), detour_addr(jmp_to), hook_installed(false) { reinterpret_cast(jmp_code)[0] = ARM_JMP_CODE; reinterpret_cast(jmp_code)[1] = jmp_to; memcpy(org_bytes, hook_addr, sizeof(org_bytes)); reinterpret_cast(landing_code)[2] = ARM_JMP_CODE; memcpy(landing_code, org_bytes, sizeof(org_bytes)); reinterpret_cast(landing_code)[3] = reinterpret_cast(hook_addr) + 8; mprotect(PAGE_START(landing_code), getpagesize(), PROT_EXEC | PROT_READ | PROT_WRITE); cacheflush(reinterpret_cast(PAGE_START(landing_code)), reinterpret_cast( PAGE_START(landing_code)) + getpagesize(), NULL); if (enable) install(); } ~detour() { uninstall(); } void install() { if (hook_installed.load()) return; if (!mprotect(PAGE_START(hook_addr), getpagesize(), PROT_READ | PROT_WRITE | PROT_EXEC)) { memcpy((void*)((long)hook_addr), jmp_code, sizeof(jmp_code)); mprotect(PAGE_START(hook_addr), getpagesize(), PROT_READ | PROT_EXEC); cacheflush(reinterpret_cast(hook_addr), reinterpret_cast(hook_addr) + getpagesize(), NULL); hook_installed.exchange(true); } } void uninstall() { if (!hook_installed.load()) return; if (!mprotect(PAGE_START(hook_addr), getpagesize(), PROT_READ | PROT_WRITE | PROT_EXEC)) { memcpy(hook_addr, org_bytes, sizeof(jmp_code)); mprotect(PAGE_START(hook_addr), getpagesize(), PROT_READ | PROT_EXEC); cacheflush(reinterpret_cast(hook_addr), reinterpret_cast(hook_addr) + getpagesize(), NULL); hook_installed.exchange(false); } } bool installed() { return hook_installed; } void* hook_address() { return hook_addr; } void* detour_address(){ return detour_addr; } void* get_func() { return reinterpret_cast(landing_code); } private: std::atomic hook_installed; void* hook_addr, * detour_addr; unsigned char jmp_code[8]; unsigned char landing_code[16]; std::uint8_t org_bytes[sizeof(jmp_code)]; }; inline std::map>* get_hooks() { static std::map> hooks{}; return &hooks; } template inline void make_hook(T addr_to_hook, U jmp_to_addr, bool enable = true) { get_hooks()->insert({ (void*)addr_to_hook, std::make_unique( (void*) addr_to_hook, (void*) jmp_to_addr, enable )} ); } template inline void enable(T addr) { get_hooks()->at((void*)addr)->install(); } template inline T get_func(T addr) { return reinterpret_cast( get_hooks()->at((void*)addr)->get_func()); } template inline void disable(T addr) { get_hooks()->at((void*)addr)->uninstall(); } template inline void remove(T addr) { get_hooks()->erase((void*)addr); } }