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.
128 lines
4.0 KiB
128 lines
4.0 KiB
#pragma once
|
|
#include <map>
|
|
#include <atomic>
|
|
#include <memory>
|
|
#include <string.h>
|
|
|
|
#define __arm__
|
|
#include <unistd.h>
|
|
#include "sys/mman.h"
|
|
|
|
#define ARM_JMP_CODE 0xE51FF004 // LDR PC, [PC, #-4]
|
|
#define PAGE_START(ptr) reinterpret_cast<void*>(reinterpret_cast<std::uintptr_t>(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<std::uint32_t*>(jmp_code)[0] = ARM_JMP_CODE;
|
|
reinterpret_cast<void**>(jmp_code)[1] = jmp_to;
|
|
memcpy(org_bytes, hook_addr, sizeof(org_bytes));
|
|
|
|
reinterpret_cast<std::uint32_t*>(landing_code)[2] = ARM_JMP_CODE;
|
|
memcpy(landing_code, org_bytes, sizeof(org_bytes));
|
|
reinterpret_cast<std::uint32_t*>(landing_code)[3] =
|
|
reinterpret_cast<std::uintptr_t>(hook_addr) + 8;
|
|
|
|
mprotect(PAGE_START(landing_code), getpagesize(),
|
|
PROT_EXEC | PROT_READ | PROT_WRITE);
|
|
|
|
cacheflush(reinterpret_cast<long>(PAGE_START(landing_code)),
|
|
reinterpret_cast<long>(
|
|
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<long>(hook_addr), reinterpret_cast<long>(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<long>(hook_addr), reinterpret_cast<long>(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<void*>(landing_code); }
|
|
private:
|
|
std::atomic<bool> 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<void*, std::unique_ptr<detour>>* get_hooks()
|
|
{
|
|
static std::map<void*, std::unique_ptr<detour>> hooks{};
|
|
return &hooks;
|
|
}
|
|
|
|
template <class T, class U>
|
|
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<detour>(
|
|
(void*) addr_to_hook,
|
|
(void*) jmp_to_addr,
|
|
enable
|
|
)}
|
|
);
|
|
}
|
|
|
|
template<class T>
|
|
inline void enable(T addr)
|
|
{
|
|
get_hooks()->at((void*)addr)->install();
|
|
}
|
|
|
|
template <class T>
|
|
inline T get_func(T addr)
|
|
{
|
|
return reinterpret_cast<T>(
|
|
get_hooks()->at((void*)addr)->get_func());
|
|
}
|
|
|
|
template <class T>
|
|
inline void disable(T addr)
|
|
{
|
|
get_hooks()->at((void*)addr)->uninstall();
|
|
}
|
|
|
|
template <class T>
|
|
inline void remove(T addr)
|
|
{
|
|
get_hooks()->erase((void*)addr);
|
|
}
|
|
} |