diff --git a/include/mach_detours.h b/include/mach_detours.h index 8961b93..5fa69a0 100644 --- a/include/mach_detours.h +++ b/include/mach_detours.h @@ -127,7 +127,7 @@ mach_error_t detour_manage_all_threads(); /// * If a previous `detour_attach` or `detour_detach` operation failed, returns the error code from that call. /// * `KERN_INVALID_ARGUMENT` if any of `detour`, `inout_pointer`, or `*inout_pointer` is nullptr /// * `detour_err_too_small` if the target function only points to the detour, or if the target function is too -/// short to insert a detour +/// short to insert a detour. See also `detour_set_ignore_too_small`. /// * `detour_err_too_large` if the instructions copied from the original function are too large to fit into the /// trampoline. This is likely a bug in mach_detours. /// * `KERN_RESOURCE_SHORTAGE` if `calloc` failed for the structure keeping track of the operation or the trampoline @@ -164,7 +164,7 @@ mach_error_t detour_attach_ex(detour_func_t* inout_pointer, detour_func_t detour /// * If a previous `detour_attach` or `detour_detach` operation failed, returns the error code from that call. /// * `KERN_INVALID_ARGUMENT` if any of `detour`, `inout_pointer`, or `*inout_pointer` is nullptr /// * `KERN_FAILURE` if `inout_pointer` or `detour` are not a valid combination, or that detour is not yet or no -/// longer committed. +/// longer committed. See also `detour_set_ignore_too_small`. /// * `KERN_RESOURCE_SHORTAGE` if `calloc` failed for the structure keeping track of the operation /// * If `mach_vm_region_recurse` fails on the target address, forwards its error code /// * If `mach_vm_protect` fails on the target address, forwards its error code @@ -193,9 +193,35 @@ mach_error_t detour_attach_and_commit_ex(detour_func_t* inout_pointer, detour_fu mach_error_t detour_detach_and_commit(detour_func_t* inout_pointer, detour_func_t detour); +/// @brief Toggle whether to ignore attach operation failures due to `detour_err_too_small` and detach operation +/// failures due to `KERN_FAILURE`. +/// +/// Default is `false`. If set to `true`, these failures will cause the attach/detach to abort but return `err_none`, as if +/// they were successful. +/// +/// @returns the previous state of the flag bool detour_set_ignore_too_small(bool value); + +/// @brief Toggle whether to free memory allocated for trampoline regions when they are empty. +/// +/// Default is `true` - free unused regions upon commit.
+/// `false` means they are not freed upon commit. Note that there is no way to manually free unused regions. +/// +/// @returns the previous state of the flag bool detour_set_retain_regions(bool value); + +/// @brief Sets the lower bound of the memory area that will not be used for detours trampoline regions +/// +/// Default is `0x70000000` +/// +/// @returns the previous state of the value void* detour_set_system_region_lower_bound(void* value); + +/// @brief Sets the upper bound of the memory area that will not be used for detours trampoline regions +/// +/// Default is `0x80000000` +/// +/// @returns the previous state of the value void* detour_set_system_region_upper_bound(void* value); #ifdef __cplusplus diff --git a/src/mach_detours.c b/src/mach_detours.c index 43cf435..d459486 100644 --- a/src/mach_detours.c +++ b/src/mach_detours.c @@ -658,11 +658,10 @@ mach_error_t detour_attach_ex(detour_func_t* inout_pointer, detour_func_t detour if (detour == (detour_func_t)target) { if (s_ignore_too_small) { goto stop; - } else { - DETOUR_BREAK(); - error = detour_err_too_small; - goto fail; } + error = detour_err_too_small; + DETOUR_BREAK(); + goto fail; } if (out_real_target) { @@ -677,6 +676,7 @@ mach_error_t detour_attach_ex(detour_func_t* inout_pointer, detour_func_t detour error = KERN_RESOURCE_SHORTAGE; fail: s_pending_error = error; + s_pending_error_pointer = inout_pointer; DETOUR_BREAK(); stop: if (trampoline) { @@ -698,7 +698,6 @@ mach_error_t detour_attach_ex(detour_func_t* inout_pointer, detour_func_t detour if (out_real_target) { *out_real_target = nullptr; } - s_pending_error_pointer = inout_pointer; return error; } @@ -771,13 +770,12 @@ mach_error_t detour_attach_ex(detour_func_t* inout_pointer, detour_func_t detour if (target_override_len < DETOUR_PLATFORM_SIZE_OF_JMP || align_idx > ARRAYSIZE(trampoline->align)) { // Too few instructions. - error = detour_err_too_small; if (s_ignore_too_small) { goto stop; - } else { - DETOUR_BREAK(); - goto fail; } + error = detour_err_too_small; + DETOUR_BREAK(); + goto fail; } if (trampoline_code > trampoline_code_limit) { @@ -892,12 +890,12 @@ mach_error_t detour_detach(detour_func_t* inout_pointer, detour_func_t detour) error = KERN_RESOURCE_SHORTAGE; fail: s_pending_error = error; + s_pending_error_pointer = inout_pointer; DETOUR_BREAK(); stop: free(op); // ReSharper disable once CppDFAUnusedValue op = nullptr; - s_pending_error_pointer = inout_pointer; return error; } @@ -908,23 +906,21 @@ mach_error_t detour_detach(detour_func_t* inout_pointer, detour_func_t detour) const uint32_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; } + error = KERN_FAILURE; + DETOUR_BREAK(); + goto fail; } if (trampoline->ptr_detour != detour) { - error = KERN_FAILURE; if (s_ignore_too_small) { goto stop; - } else { - DETOUR_BREAK(); - goto fail; } + error = KERN_FAILURE; + DETOUR_BREAK(); + goto fail; } const mach_port_t port = mach_task_self();