mach-detours/docs/using.md

65 lines
3.5 KiB
Markdown
Raw Normal View History

2025-10-03 23:59:07 +02:00
# Using mach-detours
Two things are necessary in order to detour a target function: a target pointer containing the address of the target function and a detour function. For proper interception the target function, detour function, and the target pointer must have exactly the same call signature.
The code fragment in Figure 5 illustrates the usage of the mach-detours library. User code must include the `mach_detours.h` header file and link with the `mach_detours` library.
------------------------------------------------------------------------
```cpp
#include <assert.h>
#include <string.h>
#include <mach_detours.h>
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((detour_func_t*)&real_strerror, (detour_func_t)my_strerror);
detour_transaction_commit();
assert(counter == 0);
strerror(0);
assert(counter == 1);
detour_transaction_begin();
detour_detach((detour_func_t*)&real_strerror, (detour_func_t)my_strerror);
detour_transaction_commit();
assert(counter == 1);
strerror(0);
assert(counter == 1);
return 0;
}
```
###### Figure 5. [Simple example](../sample/main.c) detour to modify the strerror API.
------------------------------------------------------------------------
Interception of the target function is enabled by invoking the `detour_attach` API within a detour transaction. A detour transaction is marked by calls to the `detour_transaction_begin` API and the `detour_transaction_commit` API. The `detour_attach` API takes two arguments: the address of the target pointer and the pointer to the detour function. The target function is not given as an argument because it must already be stored in the target pointer.
In a multi-threaded application, `detour_manage_thread` API enlists threads in the transaction so that they are suspended while the transaction is being set up and so that their instruction pointers are appropriately updated when the transaction commits.
The `detour_attach` API allocates and prepares a trampoline for calling the target function. When the detour transaction commits, the target function and trampoline are rewritten and the target pointer is updated to point to the trampoline function.
Once a target function has been detoured, any call to the target function will be re-routed through the detour function. It is the responsibility of the detour function to copy arguments when invoking the target function through the trampoline. This is intuitive as the target function becomes simply a subroutine callable by the detour function.
Interception of a target function is removed by calling the `detour_detach` API within a detour transaction. Like the `detour_attach` API, the `detour_detach` API takes two arguments: the address of the target pointer and the pointer to the detour function. When the detour transaction commits, the target function is rewritten and restored to its original code, the trampoline function is deleted, and the target pointer is restored to point to the original target function.
In cases where detour functions need to inserted into an existing application without source code access, the detour functions should be packaged in a dylib. The dylib can be inserted into a new process using `DYLD_INSERT_LIBRARIES` or the mach task port API.