diff --git a/src/arm64/detours_arm64.h b/src/arm64/detours_arm64.h index aca654a..36c4f92 100644 --- a/src/arm64/detours_arm64.h +++ b/src/arm64/detours_arm64.h @@ -53,17 +53,17 @@ static_assert(sizeof(detour_trampoline)== 192); enum { - DETOUR_SIZE_OF_JMP = 12 + DETOUR_PLATFORM_SIZE_OF_JMP = 12 }; typedef uint32_t detour_arm64_opcode_t; -static inline detour_arm64_opcode_t fetch_opcode(const uint8_t* code) +static inline detour_arm64_opcode_t detour_arm64_fetch_opcode(const uint8_t* code) { return *(detour_arm64_opcode_t*)code; } -static inline void write_opcode(uint8_t** int_out_code, const detour_arm64_opcode_t opcode) +static inline void detour_arm64_write_opcode(uint8_t** int_out_code, const detour_arm64_opcode_t opcode) { uint8_t* code = *int_out_code; *(detour_arm64_opcode_t*)code = opcode; @@ -108,7 +108,7 @@ union detour_arm64_indirect_imm uint64_t value; }; -static inline uint8_t* internal_detour_gen_jmp_indirect(uint8_t* code, const uint64_t* jump_val) +static inline uint8_t* detour_arm64_gen_jmp_indirect(uint8_t* code, const uint64_t* jump_val) { // adrp x17, [jmpval] // ldr x17, [x17, jmpval] @@ -142,7 +142,7 @@ static inline uint8_t* internal_detour_gen_jmp_indirect(uint8_t* code, const uin return code; } -static inline uint8_t* internal_detour_gen_jmp_immediate(uint8_t* code, uint8_t** inout_code_limit, uint8_t* jmp_val) +static inline uint8_t* detour_platform_gen_jmp_immediate(uint8_t* code, uint8_t** inout_code_limit, uint8_t* jmp_val) { *inout_code_limit = *inout_code_limit - 8; uint8_t* literal = *inout_code_limit; @@ -150,21 +150,21 @@ static inline uint8_t* internal_detour_gen_jmp_immediate(uint8_t* code, uint8_t* *(uint8_t**)literal = jmp_val; const int32_t delta = (int32_t)(literal - code); - write_opcode(&code, 0x58000011 | ((delta / 4) << 5)); // LDR X17,[PC+n] - write_opcode(&code, 0xd61f0000 | (17 << 5)); // BR X17 + detour_arm64_write_opcode(&code, 0x58000011 | ((delta / 4) << 5)); // LDR X17,[PC+n] + detour_arm64_write_opcode(&code, 0xd61f0000 | (17 << 5)); // BR X17 return code; } -static inline uint8_t* internal_detour_gen_brk(uint8_t* code, const uint8_t* limit) +static inline uint8_t* detour_platform_gen_brk(uint8_t* code, const uint8_t* limit) { while (code < limit) { - write_opcode(&code, 0xd4100000 | (0xf000 << 5)); + detour_arm64_write_opcode(&code, 0xd4100000 | (0xf000 << 5)); } return code; } -static inline void internal_detour_find_jmp_bounds(uint8_t* code, detour_trampoline** out_lower, +static inline void detour_platform_find_jmp_bounds(uint8_t* code, detour_trampoline** out_lower, detour_trampoline** out_upper) { // The encoding used by detour_gen_jmp_indirect actually enables a @@ -179,12 +179,12 @@ static inline void internal_detour_find_jmp_bounds(uint8_t* code, detour_trampol *out_upper = (detour_trampoline*)hi; } -static inline bool internal_detour_is_code_os_patched(const uint8_t* code) +static inline bool detour_arm64_is_code_os_patched(const uint8_t* code) { // Identify whether the provided code pointer is a OS patch jump. // We can do this by checking if a branch (b ) is present, and if so, // it must be jumping to an HPAT page containing ldr [PC+PAGE_SIZE-4], br . - const uint32_t opcode = fetch_opcode(code); + const uint32_t opcode = detour_arm64_fetch_opcode(code); if ((opcode & 0xfc000000) != 0x14000000) { return false; @@ -198,8 +198,8 @@ static inline bool internal_detour_is_code_os_patched(const uint8_t* code) const uint8_t* branch_target = code + delta; // Now inspect the opcodes of the code we jumped to in order to determine if it's HPAT. - const uint32_t hpat_opcode1 = fetch_opcode(branch_target); - const uint32_t hpat_opcode2 = fetch_opcode(branch_target + 4); + const uint32_t hpat_opcode1 = detour_arm64_fetch_opcode(branch_target); + const uint32_t hpat_opcode2 = detour_arm64_fetch_opcode(branch_target + 4); if (hpat_opcode1 != 0x58008010) { // ldr [PC+PAGE_SIZE] return false; @@ -210,12 +210,12 @@ static inline bool internal_detour_is_code_os_patched(const uint8_t* code) return true; } -static inline bool internal_detour_does_code_end_function(const uint8_t* code) +static inline bool detour_platform_does_code_end_function(const uint8_t* code) { - const uint32_t opcode = fetch_opcode(code); + const uint32_t opcode = detour_arm64_fetch_opcode(code); // When the OS has patched a function entry point, it will incorrectly // appear as though the function is just a single branch instruction. - if (internal_detour_is_code_os_patched(code)) { + if (detour_arm64_is_code_os_patched(code)) { return false; } if ((opcode & 0xffbffc1f) == 0xd61f0000 || // ret/br @@ -225,7 +225,7 @@ static inline bool internal_detour_does_code_end_function(const uint8_t* code) return false; } -static inline uint32_t internal_detour_is_code_filler(const uint8_t* code) +static inline uint32_t detour_platform_is_code_filler(const uint8_t* code) { if (*(uint32_t*)code == 0xd503201f) { // nop. return 4; @@ -236,31 +236,31 @@ static inline uint32_t internal_detour_is_code_filler(const uint8_t* code) return 0; } -static inline uint8_t* internal_detour_skip_jmp(uint8_t* code) +static inline uint8_t* detour_platform_skip_jmp(uint8_t* code) { // nothing special implemented return code; } -static inline uint8_t* internal_detour_operation_get_target_ptr(detour_operation* operation) +static inline uint8_t* detour_platform_operation_get_target_ptr(detour_operation* operation) { return operation->target; } -static inline uint8_t* internal_detour_operation_get_trampoline_ptr(detour_operation* operation) +static inline uint8_t* detour_platform_operation_get_trampoline_ptr(detour_operation* operation) { return operation->trampoline->code; } -static inline uint8_t* internal_detour_operation_commit_detour(detour_operation* operation) +static inline uint8_t* detour_platform_operation_commit_detour(detour_operation* operation) { - uint8_t* code = internal_detour_gen_jmp_indirect( + uint8_t* code = detour_arm64_gen_jmp_indirect( operation->target, (uint64_t*)&(operation->trampoline->ptr_detour)); - code = internal_detour_gen_brk(code, operation->trampoline->ptr_remain); + code = detour_platform_gen_brk(code, operation->trampoline->ptr_remain); return code; } -static inline void internal_detour_update_thread_on_commit(detour_pending_thread* thread, detour_operation* operations_head) +static inline void detour_platform_update_thread_on_commit(detour_pending_thread* thread, detour_operation* operations_head) { arm_thread_state64_t threadState; mach_msg_type_number_t threadStateCnt = ARM_THREAD_STATE64_COUNT; diff --git a/src/detours_internal.h b/src/detours_internal.h index ddec6f1..c402ecc 100644 --- a/src/detours_internal.h +++ b/src/detours_internal.h @@ -37,25 +37,6 @@ #define UNUSED_VARIABLE(x) (void)(x) #endif - -// Region reserved for system DLLs, which cannot be used for trampolines. -static void* s_system_region_lower_bound = (void*)(uintptr_t)0x70000000; -static void* s_system_region_upper_bound = (void*)(uintptr_t)0x80000000; - -static inline uintptr_t internal_detour_2gb_below(const uintptr_t address) -{ - return (address > 0x7ff80000) ? address - 0x7ff80000 : 0x80000; -} - -static inline uintptr_t internal_detour_2gb_above(uintptr_t address) -{ -#if defined(DETOURS_64BIT) - return (address < 0xffffffff80000000) ? address + 0x7ff80000 : 0xfffffffffff80000; -#else - return (address < 0x80000000) ? address + 0x7ff80000 : 0xfff80000; -#endif -} - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Structs @@ -89,10 +70,31 @@ typedef struct detour_align uint8_t offset_trampoline; } detour_align; +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Trampoline Memory Management Helpers + +// Region reserved for system DLLs, which cannot be used for trampolines. +static void* s_system_region_lower_bound = (void*)(uintptr_t)0x70000000; +static void* s_system_region_upper_bound = (void*)(uintptr_t)0x80000000; + +static inline uintptr_t internal_detour_2gb_below(const uintptr_t address) +{ + return (address > 0x7ff80000) ? address - 0x7ff80000 : 0x80000; +} + +static inline uintptr_t internal_detour_2gb_above(uintptr_t address) +{ +#if defined(DETOURS_64BIT) + return (address < 0xffffffff80000000) ? address + 0x7ff80000 : 0xfffffffffff80000; +#else + return (address < 0x80000000) ? address + 0x7ff80000 : 0xfff80000; +#endif +} + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Trampoline Helpers -static uint8_t internal_detour_align_from_trampoline(const detour_align align[], const size_t align_size, const uint8_t offset_trampoline) +static inline uint8_t internal_detour_align_from_trampoline(const detour_align align[], const size_t align_size, const uint8_t offset_trampoline) { for (size_t n = 0; n < align_size; n++) { if (align[n].offset_trampoline == offset_trampoline) { @@ -102,7 +104,7 @@ static uint8_t internal_detour_align_from_trampoline(const detour_align align[], return 0; } -static uint8_t internal_detour_align_from_target(const detour_align align[], const size_t align_size, const uint8_t offset_target) +static inline uint8_t internal_detour_align_from_target(const detour_align align[], const size_t align_size, const uint8_t offset_target) { for (size_t n = 0; n < align_size; n++) { if (align[n].offset_target == offset_target) { diff --git a/src/mach_detours.c b/src/mach_detours.c index 58e1602..95c40f9 100644 --- a/src/mach_detours.c +++ b/src/mach_detours.c @@ -187,7 +187,7 @@ static detour_trampoline* internal_detour_alloc_trampoline(uint8_t* target) detour_trampoline* lo; detour_trampoline* hi; - internal_detour_find_jmp_bounds(target, &lo, &hi); + detour_platform_find_jmp_bounds(target, &lo, &hi); // ReSharper disable once CppDFAUnusedValue detour_trampoline* trampoline = nullptr; @@ -421,8 +421,8 @@ mach_error_t detour_transaction_commit_ex(detour_func_t** out_failed_target) operation->target[4], operation->target[5], operation->target[6], operation->target[7], operation->target[8], operation->target[9], operation->target[10], operation->target[11])); - internal_detour_operation_commit_detour(operation); - *operation->pointer = internal_detour_operation_get_trampoline_ptr(operation) + detour_platform_operation_commit_detour(operation); + *operation->pointer = detour_platform_operation_get_trampoline_ptr(operation) DETOUR_TRACE(("detours: target=%p: " "%02x %02x %02x %02x " @@ -449,7 +449,7 @@ mach_error_t detour_transaction_commit_ex(detour_func_t** out_failed_target) case detour_operation_kind_detach: { memcpy(operation->target, operation->trampoline->restore_code, operation->trampoline->restore_code_size); - *operation->pointer = internal_detour_operation_get_target_ptr(operation); + *operation->pointer = detour_platform_operation_get_target_ptr(operation); break; } } @@ -457,7 +457,7 @@ mach_error_t detour_transaction_commit_ex(detour_func_t** out_failed_target) // Update any suspended threads. for (detour_pending_thread* thread = s_pending_threads_head; thread != nullptr; thread = thread->next) { - internal_detour_update_thread_on_commit(thread, s_pending_operations_head); + detour_platform_update_thread_on_commit(thread, s_pending_operations_head); } // Restore all the page permissions @@ -606,8 +606,8 @@ mach_error_t detour_attach_ex(detour_func_t* inout_pointer, detour_func_t detour detour_trampoline* trampoline = nullptr; detour_operation* op = nullptr; - uint8_t* target = internal_detour_skip_jmp(*inout_pointer); - detour = internal_detour_skip_jmp(detour); + uint8_t* target = detour_platform_skip_jmp(*inout_pointer); + detour = detour_platform_skip_jmp(detour); // Don't follow a jump if its destination is the target function. // This happens when the detour does nothing other than call the target. @@ -678,7 +678,7 @@ mach_error_t detour_attach_ex(detour_func_t* inout_pointer, detour_func_t detour uint32_t offset_target = 0; uint32_t align_idx = 0; - while (offset_target < DETOUR_SIZE_OF_JMP) { + while (offset_target < DETOUR_PLATFORM_SIZE_OF_JMP) { const uint8_t* curr_op = src; uint32_t extra_len = 0; @@ -695,14 +695,14 @@ mach_error_t detour_attach_ex(detour_func_t* inout_pointer, detour_func_t detour break; } - if (internal_detour_does_code_end_function(curr_op)) { + if (detour_platform_does_code_end_function(curr_op)) { break; } } // Consume, but don't duplicate padding if it is needed and available. - while (offset_target < DETOUR_SIZE_OF_JMP) { - const uint32_t len_filler = internal_detour_is_code_filler(src); + while (offset_target < DETOUR_PLATFORM_SIZE_OF_JMP) { + const uint32_t len_filler = detour_platform_is_code_filler(src); if (len_filler == 0) { break; } @@ -725,7 +725,7 @@ mach_error_t detour_attach_ex(detour_func_t* inout_pointer, detour_func_t detour } #endif - if (offset_target < DETOUR_SIZE_OF_JMP || align_idx > ARRAYSIZE(trampoline->align)) { + if (offset_target < DETOUR_PLATFORM_SIZE_OF_JMP || align_idx > ARRAYSIZE(trampoline->align)) { // Too few instructions. error = detour_err_too_small; if (s_ignore_too_small) { @@ -744,7 +744,7 @@ mach_error_t detour_attach_ex(detour_func_t* inout_pointer, detour_func_t detour trampoline->restore_code_size = (uint8_t)offset_target; memcpy(trampoline->restore_code, target, offset_target); - if (offset_target > sizeof(trampoline->code) - DETOUR_SIZE_OF_JMP) { + if (offset_target > sizeof(trampoline->code) - DETOUR_PLATFORM_SIZE_OF_JMP) { // Too many instructions. error = detour_err_too_large; DETOUR_BREAK(); @@ -757,8 +757,8 @@ mach_error_t detour_attach_ex(detour_func_t* inout_pointer, detour_func_t detour trampoline_code = trampoline->code + trampoline->code_size; trampoline_code = - internal_detour_gen_jmp_immediate(trampoline_code, &trampoline_code_limit, trampoline->ptr_remain); - trampoline_code = internal_detour_gen_brk(trampoline_code, trampoline_code_limit); + detour_platform_gen_jmp_immediate(trampoline_code, &trampoline_code_limit, trampoline->ptr_remain); + trampoline_code = detour_platform_gen_brk(trampoline_code, trampoline_code_limit); UNUSED_VARIABLE(trampoline_code); const mach_port_t port = mach_task_self(); @@ -856,8 +856,8 @@ mach_error_t detour_detach(detour_func_t* inout_pointer, detour_func_t detour) return error; } - detour_trampoline* trampoline = (detour_trampoline*)internal_detour_skip_jmp(*inout_pointer); - detour = internal_detour_skip_jmp(detour); + detour_trampoline* trampoline = (detour_trampoline*)detour_platform_skip_jmp(*inout_pointer); + detour = detour_platform_skip_jmp(detour); // Verify that Trampoline is in place. const int32_t restore_code_size = trampoline->restore_code_size;