From ade0920e54193a37cdfa8e2b80fec65d46ceca4c Mon Sep 17 00:00:00 2001 From: Lysann Tranvouez Date: Mon, 29 Sep 2025 23:53:05 +0200 Subject: [PATCH] detour_detach + some setters --- include/mach_detours.h | 5 ++ src/mach_detours.c | 135 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 139 insertions(+), 1 deletion(-) diff --git a/include/mach_detours.h b/include/mach_detours.h index 1cf57fa..97ef6b5 100644 --- a/include/mach_detours.h +++ b/include/mach_detours.h @@ -26,4 +26,9 @@ mach_error_t detour_attach(detour_func_t* inout_pointer, detour_func_t detour); mach_error_t detour_attach_ex(detour_func_t* inout_pointer, detour_func_t detour, detour_func_t* out_real_trampoline, detour_func_t* out_real_target, detour_func_t* out_real_detour); mach_error_t detour_detach(detour_func_t* inout_pointer, detour_func_t detour); +bool detour_set_ignore_too_small(bool value); +bool detour_set_retain_regions(bool value); +void* detour_set_system_region_lower_bound(void* value); +void* detour_set_system_region_upper_bound(void* value); + #endif // MACH_DETOURS_H diff --git a/src/mach_detours.c b/src/mach_detours.c index 4b10c5e..0340257 100644 --- a/src/mach_detours.c +++ b/src/mach_detours.c @@ -9,7 +9,7 @@ #define DETOURS_ARM64 #define DETOURS_64BIT #else -#error Unsupported architecture (arm64) +#error Unsupported architecture (supported: arm64) #endif #include "detours_internal.h" @@ -640,6 +640,9 @@ mach_error_t detour_manage_thread(thread_t thread) return err_none; } +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Attach/Detach + mach_error_t detour_attach(detour_func_t* inout_pointer, detour_func_t detour) { return detour_attach_ex(inout_pointer, detour, nullptr, nullptr, nullptr); @@ -898,3 +901,133 @@ mach_error_t detour_attach_ex(detour_func_t* inout_pointer, detour_func_t detour return err_none; } + +mach_error_t detour_detach(detour_func_t* inout_pointer, detour_func_t detour) +{ + if (s_transaction_thread != mach_thread_self()) { + return detour_err_wrong_thread; + } + + // If any of the pending operations failed, then we don't need to do this. + if (s_pending_error != err_none) { + return s_pending_error; + } + + if (!detour) { + return KERN_INVALID_ARGUMENT; + } + if (!inout_pointer) { + return KERN_INVALID_ARGUMENT; + } + if (!(*inout_pointer)) { + s_pending_error = KERN_INVALID_ARGUMENT; + s_pending_error_pointer = inout_pointer; + DETOUR_BREAK(); + return s_pending_error; + } + + mach_error_t error = err_none; + + detour_operation* op = calloc(1, sizeof(detour_operation)); + if (!op) { + error = KERN_RESOURCE_SHORTAGE; + fail: + s_pending_error = error; + DETOUR_BREAK(); + stop: + free(op); + // ReSharper disable once CppDFAUnusedValue + op = nullptr; + s_pending_error_pointer = inout_pointer; + return error; + } + + detour_trampoline* trampoline = (detour_trampoline*)internal_detour_skip_jmp(*inout_pointer); + detour = internal_detour_skip_jmp(detour); + + // Verify that Trampoline is in place. + const int32_t restore_code_size = trampoline->restore_code_size; + uint8_t* target = trampoline->ptr_remain - restore_code_size; + if (restore_code_size == 0 || restore_code_size > sizeof(trampoline->code)) { + error = KERN_FAILURE; + if (s_ignore_too_small) { + goto stop; + } else { + DETOUR_BREAK(); + goto fail; + } + } + + if (trampoline->ptr_detour != detour) { + error = KERN_FAILURE; + if (s_ignore_too_small) { + goto stop; + } else { + DETOUR_BREAK(); + goto fail; + } + } + + const mach_port_t port = mach_task_self(); + + vm_region_submap_short_info_data_64_t region_info; + { + mach_vm_address_t region_addr = (mach_vm_address_t)target; + mach_vm_size_t region_size = 0; + natural_t nesting_depth = 99999; + mach_msg_type_number_t count = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64; + error = mach_vm_region_recurse(port, ®ion_addr, ®ion_size, &nesting_depth, (vm_region_recurse_info_t)®ion_info, &count); + if (error != err_none) { + DETOUR_BREAK(); + goto fail; + } + } + const vm_prot_t old_perm = region_info.protection; + + error = mach_vm_protect(port, (mach_vm_address_t)target, PAGE_SIZE, false, VM_PROT_READ | VM_PROT_WRITE | VM_PROT_COPY); + if (error != err_none) { + DETOUR_BREAK(); + goto fail; + } + + op->kind = detour_operation_kind_detach; + op->pointer = (uint8_t**)inout_pointer; + op->trampoline = trampoline; + op->target = target; + op->perm = old_perm; + op->next = s_pending_operations_head; + s_pending_operations_head = op; + + return ERR_SUCCESS; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// API Setters + +bool detour_set_ignore_too_small(const bool value) +{ + const bool previous = s_ignore_too_small; + s_ignore_too_small = value; + return previous; +} + +bool detour_set_retain_regions(const bool value) +{ + const bool previous = s_retain_regions; + s_retain_regions = value; + return previous; +} + +void* detour_set_system_region_lower_bound(void* value) +{ + void* previous = s_system_region_lower_bound; + s_system_region_lower_bound = value; + return previous; +} + +void* detour_set_system_region_upper_bound(void* value) +{ + void* previous = s_system_region_upper_bound; + s_system_region_upper_bound = value; + return previous; +}