|
1 /******************************************************************************* |
|
2 mach_override.h |
|
3 Copyright (c) 2003-2009 Jonathan 'Wolf' Rentzsch: <http://rentzsch.com> |
|
4 Some rights reserved: <http://opensource.org/licenses/mit-license.php> |
|
5 |
|
6 ***************************************************************************/ |
|
7 |
|
8 /***************************************************************************//** |
|
9 @mainpage mach_override |
|
10 @author Jonathan 'Wolf' Rentzsch: <http://rentzsch.com> |
|
11 |
|
12 This package, coded in C to the Mach API, allows you to override ("patch") |
|
13 program- and system-supplied functions at runtime. You can fully replace |
|
14 functions with your implementations, or merely head- or tail-patch the |
|
15 original implementations. |
|
16 |
|
17 Use it by #include'ing mach_override.h from your .c, .m or .mm file(s). |
|
18 |
|
19 @todo Discontinue use of Carbon's MakeDataExecutable() and |
|
20 CompareAndSwap() calls and start using the Mach equivalents, if they |
|
21 exist. If they don't, write them and roll them in. That way, this |
|
22 code will be pure Mach, which will make it easier to use everywhere. |
|
23 Update: MakeDataExecutable() has been replaced by |
|
24 msync(MS_INVALIDATE). There is an OSCompareAndSwap in libkern, but |
|
25 I'm currently unsure if I can link against it. May have to roll in |
|
26 my own version... |
|
27 @todo Stop using an entire 4K high-allocated VM page per 28-byte escape |
|
28 branch island. Done right, this will dramatically speed up escape |
|
29 island allocations when they number over 250. Then again, if you're |
|
30 overriding more than 250 functions, maybe speed isn't your main |
|
31 concern... |
|
32 @todo Add detection of: b, bl, bla, bc, bcl, bcla, bcctrl, bclrl |
|
33 first-instructions. Initially, we should refuse to override |
|
34 functions beginning with these instructions. Eventually, we should |
|
35 dynamically rewrite them to make them position-independent. |
|
36 @todo Write mach_unoverride(), which would remove an override placed on a |
|
37 function. Must be multiple-override aware, which means an almost |
|
38 complete rewrite under the covers, because the target address can't |
|
39 be spread across two load instructions like it is now since it will |
|
40 need to be atomically updatable. |
|
41 @todo Add non-rentry variants of overrides to test_mach_override. |
|
42 |
|
43 ***************************************************************************/ |
|
44 |
|
45 #ifndef _mach_override_ |
|
46 #define _mach_override_ |
|
47 |
|
48 #include <sys/types.h> |
|
49 #include <mach/error.h> |
|
50 |
|
51 #ifdef __cplusplus |
|
52 extern "C" { |
|
53 #endif |
|
54 |
|
55 /** |
|
56 Returned if the function to be overrided begins with a 'mfctr' instruction. |
|
57 */ |
|
58 #define err_cannot_override (err_local|1) |
|
59 |
|
60 /************************************************************************************//** |
|
61 Dynamically overrides the function implementation referenced by |
|
62 originalFunctionAddress with the implentation pointed to by overrideFunctionAddress. |
|
63 Optionally returns a pointer to a "reentry island" which, if jumped to, will resume |
|
64 the original implementation. |
|
65 |
|
66 @param originalFunctionAddress -> Required address of the function to |
|
67 override (with overrideFunctionAddress). |
|
68 @param overrideFunctionAddress -> Required address to the overriding |
|
69 function. |
|
70 @param originalFunctionReentryIsland <- Optional pointer to pointer to the |
|
71 reentry island. Can be nullptr. |
|
72 @result <- err_cannot_override if the original |
|
73 function's implementation begins with |
|
74 the 'mfctr' instruction. |
|
75 |
|
76 ************************************************************************************/ |
|
77 |
|
78 mach_error_t |
|
79 mach_override_ptr( |
|
80 void *originalFunctionAddress, |
|
81 const void *overrideFunctionAddress, |
|
82 void **originalFunctionReentryIsland ); |
|
83 |
|
84 /************************************************************************************//** |
|
85 |
|
86 |
|
87 ************************************************************************************/ |
|
88 |
|
89 #ifdef __cplusplus |
|
90 |
|
91 #define MACH_OVERRIDE( ORIGINAL_FUNCTION_RETURN_TYPE, ORIGINAL_FUNCTION_NAME, ORIGINAL_FUNCTION_ARGS, ERR ) \ |
|
92 { \ |
|
93 static ORIGINAL_FUNCTION_RETURN_TYPE (*ORIGINAL_FUNCTION_NAME##_reenter)ORIGINAL_FUNCTION_ARGS; \ |
|
94 static bool ORIGINAL_FUNCTION_NAME##_overriden = false; \ |
|
95 class mach_override_class__##ORIGINAL_FUNCTION_NAME { \ |
|
96 public: \ |
|
97 static kern_return_t override(void *originalFunctionPtr) { \ |
|
98 kern_return_t result = err_none; \ |
|
99 if (!ORIGINAL_FUNCTION_NAME##_overriden) { \ |
|
100 ORIGINAL_FUNCTION_NAME##_overriden = true; \ |
|
101 result = mach_override_ptr( (void*)originalFunctionPtr, \ |
|
102 (void*)mach_override_class__##ORIGINAL_FUNCTION_NAME::replacement, \ |
|
103 (void**)&ORIGINAL_FUNCTION_NAME##_reenter ); \ |
|
104 } \ |
|
105 return result; \ |
|
106 } \ |
|
107 static ORIGINAL_FUNCTION_RETURN_TYPE replacement ORIGINAL_FUNCTION_ARGS { |
|
108 |
|
109 #define END_MACH_OVERRIDE( ORIGINAL_FUNCTION_NAME ) \ |
|
110 } \ |
|
111 }; \ |
|
112 \ |
|
113 err = mach_override_class__##ORIGINAL_FUNCTION_NAME::override((void*)ORIGINAL_FUNCTION_NAME); \ |
|
114 } |
|
115 |
|
116 #endif |
|
117 |
|
118 #ifdef __cplusplus |
|
119 } |
|
120 #endif |
|
121 #endif // _mach_override_ |