implement detour_transaction_begin
This commit is contained in:
parent
c0975230fe
commit
d80ec89490
8 changed files with 231 additions and 6 deletions
18
.idea/codeStyles/Project.xml
generated
Normal file
18
.idea/codeStyles/Project.xml
generated
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
<component name="ProjectCodeStyleConfiguration">
|
||||||
|
<code_scheme name="Project" version="173">
|
||||||
|
<option name="AUTODETECT_INDENTS" value="false" />
|
||||||
|
<RiderCodeStyleSettings>
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppClangFormat/EnableClangFormatSupport/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/EditorConfig/EnableClangFormatSupport/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ANONYMOUS_METHOD_DECLARATION_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/CASE_BLOCK_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/OTHER_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/EXPRESSION_BRACES/@EntryValue" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/EMPTY_BLOCK_STYLE/@EntryValue" value="TOGETHER_SAME_LINE" type="string" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALLOW_COMMENT_AFTER_LBRACE/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/PLACE_ELSE_ON_NEW_LINE/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/PLACE_WHILE_ON_NEW_LINE/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/PLACE_CATCH_ON_NEW_LINE/@EntryValue" value="false" type="bool" />
|
||||||
|
</RiderCodeStyleSettings>
|
||||||
|
</code_scheme>
|
||||||
|
</component>
|
||||||
5
.idea/codeStyles/codeStyleConfig.xml
generated
Normal file
5
.idea/codeStyles/codeStyleConfig.xml
generated
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
<component name="ProjectCodeStyleConfiguration">
|
||||||
|
<state>
|
||||||
|
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
|
||||||
|
</state>
|
||||||
|
</component>
|
||||||
10
.idea/editor.xml
generated
10
.idea/editor.xml
generated
|
|
@ -244,5 +244,15 @@
|
||||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=IfStdIsConstantEvaluatedCanBeReplaced/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=IfStdIsConstantEvaluatedCanBeReplaced/@EntryIndexedValue" value="SUGGESTION" type="string" />
|
||||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=StdIsConstantEvaluatedWillAlwaysEvaluateToConstant/@EntryIndexedValue" value="WARNING" type="string" />
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=StdIsConstantEvaluatedWillAlwaysEvaluateToConstant/@EntryIndexedValue" value="WARNING" type="string" />
|
||||||
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=StringLiteralTypo/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
<option name="/Default/CodeInspection/Highlighting/InspectionSeverities/=StringLiteralTypo/@EntryIndexedValue" value="DO_NOT_SHOW" type="string" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppClangFormat/EnableClangFormatSupport/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALLOW_COMMENT_AFTER_LBRACE/@EntryValue" value="true" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ANONYMOUS_METHOD_DECLARATION_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/CASE_BLOCK_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/EMPTY_BLOCK_STYLE/@EntryValue" value="TOGETHER_SAME_LINE" type="string" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/OTHER_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/PLACE_CATCH_ON_NEW_LINE/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/PLACE_ELSE_ON_NEW_LINE/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/PLACE_WHILE_ON_NEW_LINE/@EntryValue" value="false" type="bool" />
|
||||||
|
<option name="/Default/CodeStyle/EditorConfig/EnableClangFormatSupport/@EntryValue" value="false" type="bool" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
|
|
@ -6,4 +6,6 @@ set(CMAKE_C_STANDARD 23)
|
||||||
add_library(mach_detours SHARED
|
add_library(mach_detours SHARED
|
||||||
mach_detours.c
|
mach_detours.c
|
||||||
mach_detours.h
|
mach_detours.h
|
||||||
|
arm64/detours_arm64.h
|
||||||
|
detours_internal.h
|
||||||
)
|
)
|
||||||
|
|
|
||||||
53
arm64/detours_arm64.h
Normal file
53
arm64/detours_arm64.h
Normal file
|
|
@ -0,0 +1,53 @@
|
||||||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
// Copyright (c) Lysann Tranvouez. All rights reserved.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#ifndef MACH_DETOURS_ARM64_H
|
||||||
|
#define MACH_DETOURS_ARM64_H
|
||||||
|
|
||||||
|
typedef struct detour_align
|
||||||
|
{
|
||||||
|
uint8_t obTarget;
|
||||||
|
uint8_t obTrampoline;
|
||||||
|
} detour_align;
|
||||||
|
|
||||||
|
typedef struct detour_trampoline
|
||||||
|
{
|
||||||
|
// An ARM64 instruction is 4 bytes long.
|
||||||
|
//
|
||||||
|
// The overwrite is always composed of 3 instructions (12 bytes) which perform an indirect jump
|
||||||
|
// using _DETOUR_TRAMPOLINE::pbDetour as the address holding the target location.
|
||||||
|
//
|
||||||
|
// Copied instructions can expand.
|
||||||
|
//
|
||||||
|
// The scheme using MovImmediate can cause an instruction
|
||||||
|
// to grow as much as 6 times.
|
||||||
|
// That would be Bcc or Tbz with a large address space:
|
||||||
|
// 4 instructions to form immediate
|
||||||
|
// inverted tbz/bcc
|
||||||
|
// br
|
||||||
|
//
|
||||||
|
// An expansion of 4 is not uncommon -- bl/blr and small address space:
|
||||||
|
// 3 instructions to form immediate
|
||||||
|
// br or brl
|
||||||
|
//
|
||||||
|
// A theoretical maximum for rbCode is thefore 4*4*6 + 16 = 112 (another 16 for jmp to pbRemain).
|
||||||
|
//
|
||||||
|
// With literals, the maximum expansion is 5, including the literals: 4*4*5 + 16 = 96.
|
||||||
|
//
|
||||||
|
// The number is rounded up to 128. m_rbScratchDst should match this.
|
||||||
|
//
|
||||||
|
uint8_t rbCode[128]; // target code + jmp to pbRemain
|
||||||
|
uint8_t cbCode; // size of moved target code.
|
||||||
|
uint8_t cbCodeBreak[3]; // padding to make debugging easier.
|
||||||
|
uint8_t rbRestore[24]; // original target code.
|
||||||
|
uint8_t cbRestore; // size of original target code.
|
||||||
|
uint8_t cbRestoreBreak[3]; // padding to make debugging easier.
|
||||||
|
detour_align rAlign[8]; // instruction alignment array.
|
||||||
|
uint8_t* pbRemain; // first instruction after moved code. [free list]
|
||||||
|
uint8_t* pbDetour; // first instruction of detour function.
|
||||||
|
} detour_trampoline;
|
||||||
|
|
||||||
|
static_assert(sizeof(detour_trampoline) == 192);
|
||||||
|
|
||||||
|
#endif //MACH_DETOURS_ARM64_H
|
||||||
18
detours_internal.h
Normal file
18
detours_internal.h
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
// Copyright (c) Lysann Tranvouez. All rights reserved.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#ifndef MACH_DETOURS_INTERNAL_H
|
||||||
|
#define MACH_DETOURS_INTERNAL_H
|
||||||
|
|
||||||
|
#ifndef DETOUR_TRACE
|
||||||
|
#if DETOUR_DEBUG
|
||||||
|
#define DETOUR_TRACE(x) printf x
|
||||||
|
#define DETOUR_BREAK() raise(SIGTRAP)
|
||||||
|
#else
|
||||||
|
#define DETOUR_TRACE(x)
|
||||||
|
#define DETOUR_BREAK()
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif //MACH_DETOURS_INTERNAL_H
|
||||||
104
mach_detours.c
104
mach_detours.c
|
|
@ -1,8 +1,104 @@
|
||||||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
// Copyright (c) Lysann Tranvouez. All rights reserved.
|
||||||
|
|
||||||
#include "mach_detours.h"
|
#include "mach_detours.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include "detours_internal.h"
|
||||||
|
#include "arm64/detours_arm64.h"
|
||||||
|
|
||||||
void hello(void)
|
#include <stdatomic.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <mach/mach_init.h>
|
||||||
|
#include <mach/mach_vm.h>
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Trampoline Memory Management
|
||||||
|
|
||||||
|
typedef struct detour_region
|
||||||
{
|
{
|
||||||
printf("Hello, World!\n");
|
uint32_t signature;
|
||||||
}
|
struct detour_region* next; // Next region in list of regions.
|
||||||
|
detour_trampoline* free_list_head; // List of free trampolines in this region.
|
||||||
|
} detour_region;
|
||||||
|
|
||||||
|
static const uint32_t DETOUR_REGION_SIGNATURE = 'Rrtd';
|
||||||
|
static const uint32_t DETOUR_REGION_SIZE = 0x10000;
|
||||||
|
static const uint32_t DETOUR_TRAMPOLINES_PER_REGION = (DETOUR_REGION_SIZE / sizeof(detour_trampoline)) - 1;
|
||||||
|
static detour_region* s_regions_head = nullptr;
|
||||||
|
static detour_region* s_default_region = nullptr;
|
||||||
|
|
||||||
|
static mach_error_t internal_detour_writable_trampoline_regions()
|
||||||
|
{
|
||||||
|
// Mark all the regions as writable.
|
||||||
|
const mach_port_t port = mach_task_self();
|
||||||
|
for (detour_region* pRegion = s_regions_head; pRegion != NULL; pRegion = pRegion->next) {
|
||||||
|
const mach_error_t error = mach_vm_protect(port, (mach_vm_address_t)pRegion, DETOUR_REGION_SIZE, false, VM_PROT_READ | VM_PROT_WRITE);
|
||||||
|
if (error != err_none) {
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err_none;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void internal_detour_runnable_trampoline_regions()
|
||||||
|
{
|
||||||
|
// Mark all the regions as executable.
|
||||||
|
const mach_port_t port = mach_task_self();
|
||||||
|
for (detour_region* pRegion = s_regions_head; pRegion != NULL; pRegion = pRegion->next) {
|
||||||
|
const mach_error_t error = mach_vm_protect(port, (mach_vm_address_t)pRegion, DETOUR_REGION_SIZE, false, VM_PROT_READ | VM_PROT_EXECUTE);
|
||||||
|
if (error != err_none) {
|
||||||
|
DETOUR_BREAK();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Transactions
|
||||||
|
|
||||||
|
typedef enum detour_operation_kind {
|
||||||
|
attach,
|
||||||
|
detach,
|
||||||
|
} detour_operation_kind;
|
||||||
|
|
||||||
|
typedef struct detour_operation
|
||||||
|
{
|
||||||
|
struct detour_operation* next;
|
||||||
|
detour_operation_kind kind;
|
||||||
|
uint8_t** pointer;
|
||||||
|
uint8_t* target;
|
||||||
|
struct 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 _Atomic(thread_t) s_transaction_thread = THREAD_NULL;
|
||||||
|
static detour_operation* s_pending_operations_head = nullptr;
|
||||||
|
static detour_pending_thread* s_pending_threads_head = nullptr;
|
||||||
|
|
||||||
|
static mach_error_t s_pending_error = err_none;
|
||||||
|
static void** s_pending_error_pointer = nullptr;
|
||||||
|
|
||||||
|
mach_error_t detour_transaction_begin()
|
||||||
|
{
|
||||||
|
// Make sure only one thread can start a transaction.
|
||||||
|
thread_t expected = THREAD_NULL;
|
||||||
|
// ReSharper disable once CppIncompatiblePointerConversion
|
||||||
|
if (!atomic_compare_exchange_strong(&s_transaction_thread, &expected, mach_thread_self())) {
|
||||||
|
return detour_err_in_progress;
|
||||||
|
}
|
||||||
|
|
||||||
|
s_pending_operations_head = nullptr;
|
||||||
|
s_pending_threads_head = nullptr;
|
||||||
|
s_pending_error_pointer = nullptr;
|
||||||
|
|
||||||
|
// Make sure the trampoline pages are writable.
|
||||||
|
s_pending_error = internal_detour_writable_trampoline_regions();
|
||||||
|
|
||||||
|
return s_pending_error;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,26 @@
|
||||||
#pragma once
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
// Copyright (c) Lysann Tranvouez. All rights reserved.
|
||||||
|
|
||||||
void hello();
|
#pragma once
|
||||||
|
#ifndef MACH_DETOURS_H
|
||||||
|
#define MACH_DETOURS_H
|
||||||
|
|
||||||
|
#include <mach/error.h>
|
||||||
|
#include <mach/mach_types.h>
|
||||||
|
|
||||||
|
typedef void* detour_func_t;
|
||||||
|
|
||||||
|
#define detour_err_in_progress (err_local | 1)
|
||||||
|
|
||||||
|
mach_error_t detour_transaction_begin();
|
||||||
|
mach_error_t detour_transaction_abort();
|
||||||
|
mach_error_t detour_transaction_commit();
|
||||||
|
mach_error_t detour_transaction_commit_ex(detour_func_t** out_failed_target);
|
||||||
|
|
||||||
|
mach_error_t detour_manage_thread(thread_t thread);
|
||||||
|
|
||||||
|
mach_error_t detour_attach(detour_func_t* inout_pointer, detour_func_t 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);
|
||||||
|
mach_error_t detour_detach(detour_func_t* inout_pointer, detour_func_t detour);
|
||||||
|
|
||||||
|
#endif // MACH_DETOURS_H
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue