163 lines
8.1 KiB
C
163 lines
8.1 KiB
C
/*
|
|
* MIT License
|
|
*
|
|
* Copyright (c) 2017 Rokas Kupstys
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in all
|
|
* copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
* SOFTWARE.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <stdbool.h>
|
|
#include <stdint.h>
|
|
#include <stddef.h>
|
|
|
|
#define HOOKER_ERROR (false)
|
|
#define HOOKER_SUCCESS (true)
|
|
#define HOOKER_MEM_R (1 << 0)
|
|
#define HOOKER_MEM_W (1 << 1)
|
|
#define HOOKER_MEM_X (1 << 2)
|
|
#define HOOKER_MEM_RW (HOOKER_MEM_R|HOOKER_MEM_W)
|
|
#define HOOKER_MEM_RX (HOOKER_MEM_R|HOOKER_MEM_X)
|
|
#define HOOKER_MEM_RWX (HOOKER_MEM_R|HOOKER_MEM_W|HOOKER_MEM_X)
|
|
/// Memory protection flags are platform specific (not a combination of above flags) and should not be converted.
|
|
#define HOOKER_MEM_PLATFORM (1 << 31)
|
|
|
|
/// Write a call instruction (5 bytes on x86/64).
|
|
#define HOOKER_HOOK_CALL (1 << 0)
|
|
/// Write a jump instruction (5 bytes on x86/64).
|
|
#define HOOKER_HOOK_JMP (1 << 1)
|
|
/// Use fat jump (16 for call and 14 bytes for jmp on x64). Has no effect on x86.
|
|
#define HOOKER_HOOK_FAT (1 << 2)
|
|
|
|
#if __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
/// Call any address with arbitrary amount of arguments. Returns value of specified type.
|
|
/// \param returnType of return value.
|
|
/// \param address of a call.
|
|
#define hooker_call(returnType, address, ...) (returnType(*)(...))(address)(__VA_ARGS__);
|
|
/// Call any address with arbitrary amount of arguments. Does not return anything.
|
|
/// \param address of a call.
|
|
#define hooker_callv(address, ...) (void(*)(...))(address)(__VA_ARGS__);
|
|
|
|
/// Change protection of memory range.
|
|
/// \param p memory address.
|
|
/// \param size of memory at address p.
|
|
/// \param protection a combination of HOOKER_MEM_* flags.
|
|
/// \param original_protection on supported platforms will be set to current memory protection mode. May be null. If not null - always initialize to a best-guess current protection flags value, because on some platforms (like linux) this variable will not be set.
|
|
bool hooker_mem_protect(void* p, size_t size, size_t protection, size_t* original_protection);
|
|
/// Get mnemonic size of current platform.
|
|
size_t hooker_get_mnemonic_size(void* address, size_t min_size);
|
|
|
|
/// Hotpatch a call.
|
|
void* hooker_hotpatch(void* location, void* new_proc);
|
|
/// Unhotpatch a call.
|
|
bool hooker_unhotpatch(void* location);
|
|
|
|
/// Writes a jump or call hook from `address` to `new_proc`.
|
|
/// \param address a pointer where hook should be written
|
|
/// \param new_proc a pointer where hook should point to.
|
|
/// \param flags any of HOOKER_HOOK_* flags. They may not be combined.
|
|
/// \param nops of bytes to nop after hook instruction. Specify -1 to autocalculate.
|
|
/// \returns null on failure or non-null on success.
|
|
bool hooker_write_instruction(void* address, void* new_proc, size_t flags, size_t nops);
|
|
|
|
/// Writes a 5 byte jump with E9 opcode. Difference between pointers is limited to 32bit.
|
|
/// \param address a pointer where hook should be written
|
|
/// \param new_proc a pointer where hook should point to.
|
|
/// \returns null on failure or non-null on success.
|
|
bool hooker_write_jmp(void* address, void* new_proc);
|
|
/// Writes a 5 byte call with E8 opcode. Difference between pointers is limited to 32bit.
|
|
/// \param address a pointer where hook should be written
|
|
/// \param new_proc a pointer where hook should point to.
|
|
/// \returns null on failure or non-null on success.
|
|
bool hooker_write_call(void* address, void* new_proc);
|
|
|
|
/// Redirect call to custom proc.
|
|
/// \param address a start of original call. Warning: It should not contain any relatively-addressed instructions like calls or jumps.
|
|
/// \param new_proc a proc that will be called instead of original one.
|
|
/// \returns pointer, calling which will invoke original proc. It is user's responsibility to call original code when necessary.
|
|
void* hooker_hook(void* address, void* new_proc, size_t flags);
|
|
|
|
/// Unhook a hook created by hooker_hook(.., .., HOOKER_HOOK_REDIRECT, ..).
|
|
/// \param address where hook was written to.
|
|
/// \param original result of hooker_hook() call.
|
|
void hooker_unhook(void* address, void* original);
|
|
|
|
/// Return address in object's vmt which is pointing to specified method.
|
|
/// \param object is a pointer to a c++ object.
|
|
/// \param method is a pointer to a c++ object method.
|
|
size_t* hooker_get_vmt_address(void* object, void* method);
|
|
|
|
/// Find a first occurrence of memory pattern.
|
|
/// \param start a pointer to beginning of memory range.
|
|
/// \param size a size of memory range. If size is 0 then entire memory space will be searched. If pattern does not exist this will likely result in a crash. Negative size will search backwards.
|
|
/// \param pattern a array of bytes to search for.
|
|
/// \param pattern_len a length of pattern array.
|
|
/// \param wildcard byte in the pattern array. It must be of same size as indicated by `pattern_len`.
|
|
void* hooker_find_pattern(void* start, int size, const uint8_t* pattern, size_t pattern_len, uint8_t wildcard);
|
|
|
|
/// Find a first occurrence of memory pattern.
|
|
/// \param start a pointer to beginning of memory range.
|
|
/// \param size a size of memory range. If size is 0 then entire memory space will be searched. If pattern does not exist this will likely result in a crash. Negative size will search backwards.
|
|
/// \param pattern a array of bytes to search for.
|
|
/// \param pattern_len a length of pattern array.
|
|
/// \param wildcard array where values may be one of: 0? = 1, ?0 = 2, ?? = 3.
|
|
void* hooker_find_pattern_ex(void* start, int size, const uint8_t* pattern, size_t pattern_len, const uint8_t* wildcard);
|
|
|
|
/// Fill memory with nops (0x90 opcode).
|
|
/// \param start of the memory address.
|
|
/// \param size of the memory that will be filled.
|
|
/// \returns HOOKER_SUCCESS or HOOKER_ERROR.
|
|
bool hooker_nop(void* start, size_t size);
|
|
|
|
/// Write bytes to specified memory address.
|
|
/// \param start of the memory address.
|
|
/// \param data to be written.
|
|
/// \param size of data.
|
|
bool hooker_write(void* start, void* data, size_t size);
|
|
|
|
/// Searches for symbol in specified library. On Windows LoadLibrary() will be called if its not loaded yet, otherwise GetModuleHandle() will be used.
|
|
/// On linux dlopen(RTLD_NODELETE) and dlclose() will always be called.
|
|
/// \param lib_name string with dynamic library name.
|
|
/// \param sym_name string with exported symbol name.
|
|
/// \returns pointer to resolved dynamic symbol.
|
|
void* hooker_dlsym(const char* lib_name, const char* sym_name);
|
|
|
|
#if _WIN32
|
|
/// Replaces entry in import address table of specified module.
|
|
/// \param mod_name string with name of module whose import table is to be modified.
|
|
/// \param imp_mod_name string with name of module which module specified in `mod_name` imports.
|
|
/// \param imp_proc_name string with name of symbol imported from module specified in `imp_mod_name`.
|
|
/// \param new_proc a pointer that should replace old entry in import address table.
|
|
/// \returns original value that was in import address table or null pointer on failure.
|
|
void* hooker_hook_iat(const char* mod_name, const char* imp_mod_name, const char* imp_proc_name, void* new_proc);
|
|
#endif
|
|
|
|
// Define following macro in a single translation unit in order to use library without building it.
|
|
#ifdef HOOKER_IMPLEMENTATION
|
|
# include "hooker.c"
|
|
#endif // HOOKER_IMPLEMENTATION
|
|
|
|
#if __cplusplus
|
|
};
|
|
#endif
|