|
102 Patches: Detours to the Rescue
C reference for DttR maintainers and modders.
|
#include "core_internal.h"#include <dttr_log.h>#include <dttr_sigscan.h>#include <Zydis/Zydis.h>#include <khash.h>#include <kvec.h>#include <psapi.h>#include <xxhash.h>#include <limits.h>#include <stdio.h>#include <stdlib.h>#include <string.h>Go to the source code of this file.
Data Structures | |
| struct | DTTR_Core_Hook |
| struct | hook_chain |
| struct | trampoline_insn |
Macros | |
| #define | DTTR_HOOK_PATCH_SIZE 5u |
| #define | DTTR_HOOK_MIN_PROLOGUE 5u |
| #define | DTTR_HOOK_MAX_PROLOGUE 64u |
| #define | DTTR_HOOK_MAX_INSN 32u |
Typedefs | |
| typedef struct hook_chain | hook_chain |
Enumerations | |
| enum | hook_record_kind { DTTR_HOOK_RECORD_PATCH = 0 , DTTR_HOOK_RECORD_FUNCTION = 1 } |
Functions | |
| uintptr_t | DTTR_Core_HookSigscan (HMODULE mod, const char *sig, const char *mask) |
| DTTR_Result | dttr_core_hook_last_error () |
| void | dttr_core_hook_set_last_error (DTTR_Status status, const char *message) |
| static void | hook_error_clear () |
| static bool | decoder_init () |
| static bool | is_readable_page_protect (DWORD protect) |
| static bool | copy_memory_checked (uintptr_t addr, uint8_t *out, size_t size) |
| static void | log_prologue_bytes (uintptr_t site, const uint8_t *bytes, size_t size) |
| static bool | decode_prologue (uintptr_t addr, int requested_size, trampoline_insn *insns, size_t *out_insn_count, size_t *out_prologue_size, uint8_t *out_prologue_bytes, size_t out_prologue_bytes_cap) |
| static bool | trampoline_relocate (uint8_t *trampoline, uintptr_t site, const trampoline_insn *insns, size_t insn_count) |
| static | khash_t (sigscan_cache) |
| uintptr_t | DTTR_Core_HookCachedSigscan (HMODULE mod, const char *sig, const char *mask) |
| typedef | kvec_t (DTTR_Core_Hook *) |
| static void | hook_chain_destroy (hook_chain *chain) |
| static bool | check_overlap (uintptr_t addr, size_t size) |
| static DTTR_Core_Hook * | hook_create (const char *op, uintptr_t addr, size_t size) |
| static size_t | hook_find_index (DTTR_Core_Hook *hook) |
| static hook_chain * | hook_find_function_chain (uintptr_t addr) |
| static void | flush_patched_range (const char *op, uintptr_t addr, size_t size) |
| static bool | write_bytes (const char *op, uintptr_t addr, const uint8_t *bytes, size_t size) |
| static bool | build_rel32_jump (uintptr_t site, void *target, uint8_t out[DTTR_HOOK_PATCH_SIZE]) |
| static bool | write_function_jump (uintptr_t site, void *target) |
| static bool | hook_thunk_set_target (uint8_t *thunk, void *target) |
| static void * | function_link_next_target (const DTTR_Core_Hook *hook) |
| static DTTR_Core_Hook * | function_link_create (hook_chain *chain, void *detour, void *next_target) |
| static bool | function_chain_push_head (hook_chain *chain, DTTR_Core_Hook *hook, void **out_original) |
| static DTTR_Core_Hook * | function_chain_append (hook_chain *chain, void *handler, void **out_original) |
| static bool | function_link_detach (DTTR_Core_Hook *hook) |
| static bool | hook_detach_index (size_t index) |
| DTTR_Core_Hook * | DTTR_Core_HookAttachFunction (uintptr_t addr, int prologue_size, void *handler, void **out_original) |
| DTTR_Core_Hook * | DTTR_Core_HookAttachPointer (uintptr_t addr, void *new_value, void **out_original) |
| DTTR_Core_Hook * | DTTR_Core_HookPatchBytes (uintptr_t addr, const uint8_t *bytes, size_t size) |
| bool | DTTR_Core_HookDetachChecked (DTTR_Core_Hook *hook) |
| void | DTTR_Core_HookDetach (DTTR_Core_Hook *hook) |
| bool | DTTR_Core_HookIsActive (DTTR_Core_Hook *hook) |
| bool | DTTR_Core_HookDetachOwnerChecked (void *owner) |
| void * | DTTR_Core_HookSetOwner (void *owner) |
| void | DTTR_Core_HookDetachOwner (void *owner) |
| static void | cleanup_sigscan_cache () |
| bool | DTTR_Core_HookCleanupAllChecked () |
| void | DTTR_Core_HookCleanupAll () |
| Detach all remaining hooks and free the sigscan cache. | |
Variables | |
| static ZydisDecoder | decoder |
| static bool | decoder_initialized = false |
| static DTTR_Result | hook_last_error = {DTTR_OK, "ok"} |
| #define DTTR_HOOK_MAX_INSN 32u |
Definition at line 72 of file hook_registry.c.
Referenced by decode_prologue(), and DTTR_Core_HookAttachFunction().
| #define DTTR_HOOK_MAX_PROLOGUE 64u |
Definition at line 71 of file hook_registry.c.
Referenced by decode_prologue(), DTTR_Core_HookAttachFunction(), and log_prologue_bytes().
| #define DTTR_HOOK_MIN_PROLOGUE 5u |
Definition at line 70 of file hook_registry.c.
Referenced by decode_prologue().
| #define DTTR_HOOK_PATCH_SIZE 5u |
Definition at line 69 of file hook_registry.c.
Referenced by build_rel32_jump(), DTTR_Core_HookAttachFunction(), and write_function_jump().
| typedef struct hook_chain hook_chain |
Definition at line 22 of file hook_registry.c.
| enum hook_record_kind |
| Enumerator | |
|---|---|
| DTTR_HOOK_RECORD_PATCH | |
| DTTR_HOOK_RECORD_FUNCTION | |
Definition at line 17 of file hook_registry.c.
|
static |
Definition at line 626 of file hook_registry.c.
References DTTR_HOOK_PATCH_SIZE, and target.
Referenced by write_function_jump().
|
static |
Definition at line 540 of file hook_registry.c.
References DTTR_LOG_WARN, h, and size.
Referenced by DTTR_Core_HookAttachFunction(), and DTTR_Core_HookPatchBytes().
|
static |
Definition at line 1115 of file hook_registry.c.
References NULL.
Referenced by DTTR_Core_HookCleanupAllChecked().
|
static |
Definition at line 136 of file hook_registry.c.
References DTTR_LOG_ERROR, is_readable_page_protect(), and size.
Referenced by decode_prologue().
|
static |
Definition at line 219 of file hook_registry.c.
References copy_memory_checked(), count, decoder, decoder_init(), DTTR_HOOK_MAX_INSN, DTTR_HOOK_MAX_PROLOGUE, DTTR_HOOK_MIN_PROLOGUE, DTTR_LOG_DEBUG, DTTR_LOG_ERROR, DTTR_LOG_WARN, trampoline_insn::length, log_prologue_bytes(), NULL, trampoline_insn::offset, trampoline_insn::rel_offset, and trampoline_insn::rel_size.
Referenced by DTTR_Core_HookAttachFunction().
|
static |
Definition at line 97 of file hook_registry.c.
References decoder, decoder_initialized, and DTTR_LOG_ERROR.
Referenced by decode_prologue().
| DTTR_Result dttr_core_hook_last_error | ( | ) |
Definition at line 85 of file hook_registry.c.
References hook_last_error.
Referenced by DTTR_Core_HookFunction().
| void dttr_core_hook_set_last_error | ( | DTTR_Status | status, |
| const char * | message ) |
Definition at line 89 of file hook_registry.c.
References dttr_core_result(), and hook_last_error.
Referenced by DTTR_Core_HookAttachFunction(), and hook_error_clear().
| DTTR_Core_Hook * DTTR_Core_HookAttachFunction | ( | uintptr_t | addr, |
| int | prologue_size, | ||
| void * | handler, | ||
| void ** | out_original ) |
Install a JMP hook and optionally return the trampoline.
| addr | Function entry or instruction site to hook. |
| prologue_size | Minimum prologue bytes for the hook injection site, or 0 for automatic sizing. |
| handler | Replacement function to call. |
| out_original | Optional output receiving the original trampoline. |
Definition at line 861 of file hook_registry.c.
References hook_chain::addr, check_overlap(), decode_prologue(), dttr_core_hook_set_last_error(), DTTR_ERR_HOOK_CHAIN_UNSUPPORTED, DTTR_HOOK_MAX_INSN, DTTR_HOOK_MAX_PROLOGUE, DTTR_HOOK_PATCH_SIZE, DTTR_LOG_DEBUG, DTTR_LOG_ERROR, DTTR_LOG_WARN, free, function_chain_append(), function_chain_push_head(), function_link_create(), hook_chain_destroy(), hook_error_clear(), hook_find_function_chain(), NULL, hook_chain::original, hook_chain::patch_size, hook_chain::prologue_size, hook_chain::trampoline, and trampoline_relocate().
Referenced by test_function_hooks_chain_and_detach().
| DTTR_Core_Hook * DTTR_Core_HookAttachPointer | ( | uintptr_t | addr, |
| void * | new_value, | ||
| void ** | out_original ) |
Patch a pointer or IAT slot and optionally return the previous value.
| addr | Address of the pointer slot to replace. |
| new_value | Replacement pointer value. |
| out_original | Optional output receiving the previous pointer value. |
Definition at line 1010 of file hook_registry.c.
References DTTR_Core_HookPatchBytes(), DTTR_LOG_ERROR, and NULL.
Referenced by test_pointer_hook_detach_restores_original().
| uintptr_t DTTR_Core_HookCachedSigscan | ( | HMODULE | mod, |
| const char * | sig, | ||
| const char * | mask ) |
Scan a module with the runtime signature cache.
| mod | Module to scan. |
| sig | Raw byte signature buffer. |
| mask | Mask string where implementation-defined wildcard characters skip bytes. |
Definition at line 467 of file hook_registry.c.
References DTTR_Core_HookSigscan().
| void DTTR_Core_HookCleanupAll | ( | ) |
Detach all remaining hooks and free the sigscan cache.
Definition at line 1142 of file hook_registry.c.
References DTTR_Core_HookCleanupAllChecked(), and DTTR_LOG_ERROR.
Referenced by cleanup_runtime(), test_cleanup_all_restores_hooks_and_allows_reuse(), test_function_hooks_chain_and_detach(), test_overlapping_byte_patches_are_rejected(), test_owner_detach_only_detaches_matching_owner(), test_patch_bytes_detach_restores_original(), test_patch_group_target_failure_rolls_back_only_new_entries(), and test_pointer_hook_detach_restores_original().
| bool DTTR_Core_HookCleanupAllChecked | ( | ) |
Detach all remaining hooks, free the sigscan cache, and report restore failures.
Definition at line 1122 of file hook_registry.c.
References cleanup_sigscan_cache(), hook_detach_index(), and NULL.
Referenced by DTTR_Core_HookCleanupAll().
| void DTTR_Core_HookDetach | ( | DTTR_Core_Hook * | hook | ) |
Detach one hook or patch.
| hook | Hook or patch handle returned by this runtime, or NULL. |
Definition at line 1078 of file hook_registry.c.
References DTTR_Core_HookDetachChecked().
Referenced by test_function_hooks_chain_and_detach(), test_overlapping_byte_patches_are_rejected(), test_patch_bytes_detach_restores_original(), and test_pointer_hook_detach_restores_original().
| bool DTTR_Core_HookDetachChecked | ( | DTTR_Core_Hook * | hook | ) |
Detach one hook or patch and report restore failure.
| hook | Hook or patch handle returned by this runtime, or NULL. |
Definition at line 1063 of file hook_registry.c.
References DTTR_LOG_DEBUG, hook_detach_index(), and hook_find_index().
Referenced by DTTR_Core_HookDetach(), DTTR_Core_Unhook(), DTTR_Core_Unpatch(), and patch_group_detach_checked().
Detach hooks tagged with the given owner.
| owner | Owner pointer previously active when hooks or byte patches were created. |
Definition at line 1111 of file hook_registry.c.
References DTTR_Core_HookDetachOwnerChecked().
Referenced by test_owner_detach_only_detaches_matching_owner().
| bool DTTR_Core_HookDetachOwnerChecked | ( | void * | owner | ) |
Detach hooks tagged with the given owner and report restore failures.
| owner | Owner pointer previously active when hooks or byte patches were created. |
Definition at line 1086 of file hook_registry.c.
References hook_detach_index().
Referenced by DTTR_Core_HookDetachOwner(), and unload_mod().
| bool DTTR_Core_HookIsActive | ( | DTTR_Core_Hook * | hook | ) |
Report whether a hook handle is still registered with the runtime.
| hook | Hook or patch handle returned by this runtime, or NULL. |
Definition at line 1082 of file hook_registry.c.
References hook_find_index().
Referenced by dttr_pcdogs_hook_is_active().
| DTTR_Core_Hook * DTTR_Core_HookPatchBytes | ( | uintptr_t | addr, |
| const uint8_t * | bytes, | ||
| size_t | size ) |
Patch bytes and keep the originals for detach.
| addr | Address to patch. |
| bytes | Replacement bytes to write. |
| size | Number of replacement bytes. |
Definition at line 1029 of file hook_registry.c.
References check_overlap(), DTTR_LOG_ERROR, hook_create(), NULL, DTTR_Core_Hook::original, size, and write_bytes().
Referenced by DTTR_Core_HookAttachPointer(), install_win_main_hook(), test_cleanup_all_restores_hooks_and_allows_reuse(), test_overlapping_byte_patches_are_rejected(), test_owner_detach_only_detaches_matching_owner(), and test_patch_bytes_detach_restores_original().
Set the owner tag for subsequent hooks and return the previous owner.
| owner | Opaque owner pointer assigned to hooks or byte patches created after this call. |
The owner tag is process-global runtime state. Save the returned owner and restore it before returning from a callback if you set it manually.
Definition at line 1104 of file hook_registry.c.
Referenced by init_mod(), and test_owner_detach_only_detaches_matching_owner().
| uintptr_t DTTR_Core_HookSigscan | ( | HMODULE | mod, |
| const char * | sig, | ||
| const char * | mask ) |
Scan a module for the first matching signature.
| mod | Module to scan. |
| sig | Raw byte signature buffer. |
| mask | Mask string where implementation-defined wildcard characters skip bytes. |
Definition at line 48 of file hook_registry.c.
References DTTR_Sigscan_Bytes(), and size.
Referenced by DTTR_Core_AOBFindInModule(), DTTR_Core_HookCachedSigscan(), and install_win_main_hook().
|
static |
Definition at line 607 of file hook_registry.c.
References DTTR_LOG_WARN, and size.
Referenced by hook_thunk_set_target(), and write_bytes().
|
static |
Definition at line 752 of file hook_registry.c.
References DTTR_Core_Hook::detour, function_chain_push_head(), function_link_create(), hook_chain::head, NULL, and hook_chain::trampoline.
Referenced by DTTR_Core_HookAttachFunction().
|
static |
Definition at line 719 of file hook_registry.c.
References hook_chain::addr, DTTR_Core_Hook::detour, hook_chain::head, DTTR_Core_Hook::next, DTTR_Core_Hook::next_thunk, NULL, DTTR_Core_Hook::prev, hook_chain::tail, and write_function_jump().
Referenced by DTTR_Core_HookAttachFunction(), and function_chain_append().
|
static |
Definition at line 680 of file hook_registry.c.
References DTTR_Core_Hook::addr, hook_chain::addr, DTTR_Core_Hook::chain, DTTR_Core_Hook::detour, DTTR_HOOK_RECORD_FUNCTION, DTTR_LOG_ERROR, free, hook_thunk_set_target(), DTTR_Core_Hook::kind, DTTR_Core_Hook::next_thunk, NULL, DTTR_Core_Hook::owner, hook_chain::patch_size, and DTTR_Core_Hook::size.
Referenced by DTTR_Core_HookAttachFunction(), and function_chain_append().
|
static |
Definition at line 775 of file hook_registry.c.
References hook_chain::addr, DTTR_Core_Hook::chain, DTTR_Core_Hook::detour, DTTR_LOG_ERROR, function_link_next_target(), hook_chain::head, hook_chain_destroy(), hook_thunk_set_target(), DTTR_Core_Hook::next, DTTR_Core_Hook::next_thunk, NULL, hook_chain::original, hook_chain::patch_size, DTTR_Core_Hook::prev, hook_chain::tail, write_bytes(), and write_function_jump().
Referenced by hook_detach_index().
|
static |
Definition at line 672 of file hook_registry.c.
References DTTR_Core_Hook::chain, DTTR_Core_Hook::detour, DTTR_Core_Hook::next, NULL, and hook_chain::trampoline.
Referenced by function_link_detach().
|
static |
Definition at line 526 of file hook_registry.c.
References free, hook_chain::original, and hook_chain::trampoline.
Referenced by DTTR_Core_HookAttachFunction(), and function_link_detach().
|
static |
Definition at line 563 of file hook_registry.c.
References DTTR_Core_Hook::addr, DTTR_LOG_ERROR, free, NULL, DTTR_Core_Hook::original, DTTR_Core_Hook::owner, DTTR_Core_Hook::size, and size.
Referenced by DTTR_Core_HookPatchBytes().
|
static |
Definition at line 833 of file hook_registry.c.
References DTTR_Core_Hook::addr, DTTR_HOOK_RECORD_FUNCTION, DTTR_LOG_ERROR, function_link_detach(), DTTR_Core_Hook::kind, DTTR_Core_Hook::original, DTTR_Core_Hook::size, and write_bytes().
Referenced by DTTR_Core_HookCleanupAllChecked(), DTTR_Core_HookDetachChecked(), and DTTR_Core_HookDetachOwnerChecked().
|
static |
Definition at line 93 of file hook_registry.c.
References dttr_core_hook_set_last_error(), and DTTR_OK.
Referenced by DTTR_Core_HookAttachFunction().
|
static |
Definition at line 594 of file hook_registry.c.
References hook_chain::addr, DTTR_Core_Hook::chain, DTTR_HOOK_RECORD_FUNCTION, DTTR_Core_Hook::kind, and NULL.
Referenced by DTTR_Core_HookAttachFunction().
|
static |
Definition at line 584 of file hook_registry.c.
Referenced by DTTR_Core_HookDetachChecked(), and DTTR_Core_HookIsActive().
|
static |
Definition at line 657 of file hook_registry.c.
References flush_patched_range(), and target.
Referenced by function_link_create(), and function_link_detach().
|
static |
Definition at line 120 of file hook_registry.c.
References DWORD.
Referenced by copy_memory_checked().
|
static |
Definition at line 453 of file hook_registry.c.
| typedef kvec_t | ( | DTTR_Core_Hook * | ) |
Definition at line 499 of file hook_registry.c.
References DTTR_HOOK_RECORD_FUNCTION, free, DTTR_Core_Hook::kind, DTTR_Core_Hook::next_thunk, NULL, DTTR_Core_Hook::original, and DTTR_Core_Hook::trampoline.
|
static |
Definition at line 184 of file hook_registry.c.
References DTTR_HOOK_MAX_PROLOGUE, DTTR_LOG_DEBUG, size, and w.
Referenced by decode_prologue().
|
static |
Definition at line 397 of file hook_registry.c.
References DTTR_LOG_DEBUG, DTTR_LOG_ERROR, trampoline_insn::length, trampoline_insn::offset, trampoline_insn::rel_offset, and trampoline_insn::rel_size.
Referenced by DTTR_Core_HookAttachFunction().
|
static |
Definition at line 613 of file hook_registry.c.
References DTTR_LOG_ERROR, DWORD, flush_patched_range(), and size.
Referenced by DTTR_Core_HookPatchBytes(), function_link_detach(), hook_detach_index(), and write_function_jump().
|
static |
Definition at line 643 of file hook_registry.c.
References build_rel32_jump(), DTTR_HOOK_PATCH_SIZE, DTTR_LOG_ERROR, target, and write_bytes().
Referenced by function_chain_push_head(), and function_link_detach().
|
static |
Definition at line 81 of file hook_registry.c.
Referenced by append_disassembly_from_bytes(), append_failed_instruction_decode(), decode_prologue(), decoder_init(), dttr_test_zydis_decode32(), format_instruction_at(), and zydis_decoder32().
|
static |
Definition at line 82 of file hook_registry.c.
Referenced by decoder_init().
|
static |
Definition at line 83 of file hook_registry.c.
Referenced by dttr_core_hook_last_error(), and dttr_core_hook_set_last_error().