move platform specific into arm file
This commit is contained in:
parent
ccaa4bfbf0
commit
db603acded
3 changed files with 193 additions and 156 deletions
|
|
@ -5,8 +5,12 @@
|
||||||
#ifndef MACH_DETOURS_ARM64_H
|
#ifndef MACH_DETOURS_ARM64_H
|
||||||
#define MACH_DETOURS_ARM64_H
|
#define MACH_DETOURS_ARM64_H
|
||||||
|
|
||||||
|
#include "detours_internal.h"
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <mach/mach.h>
|
||||||
|
|
||||||
typedef struct detour_trampoline
|
typedef struct detour_trampoline
|
||||||
{
|
{
|
||||||
// An ARM64 instruction is 4 bytes long.
|
// An ARM64 instruction is 4 bytes long.
|
||||||
|
|
@ -45,9 +49,10 @@ typedef struct detour_trampoline
|
||||||
uint8_t* ptr_detour; // first instruction of detour function.
|
uint8_t* ptr_detour; // first instruction of detour function.
|
||||||
} detour_trampoline;
|
} detour_trampoline;
|
||||||
|
|
||||||
static_assert(sizeof(detour_trampoline) == 192);
|
static_assert(sizeof(detour_trampoline)== 192);
|
||||||
|
|
||||||
enum {
|
enum
|
||||||
|
{
|
||||||
DETOUR_SIZE_OF_JMP = 12
|
DETOUR_SIZE_OF_JMP = 12
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -65,8 +70,10 @@ static inline void write_opcode(uint8_t** int_out_code, const detour_arm64_opcod
|
||||||
*int_out_code += sizeof(detour_arm64_opcode_t);
|
*int_out_code += sizeof(detour_arm64_opcode_t);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct detour_arm64_indirect_jmp {
|
struct detour_arm64_indirect_jmp
|
||||||
struct {
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
uint32_t Rd : 5;
|
uint32_t Rd : 5;
|
||||||
uint32_t immhi : 19;
|
uint32_t immhi : 19;
|
||||||
uint32_t iop : 5;
|
uint32_t iop : 5;
|
||||||
|
|
@ -74,7 +81,8 @@ struct detour_arm64_indirect_jmp {
|
||||||
uint32_t op : 1;
|
uint32_t op : 1;
|
||||||
} ardp;
|
} ardp;
|
||||||
|
|
||||||
struct {
|
struct
|
||||||
|
{
|
||||||
uint32_t Rt : 5;
|
uint32_t Rt : 5;
|
||||||
uint32_t Rn : 5;
|
uint32_t Rn : 5;
|
||||||
uint32_t imm : 12;
|
uint32_t imm : 12;
|
||||||
|
|
@ -88,8 +96,10 @@ struct detour_arm64_indirect_jmp {
|
||||||
uint32_t br;
|
uint32_t br;
|
||||||
};
|
};
|
||||||
|
|
||||||
union detour_arm64_indirect_imm {
|
union detour_arm64_indirect_imm
|
||||||
struct {
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
uint64_t pad : 12;
|
uint64_t pad : 12;
|
||||||
uint64_t adrp_immlo : 2;
|
uint64_t adrp_immlo : 2;
|
||||||
uint64_t adrp_immhi : 19;
|
uint64_t adrp_immhi : 19;
|
||||||
|
|
@ -107,7 +117,7 @@ static inline uint8_t* internal_detour_gen_jmp_indirect(uint8_t* code, const uin
|
||||||
union detour_arm64_indirect_imm jmp_ind_addr;
|
union detour_arm64_indirect_imm jmp_ind_addr;
|
||||||
|
|
||||||
jmp_ind_addr.value = (((uint64_t)jump_val) & 0xFFFFFFFFFFFFF000) -
|
jmp_ind_addr.value = (((uint64_t)jump_val) & 0xFFFFFFFFFFFFF000) -
|
||||||
(((uint64_t)code) & 0xFFFFFFFFFFFFF000);
|
(((uint64_t)code) & 0xFFFFFFFFFFFFF000);
|
||||||
|
|
||||||
struct detour_arm64_indirect_jmp* ind_jmp = (struct detour_arm64_indirect_jmp*)code;
|
struct detour_arm64_indirect_jmp* ind_jmp = (struct detour_arm64_indirect_jmp*)code;
|
||||||
code = (uint8_t*)(ind_jmp + 1);
|
code = (uint8_t*)(ind_jmp + 1);
|
||||||
|
|
@ -140,8 +150,8 @@ static inline uint8_t* internal_detour_gen_jmp_immediate(uint8_t* code, uint8_t*
|
||||||
*(uint8_t**)literal = jmp_val;
|
*(uint8_t**)literal = jmp_val;
|
||||||
const int32_t delta = (int32_t)(literal - code);
|
const int32_t delta = (int32_t)(literal - code);
|
||||||
|
|
||||||
write_opcode(&code, 0x58000011 | ((delta / 4) << 5)); // LDR X17,[PC+n]
|
write_opcode(&code, 0x58000011 | ((delta / 4) << 5)); // LDR X17,[PC+n]
|
||||||
write_opcode(&code, 0xd61f0000 | (17 << 5)); // BR X17
|
write_opcode(&code, 0xd61f0000 | (17 << 5)); // BR X17
|
||||||
|
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
@ -154,7 +164,8 @@ static inline uint8_t* internal_detour_gen_brk(uint8_t* code, const uint8_t* lim
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void internal_detour_find_jmp_bounds(uint8_t* code, detour_trampoline** out_lower, detour_trampoline** out_upper)
|
static inline void internal_detour_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
|
// The encoding used by detour_gen_jmp_indirect actually enables a
|
||||||
// displacement of +/- 4GiB. In the future, this could be changed to
|
// displacement of +/- 4GiB. In the future, this could be changed to
|
||||||
|
|
@ -190,10 +201,10 @@ static inline bool internal_detour_is_code_os_patched(const uint8_t* code)
|
||||||
const uint32_t hpat_opcode1 = fetch_opcode(branch_target);
|
const uint32_t hpat_opcode1 = fetch_opcode(branch_target);
|
||||||
const uint32_t hpat_opcode2 = fetch_opcode(branch_target + 4);
|
const uint32_t hpat_opcode2 = fetch_opcode(branch_target + 4);
|
||||||
|
|
||||||
if (hpat_opcode1 != 0x58008010) { // ldr <reg> [PC+PAGE_SIZE]
|
if (hpat_opcode1 != 0x58008010) { // ldr <reg> [PC+PAGE_SIZE]
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (hpat_opcode2 != 0xd61f0200) { // br <reg>
|
if (hpat_opcode2 != 0xd61f0200) { // br <reg>
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -207,19 +218,19 @@ static inline bool internal_detour_does_code_end_function(const uint8_t* code)
|
||||||
if (internal_detour_is_code_os_patched(code)) {
|
if (internal_detour_is_code_os_patched(code)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if ((opcode & 0xffbffc1f) == 0xd61f0000 || // ret/br <reg>
|
if ((opcode & 0xffbffc1f) == 0xd61f0000 || // ret/br <reg>
|
||||||
(opcode & 0xfc000000) == 0x14000000) { // b <imm26>
|
(opcode & 0xfc000000) == 0x14000000) { // b <imm26>
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint32_t internal_detour_is_code_filler(const uint8_t* code)
|
static inline uint32_t internal_detour_is_code_filler(const uint8_t* code)
|
||||||
{
|
{
|
||||||
if (*(uint32_t *)code == 0xd503201f) { // nop.
|
if (*(uint32_t*)code == 0xd503201f) { // nop.
|
||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
if (*(uint32_t *)code == 0x00000000) { // zero-filled padding.
|
if (*(uint32_t*)code == 0x00000000) { // zero-filled padding.
|
||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -231,4 +242,66 @@ static inline uint8_t* internal_detour_skip_jmp(uint8_t* code)
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif //MACH_DETOURS_ARM64_H
|
static inline uint8_t* internal_detour_operation_get_target_ptr(detour_operation* operation)
|
||||||
|
{
|
||||||
|
return operation->target;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint8_t* internal_detour_operation_get_trampoline_ptr(detour_operation* operation)
|
||||||
|
{
|
||||||
|
return operation->trampoline->code;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint8_t* internal_detour_operation_commit_detour(detour_operation* operation)
|
||||||
|
{
|
||||||
|
uint8_t* code = internal_detour_gen_jmp_indirect(
|
||||||
|
operation->target, (uint64_t*)&(operation->trampoline->ptr_detour));
|
||||||
|
code = internal_detour_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)
|
||||||
|
{
|
||||||
|
arm_thread_state64_t threadState;
|
||||||
|
mach_msg_type_number_t threadStateCnt = ARM_THREAD_STATE64_COUNT;
|
||||||
|
const kern_return_t error = thread_get_state(thread->thread, ARM_THREAD_STATE64, (thread_state_t)&threadState,
|
||||||
|
&threadStateCnt);
|
||||||
|
if (error != err_none) {
|
||||||
|
DETOUR_BREAK();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const uintptr_t pc = arm_thread_state64_get_pc(threadState);
|
||||||
|
|
||||||
|
for (detour_operation* op = operations_head; op != nullptr; op = op->next) {
|
||||||
|
switch (op->kind) {
|
||||||
|
case detour_operation_kind_attach: {
|
||||||
|
const uintptr_t targetAddr = (uintptr_t)op->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->align, ARRAYSIZE(op->trampoline->align), pc - targetAddr);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case detour_operation_kind_detach: {
|
||||||
|
const uintptr_t trampAddr = (uintptr_t)op->trampoline;
|
||||||
|
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->align, ARRAYSIZE(op->trampoline->align), pc - trampAddr);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //MACH_DETOURS_ARM64_H
|
||||||
|
|
|
||||||
|
|
@ -38,12 +38,6 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
typedef struct detour_align
|
|
||||||
{
|
|
||||||
uint8_t offset_target;
|
|
||||||
uint8_t offset_trampoline;
|
|
||||||
} detour_align;
|
|
||||||
|
|
||||||
// Region reserved for system DLLs, which cannot be used for trampolines.
|
// 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_lower_bound = (void*)(uintptr_t)0x70000000;
|
||||||
static void* s_system_region_upper_bound = (void*)(uintptr_t)0x80000000;
|
static void* s_system_region_upper_bound = (void*)(uintptr_t)0x80000000;
|
||||||
|
|
@ -62,4 +56,60 @@ static inline uintptr_t internal_detour_2gb_above(uintptr_t address)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Structs
|
||||||
|
|
||||||
|
typedef struct detour_trampoline detour_trampoline;
|
||||||
|
|
||||||
|
typedef enum detour_operation_kind
|
||||||
|
{
|
||||||
|
detour_operation_kind_attach,
|
||||||
|
detour_operation_kind_detach,
|
||||||
|
} detour_operation_kind;
|
||||||
|
|
||||||
|
typedef struct detour_operation
|
||||||
|
{
|
||||||
|
struct detour_operation* next;
|
||||||
|
detour_operation_kind kind;
|
||||||
|
uint8_t** pointer;
|
||||||
|
uint8_t* target;
|
||||||
|
detour_trampoline* trampoline;
|
||||||
|
vm_prot_t perm;
|
||||||
|
} detour_operation;
|
||||||
|
|
||||||
|
typedef struct detour_pending_thread
|
||||||
|
{
|
||||||
|
struct detour_pending_thread* next;
|
||||||
|
thread_t thread;
|
||||||
|
} detour_pending_thread;
|
||||||
|
|
||||||
|
typedef struct detour_align
|
||||||
|
{
|
||||||
|
uint8_t offset_target;
|
||||||
|
uint8_t offset_trampoline;
|
||||||
|
} detour_align;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Trampoline Helpers
|
||||||
|
|
||||||
|
static 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) {
|
||||||
|
return align[n].offset_target;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static 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) {
|
||||||
|
return align[n].offset_trampoline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
#endif //MACH_DETOURS_INTERNAL_H
|
#endif //MACH_DETOURS_INTERNAL_H
|
||||||
|
|
@ -305,55 +305,9 @@ static void internal_detour_free_unused_trampoline_regions()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Trampoline Helpers
|
|
||||||
|
|
||||||
static uint8_t internal_detour_align_from_trampoline(const detour_trampoline* trampoline,
|
|
||||||
const uint8_t offset_trampoline)
|
|
||||||
{
|
|
||||||
for (int32_t n = 0; n < ARRAYSIZE(trampoline->align); n++) {
|
|
||||||
if (trampoline->align[n].offset_trampoline == offset_trampoline) {
|
|
||||||
return trampoline->align[n].offset_target;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint8_t internal_detour_align_from_target(const detour_trampoline* trampoline, const uint8_t offset_target)
|
|
||||||
{
|
|
||||||
for (int32_t n = 0; n < ARRAYSIZE(trampoline->align); n++) {
|
|
||||||
if (trampoline->align[n].offset_target == offset_target) {
|
|
||||||
return trampoline->align[n].offset_trampoline;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Transactions
|
// Transactions
|
||||||
|
|
||||||
typedef enum detour_operation_kind
|
|
||||||
{
|
|
||||||
detour_operation_kind_attach,
|
|
||||||
detour_operation_kind_detach,
|
|
||||||
} detour_operation_kind;
|
|
||||||
|
|
||||||
typedef struct detour_operation
|
|
||||||
{
|
|
||||||
struct detour_operation* next;
|
|
||||||
detour_operation_kind kind;
|
|
||||||
uint8_t** pointer;
|
|
||||||
uint8_t* target;
|
|
||||||
detour_trampoline* trampoline;
|
|
||||||
vm_prot_t perm;
|
|
||||||
} detour_operation;
|
|
||||||
|
|
||||||
typedef struct detour_pending_thread
|
|
||||||
{
|
|
||||||
struct detour_pending_thread* next;
|
|
||||||
thread_t thread;
|
|
||||||
} detour_pending_thread;
|
|
||||||
|
|
||||||
static bool s_ignore_too_small = false;
|
static bool s_ignore_too_small = false;
|
||||||
static bool s_retain_regions = false;
|
static bool s_retain_regions = false;
|
||||||
|
|
||||||
|
|
@ -450,100 +404,60 @@ mach_error_t detour_transaction_commit_ex(detour_func_t** out_failed_target)
|
||||||
|
|
||||||
// Insert or remove each of the detours.
|
// Insert or remove each of the detours.
|
||||||
for (detour_operation* operation = s_pending_operations_head; operation != nullptr; operation = operation->next) {
|
for (detour_operation* operation = s_pending_operations_head; operation != nullptr; operation = operation->next) {
|
||||||
if (operation->kind == detour_operation_kind_detach) {
|
switch (operation->kind) {
|
||||||
memcpy(operation->target, operation->trampoline->restore_code, operation->trampoline->restore_code_size);
|
case detour_operation_kind_attach: {
|
||||||
#ifdef DETOURS_ARM64
|
DETOUR_TRACE(("detours: trampoline=%p, ptr_remain=%p, ptr_detour=%p, restore_code_size=%u\n",
|
||||||
*operation->pointer = operation->target;
|
operation->trampoline,
|
||||||
#endif
|
operation->trampoline->ptr_remain,
|
||||||
} else {
|
operation->trampoline->ptr_detour,
|
||||||
DETOUR_TRACE(("detours: trampoline=%p, ptr_remain=%p, ptr_detour=%p, restore_code_size=%u\n",
|
operation->trampoline->restore_code_size));
|
||||||
operation->trampoline,
|
|
||||||
operation->trampoline->ptr_remain,
|
|
||||||
operation->trampoline->ptr_detour,
|
|
||||||
operation->trampoline->restore_code_size));
|
|
||||||
|
|
||||||
DETOUR_TRACE(("detours: target=%p: "
|
DETOUR_TRACE(("detours: target=%p: "
|
||||||
"%02x %02x %02x %02x "
|
"%02x %02x %02x %02x "
|
||||||
"%02x %02x %02x %02x "
|
"%02x %02x %02x %02x "
|
||||||
"%02x %02x %02x %02x [before]\n",
|
"%02x %02x %02x %02x [before]\n",
|
||||||
operation->target,
|
operation->target,
|
||||||
operation->target[0], operation->target[1], operation->target[2], operation->target[3],
|
operation->target[0], operation->target[1], operation->target[2], operation->target[3],
|
||||||
operation->target[4], operation->target[5], operation->target[6], operation->target[7],
|
operation->target[4], operation->target[5], operation->target[6], operation->target[7],
|
||||||
operation->target[8], operation->target[9], operation->target[10], operation->target[11]));
|
operation->target[8], operation->target[9], operation->target[10], operation->target[11]));
|
||||||
|
|
||||||
#ifdef DETOURS_ARM64
|
internal_detour_operation_commit_detour(operation);
|
||||||
uint8_t* code = internal_detour_gen_jmp_indirect(operation->target,
|
*operation->pointer = internal_detour_operation_get_trampoline_ptr(operation)
|
||||||
(uint64_t*)&(operation->trampoline->ptr_detour));
|
|
||||||
code = internal_detour_gen_brk(code, operation->trampoline->ptr_remain);
|
|
||||||
UNUSED_VARIABLE(code);
|
|
||||||
*operation->pointer = operation->trampoline->code;
|
|
||||||
#endif // DETOURS_ARM64
|
|
||||||
|
|
||||||
DETOUR_TRACE(("detours: target=%p: "
|
DETOUR_TRACE(("detours: target=%p: "
|
||||||
"%02x %02x %02x %02x "
|
"%02x %02x %02x %02x "
|
||||||
"%02x %02x %02x %02x "
|
"%02x %02x %02x %02x "
|
||||||
"%02x %02x %02x %02x [after]\n",
|
"%02x %02x %02x %02x [after]\n",
|
||||||
operation->target,
|
operation->target,
|
||||||
operation->target[0], operation->target[1], operation->target[2], operation->target[3],
|
operation->target[0], operation->target[1], operation->target[2], operation->target[3],
|
||||||
operation->target[4], operation->target[5], operation->target[6], operation->target[7],
|
operation->target[4], operation->target[5], operation->target[6], operation->target[7],
|
||||||
operation->target[8], operation->target[9], operation->target[10], operation->target[11]));
|
operation->target[8], operation->target[9], operation->target[10], operation->target[11]));
|
||||||
|
|
||||||
DETOUR_TRACE(("detours: trampoline=%p: "
|
DETOUR_TRACE(("detours: trampoline=%p: "
|
||||||
"%02x %02x %02x %02x "
|
"%02x %02x %02x %02x "
|
||||||
"%02x %02x %02x %02x "
|
"%02x %02x %02x %02x "
|
||||||
"%02x %02x %02x %02x\n",
|
"%02x %02x %02x %02x\n",
|
||||||
operation->trampoline,
|
operation->trampoline,
|
||||||
operation->trampoline->code[0], operation->trampoline->code[1],
|
operation->trampoline->code[0], operation->trampoline->code[1],
|
||||||
operation->trampoline->code[2], operation->trampoline->code[3],
|
operation->trampoline->code[2], operation->trampoline->code[3],
|
||||||
operation->trampoline->code[4], operation->trampoline->code[5],
|
operation->trampoline->code[4], operation->trampoline->code[5],
|
||||||
operation->trampoline->code[6], operation->trampoline->code[7],
|
operation->trampoline->code[6], operation->trampoline->code[7],
|
||||||
operation->trampoline->code[8], operation->trampoline->code[9],
|
operation->trampoline->code[8], operation->trampoline->code[9],
|
||||||
operation->trampoline->code[10], operation->trampoline->code[11]));
|
operation->trampoline->code[10], operation->trampoline->code[11]));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update any suspended threads.
|
// Update any suspended threads.
|
||||||
for (detour_pending_thread* thread = s_pending_threads_head; thread != nullptr; thread = thread->next) {
|
for (detour_pending_thread* thread = s_pending_threads_head; thread != nullptr; thread = thread->next) {
|
||||||
arm_thread_state64_t threadState;
|
internal_detour_update_thread_on_commit(thread, s_pending_operations_head);
|
||||||
mach_msg_type_number_t threadStateCnt = ARM_THREAD_STATE64_COUNT;
|
|
||||||
const kern_return_t error = thread_get_state(thread->thread, ARM_THREAD_STATE64, (thread_state_t)&threadState,
|
|
||||||
&threadStateCnt);
|
|
||||||
if (error != err_none) {
|
|
||||||
DETOUR_BREAK();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const uintptr_t pc = arm_thread_state64_get_pc(threadState);
|
|
||||||
|
|
||||||
for (detour_operation* op = s_pending_operations_head; op != nullptr; op = op->next) {
|
|
||||||
switch (op->kind) {
|
|
||||||
case detour_operation_kind_attach: {
|
|
||||||
const uintptr_t targetAddr = (uintptr_t)op->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);
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case detour_operation_kind_detach: {
|
|
||||||
const uintptr_t trampAddr = (uintptr_t)op->trampoline;
|
|
||||||
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);
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Restore all the page permissions
|
// Restore all the page permissions
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue