// Copyright (c) Microsoft Corporation. All rights reserved. // Copyright (c) Lysann Tranvouez. All rights reserved. #pragma once #ifndef MACH_DETOURS_H #define MACH_DETOURS_H #ifdef __cplusplus extern "C" { #endif #include #include typedef void* detour_func_t; #define detour_err_in_progress (err_local | 1) #define detour_err_wrong_thread (err_local | 2) #define detour_err_too_small (err_local | 3) #define detour_err_too_large (err_local | 4) /// Begin a new transaction on the current thread /// /// @note This will mark all trampoline regions as writable and not executable. Until the transaction is committed or /// aborted, no thread can execute the trampoline code. If any threads might be doing that, consider using /// detour_transaction_begin_managed instead, to ensure all threads are suspended. mach_error_t detour_transaction_begin(); /// Begin a new transaction on the current thread and immediately manage all (other) threads /// @see `detour_transaction_begin` /// @see `detour_manage_all_threads` mach_error_t detour_transaction_begin_managed(); /// @note Requires an active transaction started on the current thread. If there is no transaction active at all, the /// function has no effect. mach_error_t detour_transaction_abort(); /// @see `detour_transaction_commit_ex` mach_error_t detour_transaction_commit(); /// @note Requires an active transaction started on the current thread. mach_error_t detour_transaction_commit_ex(detour_func_t** out_failed_target); /// Suspends the given thread and marks it as pending. It will be resumed when the transaction is committed or aborted. /// @note Requires an active transaction started on the current thread. /// @note Calling this function with the transaction thread has no effect. mach_error_t detour_manage_thread(thread_t thread); /// Manages all threads via `detour_manage_thread` /// @see `detour_manage_thread` /// @note Requires an active transaction started on the current thread. mach_error_t detour_manage_all_threads(); /// @see `detour_attach_ex` mach_error_t detour_attach(detour_func_t* inout_pointer, detour_func_t detour); /// @note Requires an active transaction started on the current thread. /// @note After calling this function, the memory page containing the target function (*inout_pointer) is no longer /// executable, until you call either commit or abort the current transaction. Due to this, you might run into /// EXC_BAD_ACCESS when hooking into local functions in the same executable as the calling function. /// You can use detour_attach_and_commit/detour_attach_and_commit_ex instead in this case.
/// Similarly, no caller can execute the target function (whether local or not), including the transaction thread. /// Make sure to detour_manage_thread/detour_manage_all_threads in this case. 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); /// @note Requires an active transaction started on the current thread. /// @note After calling this function, the memory page containing the target function (*inout_pointer) is no longer /// executable, until you call either commit or abort the current transaction. Due to this, you might run into /// EXC_BAD_ACCESS when hooking into local functions in the same executable as the calling function. /// You can use detour_detach_and_commit instead in this case. mach_error_t detour_detach(detour_func_t* inout_pointer, detour_func_t detour); /// Same as calling `detour_attach(inout_pointer, detour)` and `detour_transaction_commit()` /// @see `detour_attach` /// @see `detour_transaction_commit` mach_error_t detour_attach_and_commit(detour_func_t* inout_pointer, detour_func_t detour); /// Same as calling `detour_attach_ex(inout_pointer, detour, out_real_trampoline, out_real_target, out_real_detour)` and `detour_transaction_commit()` /// @see `detour_attach_ex` /// @see `detour_transaction_commit` mach_error_t detour_attach_and_commit_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); /// Same as calling `detour_detach(inout_pointer, detour)` and `detour_transaction_commit()` /// @see `detour_detach` /// @see `detour_transaction_commit` mach_error_t detour_detach_and_commit(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); #ifdef __cplusplus } #endif #endif // MACH_DETOURS_H