detour_detach + some setters

This commit is contained in:
Lysann Tranvouez 2025-09-29 23:53:05 +02:00
parent e04585377a
commit ade0920e54
2 changed files with 139 additions and 1 deletions

View file

@ -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

View file

@ -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, &region_addr, &region_size, &nesting_depth, (vm_region_recurse_info_t)&region_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;
}