Initial commit
This commit is contained in:
6
.gitignore
vendored
Normal file
6
.gitignore
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
/.idea
|
||||
/.cache
|
||||
/.ccls-cache
|
||||
/compile_commands.json
|
||||
/cmake-build-debug
|
||||
/build
|
24
CMakeLists.txt
Normal file
24
CMakeLists.txt
Normal file
@@ -0,0 +1,24 @@
|
||||
cmake_minimum_required(VERSION 3.18)
|
||||
project(FunctionHook)
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
|
||||
file(GLOB_RECURSE HEADERS "include/*.h")
|
||||
|
||||
#TODO more architectures.
|
||||
if (UNIX AND NOT APPLE)
|
||||
file(GLOB_RECURSE SOURCES "src/linux64/*.cpp")
|
||||
add_library(FunctionHook SHARED ${SOURCES})
|
||||
endif()
|
||||
|
||||
if (WIN32)
|
||||
file(GLOB_RECURSE SOURCES "src/windows/*.cpp")
|
||||
add_library(FunctionHook STATIC ${SOURCES})
|
||||
endif()
|
||||
|
||||
target_include_directories(FunctionHook PUBLIC ${PROJECT_SOURCE_DIR}/include)
|
||||
|
||||
add_executable(FunctionHookDemo main.cpp)
|
||||
target_link_libraries(FunctionHookDemo PUBLIC FunctionHook)
|
||||
|
||||
set_target_properties(FunctionHook PROPERTIES LINKER_LANGUAGE CXX)
|
||||
set_target_properties(FunctionHookDemo PROPERTIES LINKER_LANGUAGE CXX)
|
34
include/FunctionHook/Hook.h
Normal file
34
include/FunctionHook/Hook.h
Normal file
@@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
#include <type_traits>
|
||||
|
||||
namespace FunctionHooking {
|
||||
class Detour {
|
||||
private:
|
||||
void* source = nullptr; //The function to be hooked.
|
||||
void* destination = nullptr; //The function we are redirecting execution to.
|
||||
uint8_t overwritten_bytes[13] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
uint8_t hook_bytes[13] = {0x49, 0xBA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x41, 0xFF, 0xE2};
|
||||
void createHook(void* source_address, void* destination_address);
|
||||
public:
|
||||
void removeHook();
|
||||
Detour(void* source_address, void* destination_address);
|
||||
Detour() = default;
|
||||
|
||||
//TODO This is *technically* not thread safe.
|
||||
template <typename T, typename... Args>
|
||||
inline typename std::enable_if<!std::is_void<T>::value, T>::type callOriginal(Args... args) {
|
||||
removeHook();
|
||||
const T result = reinterpret_cast<T(*)(Args...)>(source)(args...);
|
||||
createHook(source, destination);
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T, typename... Args>
|
||||
inline typename std::enable_if<std::is_void<T>::value, void>::type callOriginal(Args... args) {
|
||||
removeHook();
|
||||
reinterpret_cast<void(*)(Args...)>(source)(args...);
|
||||
createHook(source, destination);
|
||||
}
|
||||
};
|
||||
}
|
38
main.cpp
Normal file
38
main.cpp
Normal file
@@ -0,0 +1,38 @@
|
||||
#include <iostream>
|
||||
#include <FunctionHook/Hook.h>
|
||||
|
||||
using namespace FunctionHooking;
|
||||
|
||||
Detour voidDetour;
|
||||
Detour stringDetour;
|
||||
|
||||
void original_void() {
|
||||
std::cout << "Original void function." << std::endl;
|
||||
}
|
||||
|
||||
void hook_void() {
|
||||
std::cout << "Void hook function." << std::endl;
|
||||
voidDetour.callOriginal<void>();
|
||||
}
|
||||
|
||||
std::string original_string(const std::string& string) {
|
||||
std::cout << string + " original function." << std::endl;
|
||||
return string;
|
||||
}
|
||||
|
||||
std::string hook_string(const std::string& string) {
|
||||
std::cout << string + " hook function." << std::endl;
|
||||
|
||||
return stringDetour.callOriginal<std::string>(string);
|
||||
}
|
||||
|
||||
int main() {
|
||||
//Set up hooks.
|
||||
voidDetour = FunctionHooking::Detour((void*) original_void, (void*) hook_void);
|
||||
stringDetour = FunctionHooking::Detour((void*) original_string, (void*) hook_string);
|
||||
|
||||
original_void();
|
||||
std::cout << std::endl;
|
||||
original_string("String");
|
||||
return 0;
|
||||
}
|
40
src/linux64/Hook.cpp
Normal file
40
src/linux64/Hook.cpp
Normal file
@@ -0,0 +1,40 @@
|
||||
#include <FunctionHook/Hook.h>
|
||||
#include <sys/mman.h>
|
||||
#include <csignal>
|
||||
#include <cstring>
|
||||
|
||||
void FunctionHooking::Detour::createHook(void* source_address, void* destination_address) {
|
||||
source = source_address;
|
||||
destination = destination_address;
|
||||
|
||||
//Save the bytes to be overwritten from the function prelude.
|
||||
memcpy(&overwritten_bytes, source_address, 13);
|
||||
|
||||
//Put the destination address into the jump.
|
||||
memcpy(&hook_bytes[2], &destination_address, sizeof(void*));
|
||||
|
||||
//Make the target memory page writable.
|
||||
mprotect((void*)((uintptr_t)source_address & ~(sysconf(_SC_PAGE_SIZE)-1)), sysconf(_SC_PAGE_SIZE), PROT_READ|PROT_WRITE|PROT_EXEC);
|
||||
|
||||
//Write the jmp to the beginning of the function prelude.
|
||||
memcpy(source_address, hook_bytes, sizeof(hook_bytes));
|
||||
|
||||
//Make the memory page non-writable again.
|
||||
mprotect((void*)((uintptr_t)source_address & ~(sysconf(_SC_PAGE_SIZE)-1)), sysconf(_SC_PAGE_SIZE), PROT_READ|PROT_EXEC);
|
||||
}
|
||||
|
||||
void FunctionHooking::Detour::removeHook() {
|
||||
|
||||
//Make the target memory page writable.
|
||||
mprotect((void*)((uintptr_t)source & ~(sysconf(_SC_PAGE_SIZE)-1)), sysconf(_SC_PAGE_SIZE), PROT_READ|PROT_WRITE|PROT_EXEC);
|
||||
|
||||
//Replace our hook with the bytes that were originally there.
|
||||
memcpy(source, &overwritten_bytes, 13);
|
||||
|
||||
//Make the memory page non-writable again.
|
||||
mprotect((void*)((uintptr_t)source & ~(sysconf(_SC_PAGE_SIZE)-1)), sysconf(_SC_PAGE_SIZE), PROT_READ|PROT_EXEC);
|
||||
}
|
||||
|
||||
FunctionHooking::Detour::Detour(void *source_address, void *destination_address) {
|
||||
createHook(source_address, destination_address);
|
||||
}
|
Reference in New Issue
Block a user