added test

This commit is contained in:
Lysann Tranvouez 2025-09-30 00:09:10 +02:00
parent ade0920e54
commit aaad260259
4 changed files with 94 additions and 42 deletions

View file

@ -14,7 +14,15 @@ add_library(mach_detours SHARED
src/arm64/detours_arm64.h
src/arm64/detours_arm64_disasm.cpp
)
target_include_directories(mach_detours
PUBLIC "include"
PRIVATE "src")
PUBLIC include
PRIVATE src
)
add_executable(mach_detours_sample
sample/main.cpp
)
target_link_libraries(mach_detours_sample
PRIVATE mach_detours
)

View file

@ -5,6 +5,10 @@
#ifndef MACH_DETOURS_H
#define MACH_DETOURS_H
#ifdef __cplusplus
extern "C" {
#endif
#include <mach/error.h>
#include <mach/mach_types.h>
@ -31,4 +35,8 @@ 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

34
sample/main.cpp Normal file
View file

@ -0,0 +1,34 @@
// Copyright (c) Lysann Tranvouez. All rights reserved.
#include <cassert>
#include "mach_detours.h"
#include <cstring>
char* (*real_strerror)(int errno) = strerror;
static int counter = 0;
char* my_strerror(const int errno)
{
counter++;
return real_strerror(errno);
}
int main(int argc, const char* argv[])
{
counter = 0;
strerror(0);
assert(counter == 0);
detour_transaction_begin();
detour_attach(reinterpret_cast<detour_func_t*>(&real_strerror), reinterpret_cast<detour_func_t>(my_strerror));
detour_transaction_commit();
assert(counter == 0);
strerror(0);
assert(counter == 1);
return 0;
}

View file

@ -3,7 +3,7 @@
#include "mach_detours.h"
#define DETOUR_DEBUG 1
#define DETOUR_DEBUG 0
#ifdef __arm64__
#define DETOURS_ARM64
@ -200,12 +200,11 @@ static detour_trampoline* internal_detour_alloc_trampoline(uint8_t* target)
// First check the default region for a valid free block.
if (s_default_region && s_default_region->free_list_head &&
s_default_region->free_list_head >= lo && s_default_region->free_list_head <= hi) {
found_region:
trampoline = s_default_region->free_list_head;
// do a last sanity check on region.
if (trampoline < lo || trampoline > hi) {
raise(SIGTRAP);
DETOUR_BREAK();
return nullptr;
}
s_default_region->free_list_head = (detour_trampoline*)trampoline->ptr_remain;
@ -522,9 +521,8 @@ mach_error_t detour_transaction_commit_ex(detour_func_t** out_failed_target)
if (pc >= targetAddr && pc < targetAddr + op->trampoline->restore_code_size) {
uintptr_t new_pc = (uintptr_t)op->trampoline;
new_pc += internal_detour_align_from_target(op->trampoline, pc - targetAddr);
printf("detours: thread %u was at 0x%" PRIXPTR ", moved to 0x%" PRIXPTR "\n", thread->thread,
pc,
new_pc);
DETOUR_TRACE(("detours: thread %u was at 0x%" PRIXPTR ", moved to 0x%" PRIXPTR "\n",
thread->thread, pc, new_pc));
arm_thread_state64_set_pc_fptr(threadState, new_pc);
thread_set_state(thread->thread, ARM_THREAD_STATE64, (thread_state_t)&threadState,
ARM_THREAD_STATE64_COUNT);
@ -536,9 +534,8 @@ mach_error_t detour_transaction_commit_ex(detour_func_t** out_failed_target)
if (pc >= trampAddr && pc < trampAddr + sizeof(*op->trampoline)) {
uintptr_t new_pc = (uintptr_t)op->target;
new_pc += internal_detour_align_from_trampoline(op->trampoline, pc - trampAddr);
printf("detours: thread %u was at 0x%" PRIXPTR ", moved to 0x%" PRIXPTR "\n", thread->thread,
pc,
new_pc);
DETOUR_TRACE(("detours: thread %u was at 0x%" PRIXPTR ", moved to 0x%" PRIXPTR "\n",
thread->thread, pc, new_pc));
arm_thread_state64_set_pc_fptr(threadState, new_pc);
thread_set_state(thread->thread, ARM_THREAD_STATE64, (thread_state_t)&threadState,
ARM_THREAD_STATE64_COUNT);
@ -648,7 +645,8 @@ mach_error_t detour_attach(detour_func_t* inout_pointer, detour_func_t detour)
return detour_attach_ex(inout_pointer, detour, nullptr, nullptr, nullptr);
}
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_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)
{
if (out_real_trampoline) {
*out_real_trampoline = nullptr;
@ -844,7 +842,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_jmp_immediate(trampoline_code, &trampoline_code_limit, trampoline->ptr_remain);
trampoline_code = internal_detour_gen_brk(trampoline_code, trampoline_code_limit);
UNUSED_VARIABLE(trampoline_code);
@ -857,7 +856,8 @@ mach_error_t detour_attach_ex(detour_func_t* inout_pointer, detour_func_t detour
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);
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;
@ -976,7 +976,8 @@ mach_error_t detour_detach(detour_func_t* inout_pointer, detour_func_t detour)
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);
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;
@ -984,7 +985,8 @@ mach_error_t detour_detach(detour_func_t* inout_pointer, detour_func_t detour)
}
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);
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;