OLD | NEW |
1 /******************************************************************************* | 1 /******************************************************************************* |
2 mach_override.c | 2 mach_override.c |
3 Copyright (c) 2003-2009 Jonathan 'Wolf' Rentzsch: <http://rentzs
ch.com> | 3 Copyright (c) 2003-2009 Jonathan 'Wolf' Rentzsch: <http://rentzs
ch.com> |
4 Some rights reserved: <http://opensource.org/licenses/mit-licens
e.php> | 4 Some rights reserved: <http://opensource.org/licenses/mit-licens
e.php> |
5 | 5 |
6 ************************************************************************
***/ | 6 ************************************************************************
***/ |
7 | 7 |
8 #include "mach_override.h" | 8 #include "mach_override.h" |
9 | 9 |
10 #include <mach-o/dyld.h> | 10 #include <mach-o/dyld.h> |
11 #include <mach/mach_host.h> | 11 #include <mach/mach_host.h> |
12 #include <mach/mach_init.h> | 12 #include <mach/mach_init.h> |
13 #include <mach/vm_map.h> | 13 #include <mach/vm_map.h> |
14 #include <sys/mman.h> | 14 #include <sys/mman.h> |
15 | 15 |
16 #include <CoreServices/CoreServices.h> | 16 #include <CoreServices/CoreServices.h> |
17 | 17 |
18 /************************** | 18 /************************** |
19 * | 19 * |
20 * Constants | 20 * Constants |
21 * | 21 * |
22 **************************/ | 22 **************************/ |
23 #pragma mark - | 23 #pragma mark - |
24 #pragma mark (Constants) | 24 #pragma mark (Constants) |
25 | 25 |
| 26 #define kPageSize 4096 |
26 #if defined(__ppc__) || defined(__POWERPC__) | 27 #if defined(__ppc__) || defined(__POWERPC__) |
27 | 28 |
28 long kIslandTemplate[] = { | 29 long kIslandTemplate[] = { |
29 0x9001FFFC, // stw r0,-4(SP) | 30 0x9001FFFC, // stw r0,-4(SP) |
30 0x3C00DEAD, // lis r0,0xDEAD | 31 0x3C00DEAD, // lis r0,0xDEAD |
31 0x6000BEEF, // ori r0,r0,0xBEEF | 32 0x6000BEEF, // ori r0,r0,0xBEEF |
32 0x7C0903A6, // mtctr r0 | 33 0x7C0903A6, // mtctr r0 |
33 0x8001FFFC, // lwz r0,-4(SP) | 34 0x8001FFFC, // lwz r0,-4(SP) |
34 0x60000000, // nop ; optionally replaced | 35 0x60000000, // nop ; optionally replaced |
35 0x4E800420 // bctr | 36 0x4E800420 // bctr |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
69 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, | 70 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, |
70 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, | 71 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, |
71 // Now the real jump instruction | 72 // Now the real jump instruction |
72 0xFF, 0x25, 0x00, 0x00, 0x00, 0x00, | 73 0xFF, 0x25, 0x00, 0x00, 0x00, 0x00, |
73 0x00, 0x00, 0x00, 0x00, | 74 0x00, 0x00, 0x00, 0x00, |
74 0x00, 0x00, 0x00, 0x00 | 75 0x00, 0x00, 0x00, 0x00 |
75 }; | 76 }; |
76 | 77 |
77 #endif | 78 #endif |
78 | 79 |
79 #define kAllocateHigh 1 | |
80 #define kAllocateNormal 0 | |
81 | |
82 /************************** | 80 /************************** |
83 * | 81 * |
84 * Data Types | 82 * Data Types |
85 * | 83 * |
86 **************************/ | 84 **************************/ |
87 #pragma mark - | 85 #pragma mark - |
88 #pragma mark (Data Types) | 86 #pragma mark (Data Types) |
89 | 87 |
90 typedef struct { | 88 typedef struct { |
91 char instructions[sizeof(kIslandTemplate)]; | 89 char instructions[sizeof(kIslandTemplate)]; |
92 int allocatedHigh; | |
93 } BranchIsland; | 90 } BranchIsland; |
94 | 91 |
95 /************************** | 92 /************************** |
96 * | 93 * |
97 * Funky Protos | 94 * Funky Protos |
98 * | 95 * |
99 **************************/ | 96 **************************/ |
100 #pragma mark - | 97 #pragma mark - |
101 #pragma mark (Funky Protos) | 98 #pragma mark (Funky Protos) |
102 | 99 |
103 mach_error_t | 100 mach_error_t |
104 allocateBranchIsland( | 101 allocateBranchIsland( |
105 BranchIsland **island, | 102 BranchIsland **island, |
106 int allocateHigh, | |
107 void *originalFunctionAddress); | 103 void *originalFunctionAddress); |
108 | 104 |
109 mach_error_t | 105 mach_error_t |
110 freeBranchIsland( | 106 freeBranchIsland( |
111 BranchIsland *island ); | 107 BranchIsland *island ); |
112 | 108 |
113 #if defined(__ppc__) || defined(__POWERPC__) | 109 #if defined(__ppc__) || defined(__POWERPC__) |
114 mach_error_t | 110 mach_error_t |
115 setBranchIslandTarget( | 111 setBranchIslandTarget( |
116 BranchIsland *island, | 112 BranchIsland *island, |
(...skipping 10 matching lines...) Expand all Loading... |
127 void | 123 void |
128 atomic_mov64( | 124 atomic_mov64( |
129 uint64_t *targetAddress, | 125 uint64_t *targetAddress, |
130 uint64_t value ); | 126 uint64_t value ); |
131 | 127 |
132 static Boolean | 128 static Boolean |
133 eatKnownInstructions( | 129 eatKnownInstructions( |
134 unsigned char *code, | 130 unsigned char *code, |
135 uint64_t *newInstruction, | 131 uint64_t *newInstruction, |
136 int *howManyEaten, | 132 int *howManyEaten, |
137 » char» » » *originalInstructions ); | 133 » char» » » *originalInstructions, |
| 134 » int» » » » *originalInstructionCount, |
| 135 » uint8_t»» » *originalInstructionSizes ); |
| 136 |
| 137 » static void |
| 138 fixupInstructions( |
| 139 void» » *originalFunction, |
| 140 void» » *escapeIsland, |
| 141 void» » *instructionsToFix, |
| 142 » int» » » instructionCount, |
| 143 » uint8_t»» *instructionSizes ); |
138 #endif | 144 #endif |
139 | 145 |
140 /******************************************************************************* | 146 /******************************************************************************* |
141 * | 147 * |
142 * Interface | 148 * Interface |
143 * | 149 * |
144 *******************************************************************************/ | 150 *******************************************************************************/ |
145 #pragma mark - | 151 #pragma mark - |
146 #pragma mark (Interface) | 152 #pragma mark (Interface) |
147 | 153 |
148 #if defined(__i386__) || defined(__x86_64__) | 154 #if defined(__i386__) || defined(__x86_64__) |
149 mach_error_t makeIslandExecutable(void *address) { | 155 mach_error_t makeIslandExecutable(void *address) { |
150 mach_error_t err = err_none; | 156 mach_error_t err = err_none; |
151 vm_size_t pageSize; | 157 uintptr_t page = (uintptr_t)address & ~(uintptr_t)(kPageSize-1); |
152 host_page_size( mach_host_self(), &pageSize ); | |
153 uintptr_t page = (uintptr_t)address & ~(uintptr_t)(pageSize-1); | |
154 int e = err_none; | 158 int e = err_none; |
155 e |= mprotect((void *)page, pageSize, PROT_EXEC | PROT_READ | PROT_WRITE); | 159 e |= mprotect((void *)page, kPageSize, PROT_EXEC | PROT_READ | PROT_WRITE); |
156 e |= msync((void *)page, pageSize, MS_INVALIDATE ); | 160 e |= msync((void *)page, kPageSize, MS_INVALIDATE ); |
157 if (e) { | 161 if (e) { |
158 err = err_cannot_override; | 162 err = err_cannot_override; |
159 } | 163 } |
160 return err; | 164 return err; |
161 } | 165 } |
162 #endif | 166 #endif |
163 | 167 |
164 mach_error_t | 168 mach_error_t |
165 mach_override_ptr( | 169 mach_override_ptr( |
166 void *originalFunctionAddress, | 170 void *originalFunctionAddress, |
167 const void *overrideFunctionAddress, | 171 const void *overrideFunctionAddress, |
168 void **originalFunctionReentryIsland ) | 172 void **originalFunctionReentryIsland ) |
169 { | 173 { |
170 assert( originalFunctionAddress ); | 174 assert( originalFunctionAddress ); |
171 assert( overrideFunctionAddress ); | 175 assert( overrideFunctionAddress ); |
172 | 176 |
173 // this addresses overriding such functions as AudioOutputUnitStart() | 177 // this addresses overriding such functions as AudioOutputUnitStart() |
174 // test with modified DefaultOutputUnit project | 178 // test with modified DefaultOutputUnit project |
175 #if defined(__x86_64__) || defined(__i386__) | 179 #if defined(__x86_64__) |
176 for(;;){ | 180 for(;;){ |
177 if(*(unsigned char*)originalFunctionAddress==0xE9) // jmp .+0x?????
??? | 181 if(*(uint16_t*)originalFunctionAddress==0x25FF) // jmp qword near [ri
p+0x????????] |
178 originalFunctionAddress=(void*)((char*)originalFunctionAddress+5+*(i
nt32_t *)((char*)originalFunctionAddress+1)); | |
179 #if defined(__x86_64__) | |
180 else if(*(uint16_t*)originalFunctionAddress==0x25FF) // jmp qword nea
r [rip+0x????????] | |
181 originalFunctionAddress=*(void**)((char*)originalFunctionAddress+6+*
(int32_t *)((uint16_t*)originalFunctionAddress+1)); | 182 originalFunctionAddress=*(void**)((char*)originalFunctionAddress+6+*
(int32_t *)((uint16_t*)originalFunctionAddress+1)); |
| 183 else break; |
| 184 } |
182 #elif defined(__i386__) | 185 #elif defined(__i386__) |
183 else if(*(uint16_t*)originalFunctionAddress==0x25FF) // jmp *0x??????
?? | 186 for(;;){ |
| 187 if(*(uint16_t*)originalFunctionAddress==0x25FF) // jmp *0x???????? |
184 originalFunctionAddress=**(void***)((uint16_t*)originalFunctionAddre
ss+1); | 188 originalFunctionAddress=**(void***)((uint16_t*)originalFunctionAddre
ss+1); |
185 #endif | |
186 else break; | 189 else break; |
187 } | 190 } |
188 #endif | 191 #endif |
189 | 192 |
190 long *originalFunctionPtr = (long*) originalFunctionAddress; | 193 long *originalFunctionPtr = (long*) originalFunctionAddress; |
191 mach_error_t err = err_none; | 194 mach_error_t err = err_none; |
192 | 195 |
193 #if defined(__ppc__) || defined(__POWERPC__) | 196 #if defined(__ppc__) || defined(__POWERPC__) |
194 // Ensure first instruction isn't 'mfctr'. | 197 // Ensure first instruction isn't 'mfctr'. |
195 #define kMFCTRMask 0xfc1fffff | 198 #define kMFCTRMask 0xfc1fffff |
196 #define kMFCTRInstruction 0x7c0903a6 | 199 #define kMFCTRInstruction 0x7c0903a6 |
197 | 200 |
198 long originalInstruction = *originalFunctionPtr; | 201 long originalInstruction = *originalFunctionPtr; |
199 if( !err && ((originalInstruction & kMFCTRMask) == kMFCTRInstruction) ) | 202 if( !err && ((originalInstruction & kMFCTRMask) == kMFCTRInstruction) ) |
200 err = err_cannot_override; | 203 err = err_cannot_override; |
201 #elif defined(__i386__) || defined(__x86_64__) | 204 #elif defined(__i386__) || defined(__x86_64__) |
202 int eatenCount = 0; | 205 int eatenCount = 0; |
| 206 int originalInstructionCount = 0; |
203 char originalInstructions[kOriginalInstructionsSize]; | 207 char originalInstructions[kOriginalInstructionsSize]; |
| 208 uint8_t originalInstructionSizes[kOriginalInstructionsSize]; |
204 uint64_t jumpRelativeInstruction = 0; // JMP | 209 uint64_t jumpRelativeInstruction = 0; // JMP |
205 | 210 |
206 Boolean overridePossible = eatKnownInstructions ((unsigned char *)origin
alFunctionPtr, | 211 Boolean overridePossible = eatKnownInstructions ((unsigned char *)origin
alFunctionPtr, |
207 » » » » » » » » » »
&jumpRelativeInstruction, &eatenCount, originalInstructions); | 212 » » » » » » » » » »
&jumpRelativeInstruction, &eatenCount, |
| 213 » » » » » » » » » »
originalInstructions, &originalInstructionCount, |
| 214 » » » » » » » » » »
originalInstructionSizes ); |
208 if (eatenCount > kOriginalInstructionsSize) { | 215 if (eatenCount > kOriginalInstructionsSize) { |
209 //printf ("Too many instructions eaten\n"); | 216 //printf ("Too many instructions eaten\n"); |
210 overridePossible = false; | 217 overridePossible = false; |
211 } | 218 } |
212 if (!overridePossible) err = err_cannot_override; | 219 if (!overridePossible) err = err_cannot_override; |
213 if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__); | 220 if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__); |
214 #endif | 221 #endif |
215 | 222 |
216 // Make the original function implementation writable. | 223 // Make the original function implementation writable. |
217 if( !err ) { | 224 if( !err ) { |
218 err = vm_protect( mach_task_self(), | 225 err = vm_protect( mach_task_self(), |
219 (vm_address_t) originalFunctionPtr, 8, false, | 226 (vm_address_t) originalFunctionPtr, 8, false, |
220 (VM_PROT_ALL | VM_PROT_COPY) ); | 227 (VM_PROT_ALL | VM_PROT_COPY) ); |
221 if( err ) | 228 if( err ) |
222 err = vm_protect( mach_task_self(), | 229 err = vm_protect( mach_task_self(), |
223 (vm_address_t) originalFunctionPtr, 8, f
alse, | 230 (vm_address_t) originalFunctionPtr, 8, f
alse, |
224 (VM_PROT_DEFAULT | VM_PROT_COPY) ); | 231 (VM_PROT_DEFAULT | VM_PROT_COPY) ); |
225 } | 232 } |
226 if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__); | 233 if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__); |
227 | 234 |
228 // Allocate and target the escape island to the overriding function
. | 235 // Allocate and target the escape island to the overriding function
. |
229 BranchIsland *escapeIsland = NULL; | 236 BranchIsland *escapeIsland = NULL; |
230 if( !err ) | 237 if( !err ) |
231 » » err = allocateBranchIsland( &escapeIsland, kAllocateHigh, origin
alFunctionAddress ); | 238 » » err = allocateBranchIsland( &escapeIsland, originalFunctionAddre
ss ); |
232 if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LI
NE__); | 239 if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LI
NE__); |
233 | 240 |
234 | 241 |
235 #if defined(__ppc__) || defined(__POWERPC__) | 242 #if defined(__ppc__) || defined(__POWERPC__) |
236 if( !err ) | 243 if( !err ) |
237 err = setBranchIslandTarget( escapeIsland, overrideFunctionAddre
ss, 0 ); | 244 err = setBranchIslandTarget( escapeIsland, overrideFunctionAddre
ss, 0 ); |
238 | 245 |
239 // Build the branch absolute instruction to the escape island. | 246 // Build the branch absolute instruction to the escape island. |
240 long branchAbsoluteInstruction = 0; // Set to 0 just to silence warni
ng. | 247 long branchAbsoluteInstruction = 0; // Set to 0 just to silence warni
ng. |
241 if( !err ) { | 248 if( !err ) { |
(...skipping 15 matching lines...) Expand all Loading... |
257 if (!err) { | 264 if (!err) { |
258 uint32_t addressOffset = ((char*)escapeIsland - (char*)originalF
unctionPtr - 5); | 265 uint32_t addressOffset = ((char*)escapeIsland - (char*)originalF
unctionPtr - 5); |
259 addressOffset = OSSwapInt32(addressOffset); | 266 addressOffset = OSSwapInt32(addressOffset); |
260 | 267 |
261 jumpRelativeInstruction |= 0xE900000000000000LL; | 268 jumpRelativeInstruction |= 0xE900000000000000LL; |
262 jumpRelativeInstruction |= ((uint64_t)addressOffset & 0xffffffff
) << 24; | 269 jumpRelativeInstruction |= ((uint64_t)addressOffset & 0xffffffff
) << 24; |
263 jumpRelativeInstruction = OSSwapInt64(jumpRelativeInstruction);
| 270 jumpRelativeInstruction = OSSwapInt64(jumpRelativeInstruction);
|
264 } | 271 } |
265 #endif | 272 #endif |
266 | 273 |
267 » //» Optionally allocate & return the reentry island. | 274 » //» Optionally allocate & return the reentry island. This may contai
n relocated |
| 275 » // jmp instructions and so has all the same addressing reachability req
uirements |
| 276 » // the escape island has to the original function, except the escape is
land is |
| 277 » // technically our original function. |
268 BranchIsland *reentryIsland = NULL; | 278 BranchIsland *reentryIsland = NULL; |
269 if( !err && originalFunctionReentryIsland ) { | 279 if( !err && originalFunctionReentryIsland ) { |
270 » » err = allocateBranchIsland( &reentryIsland, kAllocateHigh, NULL)
; | 280 » » err = allocateBranchIsland( &reentryIsland, escapeIsland); |
271 if( !err ) | 281 if( !err ) |
272 *originalFunctionReentryIsland = reentryIsland; | 282 *originalFunctionReentryIsland = reentryIsland; |
273 } | 283 } |
274 | 284 |
275 #if defined(__ppc__) || defined(__POWERPC__) | 285 #if defined(__ppc__) || defined(__POWERPC__) |
276 // Atomically: | 286 // Atomically: |
277 // o If the reentry island was allocated: | 287 // o If the reentry island was allocated: |
278 // o Insert the original instruction into the reentry islan
d. | 288 // o Insert the original instruction into the reentry islan
d. |
279 // o Target the reentry island at the 2nd instruction of th
e | 289 // o Target the reentry island at the 2nd instruction of th
e |
280 // original function. | 290 // original function. |
(...skipping 22 matching lines...) Expand all Loading... |
303 #elif defined(__i386__) || defined(__x86_64__) | 313 #elif defined(__i386__) || defined(__x86_64__) |
304 // Atomically: | 314 // Atomically: |
305 // o If the reentry island was allocated: | 315 // o If the reentry island was allocated: |
306 // o Insert the original instructions into the reentry isla
nd. | 316 // o Insert the original instructions into the reentry isla
nd. |
307 // o Target the reentry island at the first non-replaced | 317 // o Target the reentry island at the first non-replaced |
308 // instruction of the original function. | 318 // instruction of the original function. |
309 // o Replace the original first instructions with the jump relative
. | 319 // o Replace the original first instructions with the jump relative
. |
310 // | 320 // |
311 // Note that on i386, we do not support someone else changing the code u
nder our feet | 321 // Note that on i386, we do not support someone else changing the code u
nder our feet |
312 if ( !err ) { | 322 if ( !err ) { |
| 323 fixupInstructions(originalFunctionPtr, reentryIsland, originalIn
structions, |
| 324 originalInstructionCount, originalInstru
ctionSizes ); |
| 325 |
313 if( reentryIsland ) | 326 if( reentryIsland ) |
314 err = setBranchIslandTarget_i386( reentryIsland, | 327 err = setBranchIslandTarget_i386( reentryIsland, |
315
(void*) ((char *)originalFunctionPtr+eatenCount), originalInstructions ); | 328
(void*) ((char *)originalFunctionPtr+eatenCount), originalInstructions ); |
316 // try making islands executable before planting the jmp | 329 // try making islands executable before planting the jmp |
317 #if defined(__x86_64__) || defined(__i386__) | 330 #if defined(__x86_64__) || defined(__i386__) |
318 if( !err ) | 331 if( !err ) |
319 err = makeIslandExecutable(escapeIsland); | 332 err = makeIslandExecutable(escapeIsland); |
320 if( !err && reentryIsland ) | 333 if( !err && reentryIsland ) |
321 err = makeIslandExecutable(reentryIsland); | 334 err = makeIslandExecutable(reentryIsland); |
322 #endif | 335 #endif |
(...skipping 18 matching lines...) Expand all Loading... |
341 * Implementation | 354 * Implementation |
342 * | 355 * |
343 *******************************************************************************/ | 356 *******************************************************************************/ |
344 #pragma mark - | 357 #pragma mark - |
345 #pragma mark (Implementation) | 358 #pragma mark (Implementation) |
346 | 359 |
347 /***************************************************************************//** | 360 /***************************************************************************//** |
348 Implementation: Allocates memory for a branch island. | 361 Implementation: Allocates memory for a branch island. |
349 | 362 |
350 @param island <- The allocated island. | 363 @param island <- The allocated island. |
351 @param allocateHigh -> Whether to allocate the island at the en
d of the | |
352 address space (f
or use with the branch absolute | |
353 instruction). | |
354 @result <- mach_error_t | 364 @result <- mach_error_t |
355 | 365 |
356 ************************************************************************
***/ | 366 ************************************************************************
***/ |
357 | 367 |
358 mach_error_t | 368 mach_error_t |
359 allocateBranchIsland( | 369 allocateBranchIsland( |
360 BranchIsland **island, | 370 BranchIsland **island, |
361 int allocateHigh, | |
362 void *originalFunctionAddress) | 371 void *originalFunctionAddress) |
363 { | 372 { |
364 assert( island ); | 373 assert( island ); |
365 » | 374 » assert( sizeof( BranchIsland ) <= kPageSize ); |
366 » mach_error_t» err = err_none; | 375 |
367 » | 376 » vm_map_t task_self = mach_task_self(); |
368 » if( allocateHigh ) { | 377 » vm_address_t original_address = (vm_address_t) originalFunctionAddress; |
369 » » vm_size_t pageSize; | 378 » static vm_address_t last_allocated = 0; |
370 » » err = host_page_size( mach_host_self(), &pageSize ); | 379 » vm_address_t address = |
371 » » if( !err ) { | 380 » » last_allocated ? last_allocated : original_address; |
372 » » » assert( sizeof( BranchIsland ) <= pageSize ); | 381 |
373 #if defined(__x86_64__) | 382 » for (;;) { |
374 » » » vm_address_t first = (uint64_t)originalFunctionAddress &
~(uint64_t)(((uint64_t)1 << 31) - 1) | ((uint64_t)1 << 31); // start in the mid
dle of the page? | 383 » » vm_size_t vmsize = 0; |
375 » » » vm_address_t last = 0x0; | 384 » » memory_object_name_t object = 0; |
| 385 » » kern_return_t kr = 0; |
| 386 » » vm_region_flavor_t flavor = VM_REGION_BASIC_INFO; |
| 387 » » // Find the page the address is in. |
| 388 #if __WORDSIZE == 32 |
| 389 » » vm_region_basic_info_data_t info; |
| 390 » » mach_msg_type_number_t info_count = VM_REGION_BASIC_INFO_COUNT; |
| 391 » » kr = vm_region(task_self, &address, &vmsize, flavor, |
| 392 » » » (vm_region_info_t)&info, &info_count, &object); |
376 #else | 393 #else |
377 » » » vm_address_t first = 0xffc00000; | 394 » » vm_region_basic_info_data_64_t info; |
378 » » » vm_address_t last = 0xfffe0000; | 395 » » mach_msg_type_number_t info_count = VM_REGION_BASIC_INFO_COUNT_6
4; |
| 396 » » kr = vm_region_64(task_self, &address, &vmsize, flavor, |
| 397 » » » » (vm_region_info_t)&info, &info_count, &object)
; |
379 #endif | 398 #endif |
| 399 if (kr != KERN_SUCCESS) |
| 400 return kr; |
380 | 401 |
381 » » » vm_address_t page = first; | 402 » » // Don't underflow. This could be made to work, but this is a |
382 » » » int allocated = 0; | 403 » » // convenient place to give up. |
383 » » » vm_map_t task_self = mach_task_self(); | 404 » » assert((address & (kPageSize - 1)) == 0); |
384 » » » | 405 » » if (address == 0) |
385 » » » while( !err && !allocated && page != last ) { | 406 » » » break; |
386 | 407 |
387 » » » » err = vm_allocate( task_self, &page, pageSize, 0
); | 408 » » // Go back one page. |
388 » » » » if( err == err_none ) | 409 » » vm_address_t new_address = address - kPageSize; |
389 » » » » » allocated = 1; | 410 #if __WORDSIZE == 64 |
390 » » » » else if( err == KERN_NO_SPACE ) { | 411 » » if(original_address - new_address - 5 > INT32_MAX) |
391 #if defined(__x86_64__) | 412 » » » break; |
392 » » » » » page -= pageSize; | |
393 #else | |
394 » » » » » page += pageSize; | |
395 #endif | 413 #endif |
396 » » » » » err = err_none; | 414 » » address = new_address; |
397 » » » » } | 415 |
398 » » » } | 416 » » // Try to allocate this page. |
399 » » » if( allocated ) | 417 » » kr = vm_allocate(task_self, &address, kPageSize, 0); |
400 » » » » *island = (BranchIsland*) page; | 418 » » if (kr == KERN_SUCCESS) { |
401 » » » else if( !allocated && !err ) | 419 » » » *island = (BranchIsland*) address; |
402 » » » » err = KERN_NO_SPACE; | 420 » » » last_allocated = address; |
| 421 » » » return err_none; |
403 } | 422 } |
404 » } else { | 423 » » if (kr != KERN_NO_SPACE) |
405 » » void *block = malloc( sizeof( BranchIsland ) ); | 424 » » » return kr; |
406 » » if( block ) | |
407 » » » *island = block; | |
408 » » else | |
409 » » » err = KERN_NO_SPACE; | |
410 } | 425 } |
411 » if( !err ) | 426 |
412 » » (**island).allocatedHigh = allocateHigh; | 427 » return KERN_NO_SPACE; |
413 » | |
414 » return err; | |
415 } | 428 } |
416 | 429 |
417 /***************************************************************************//** | 430 /***************************************************************************//** |
418 Implementation: Deallocates memory for a branch island. | 431 Implementation: Deallocates memory for a branch island. |
419 | 432 |
420 @param island -> The island to deallocate. | 433 @param island -> The island to deallocate. |
421 @result <- mach_error_t | 434 @result <- mach_error_t |
422 | 435 |
423 ************************************************************************
***/ | 436 ************************************************************************
***/ |
424 | 437 |
425 mach_error_t | 438 mach_error_t |
426 freeBranchIsland( | 439 freeBranchIsland( |
427 BranchIsland *island ) | 440 BranchIsland *island ) |
428 { | 441 { |
429 assert( island ); | 442 assert( island ); |
430 assert( (*(long*)&island->instructions[0]) == kIslandTemplate[0] ); | 443 assert( (*(long*)&island->instructions[0]) == kIslandTemplate[0] ); |
431 » assert( island->allocatedHigh ); | 444 » assert( sizeof( BranchIsland ) <= kPageSize ); |
432 » | 445 » return vm_deallocate( mach_task_self(), (vm_address_t) island, |
433 » mach_error_t» err = err_none; | 446 » » » kPageSize ); |
434 » | |
435 » if( island->allocatedHigh ) { | |
436 » » vm_size_t pageSize; | |
437 » » err = host_page_size( mach_host_self(), &pageSize ); | |
438 » » if( !err ) { | |
439 » » » assert( sizeof( BranchIsland ) <= pageSize ); | |
440 » » » err = vm_deallocate( | |
441 » » » » » mach_task_self(), | |
442 » » » » » (vm_address_t) island, pageSize ); | |
443 » » } | |
444 » } else { | |
445 » » free( island ); | |
446 » } | |
447 » | |
448 » return err; | |
449 } | 447 } |
450 | 448 |
451 /***************************************************************************//** | 449 /***************************************************************************//** |
452 Implementation: Sets the branch island's target, with an optional | 450 Implementation: Sets the branch island's target, with an optional |
453 instruction. | 451 instruction. |
454 | 452 |
455 @param island -> The branch island to insert target into. | 453 @param island -> The branch island to insert target into. |
456 @param branchTo -> The address of the target. | 454 @param branchTo -> The address of the target. |
457 @param instruction -> Optional instruction to execute prior to
branch. Set | 455 @param instruction -> Optional instruction to execute prior to
branch. Set |
458 to zero for nop. | 456 to zero for nop. |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
540 #if defined(__i386__) || defined(__x86_64__) | 538 #if defined(__i386__) || defined(__x86_64__) |
541 // simplistic instruction matching | 539 // simplistic instruction matching |
542 typedef struct { | 540 typedef struct { |
543 unsigned int length; // max 15 | 541 unsigned int length; // max 15 |
544 unsigned char mask[15]; // sequence of bytes in memory order | 542 unsigned char mask[15]; // sequence of bytes in memory order |
545 unsigned char constraint[15]; // sequence of bytes in memory order | 543 unsigned char constraint[15]; // sequence of bytes in memory order |
546 } AsmInstructionMatch; | 544 } AsmInstructionMatch; |
547 | 545 |
548 #if defined(__i386__) | 546 #if defined(__i386__) |
549 static AsmInstructionMatch possibleInstructions[] = { | 547 static AsmInstructionMatch possibleInstructions[] = { |
| 548 { 0x5, {0xFF, 0x00, 0x00, 0x00, 0x00}, {0xE9, 0x00, 0x00, 0x00, 0x00} },
// jmp 0x???????? |
550 { 0x5, {0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, {0x55, 0x89, 0xe5, 0xc9, 0xc3} },
// push %ebp; mov %esp,%ebp; leave; ret | 549 { 0x5, {0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, {0x55, 0x89, 0xe5, 0xc9, 0xc3} },
// push %ebp; mov %esp,%ebp; leave; ret |
551 { 0x1, {0xFF}, {0x90} },
// nop | 550 { 0x1, {0xFF}, {0x90} },
// nop |
552 { 0x1, {0xFF}, {0x55} },
// push %esp | 551 { 0x1, {0xFF}, {0x55} },
// push %esp |
553 { 0x2, {0xFF, 0xFF}, {0x89, 0xE5} },
// mov %esp,%ebp | 552 { 0x2, {0xFF, 0xFF}, {0x89, 0xE5} },
// mov %esp,%ebp |
554 { 0x1, {0xFF}, {0x53} },
// push %ebx | 553 { 0x1, {0xFF}, {0x53} },
// push %ebx |
555 { 0x3, {0xFF, 0xFF, 0x00}, {0x83, 0xEC, 0x00} },
// sub 0x??, %esp | 554 { 0x3, {0xFF, 0xFF, 0x00}, {0x83, 0xEC, 0x00} },
// sub 0x??, %esp |
556 { 0x6, {0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00}, {0x81, 0xEC, 0x00, 0x00, 0x
00, 0x00} }, // sub 0x??, %esp with 32bit immediate | 555 { 0x6, {0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00}, {0x81, 0xEC, 0x00, 0x00, 0x
00, 0x00} }, // sub 0x??, %esp with 32bit immediate |
557 { 0x1, {0xFF}, {0x57} },
// push %edi | 556 { 0x1, {0xFF}, {0x57} },
// push %edi |
558 { 0x1, {0xFF}, {0x56} },
// push %esi | 557 { 0x1, {0xFF}, {0x56} },
// push %esi |
559 { 0x2, {0xFF, 0xFF}, {0x31, 0xC0} },
// xor %eax, %eax | 558 { 0x2, {0xFF, 0xFF}, {0x31, 0xC0} },
// xor %eax, %eax |
560 { 0x3, {0xFF, 0x4F, 0x00}, {0x8B, 0x45, 0x00} }, // mov $imm(%ebp), %re
g | 559 { 0x3, {0xFF, 0x4F, 0x00}, {0x8B, 0x45, 0x00} }, // mov $imm(%ebp), %re
g |
561 { 0x3, {0xFF, 0x4C, 0x00}, {0x8B, 0x40, 0x00} }, // mov $imm(%eax-%edx)
, %reg | 560 { 0x3, {0xFF, 0x4C, 0x00}, {0x8B, 0x40, 0x00} }, // mov $imm(%eax-%edx)
, %reg |
562 { 0x4, {0xFF, 0xFF, 0xFF, 0x00}, {0x8B, 0x4C, 0x24, 0x00} }, // mov $im
m(%esp), %ecx | 561 { 0x4, {0xFF, 0xFF, 0xFF, 0x00}, {0x8B, 0x4C, 0x24, 0x00} }, // mov $im
m(%esp), %ecx |
| 562 { 0x5, {0xFF, 0x00, 0x00, 0x00, 0x00}, {0xB8, 0x00, 0x00, 0x00, 0x00} },
// mov $imm, %eax |
563 { 0x0 } | 563 { 0x0 } |
564 }; | 564 }; |
565 #elif defined(__x86_64__) | 565 #elif defined(__x86_64__) |
566 static AsmInstructionMatch possibleInstructions[] = { | 566 static AsmInstructionMatch possibleInstructions[] = { |
| 567 { 0x5, {0xFF, 0x00, 0x00, 0x00, 0x00}, {0xE9, 0x00, 0x00, 0x00, 0x00} },
// jmp 0x???????? |
567 { 0x1, {0xFF}, {0x90} },
// nop | 568 { 0x1, {0xFF}, {0x90} },
// nop |
568 { 0x1, {0xF8}, {0x50} },
// push %rX | 569 { 0x1, {0xF8}, {0x50} },
// push %rX |
569 { 0x3, {0xFF, 0xFF, 0xFF}, {0x48, 0x89, 0xE5} },
// mov %rsp,%rbp | 570 { 0x3, {0xFF, 0xFF, 0xFF}, {0x48, 0x89, 0xE5} },
// mov %rsp,%rbp |
570 { 0x4, {0xFF, 0xFF, 0xFF, 0x00}, {0x48, 0x83, 0xEC, 0x00} },
// sub 0x??, %rsp | 571 { 0x4, {0xFF, 0xFF, 0xFF, 0x00}, {0x48, 0x83, 0xEC, 0x00} },
// sub 0x??, %rsp |
571 { 0x4, {0xFB, 0xFF, 0x00, 0x00}, {0x48, 0x89, 0x00, 0x00} },
// move onto rbp | 572 { 0x4, {0xFB, 0xFF, 0x00, 0x00}, {0x48, 0x89, 0x00, 0x00} },
// move onto rbp |
| 573 { 0x4, {0xFF, 0xFF, 0xFF, 0xFF}, {0x40, 0x0f, 0xbe, 0xce} },
// movsbl %sil, %ecx |
572 { 0x2, {0xFF, 0x00}, {0x41, 0x00} },
// push %rXX | 574 { 0x2, {0xFF, 0x00}, {0x41, 0x00} },
// push %rXX |
573 { 0x2, {0xFF, 0x00}, {0x85, 0x00} },
// test %rX,%rX | 575 { 0x2, {0xFF, 0x00}, {0x85, 0x00} },
// test %rX,%rX |
574 { 0x5, {0xF8, 0x00, 0x00, 0x00, 0x00}, {0xB8, 0x00, 0x00, 0x00, 0x00} },
// mov $imm, %reg | 576 { 0x5, {0xF8, 0x00, 0x00, 0x00, 0x00}, {0xB8, 0x00, 0x00, 0x00, 0x00} },
// mov $imm, %reg |
575 { 0x3, {0xFF, 0xFF, 0x00}, {0xFF, 0x77, 0x00} }, // pushq $imm(%rdi) | 577 { 0x3, {0xFF, 0xFF, 0x00}, {0xFF, 0x77, 0x00} }, // pushq $imm(%rdi) |
| 578 { 0x2, {0xFF, 0xFF}, {0x31, 0xC0} },
// xor %eax, %eax |
| 579 { 0x2, {0xFF, 0xFF}, {0x89, 0xF8} }, // mov %edi, %ea
x |
576 { 0x0 } | 580 { 0x0 } |
577 }; | 581 }; |
578 #endif | 582 #endif |
579 | 583 |
580 static Boolean codeMatchesInstruction(unsigned char *code, AsmInstructionMatch*
instruction) | 584 static Boolean codeMatchesInstruction(unsigned char *code, AsmInstructionMatch*
instruction) |
581 { | 585 { |
582 Boolean match = true; | 586 Boolean match = true; |
583 | 587 |
584 size_t i; | 588 size_t i; |
585 for (i=0; i<instruction->length; i++) { | 589 for (i=0; i<instruction->length; i++) { |
586 unsigned char mask = instruction->mask[i]; | 590 unsigned char mask = instruction->mask[i]; |
587 unsigned char constraint = instruction->constraint[i]; | 591 unsigned char constraint = instruction->constraint[i]; |
588 unsigned char codeValue = code[i]; | 592 unsigned char codeValue = code[i]; |
589 | 593 |
590 match = ((codeValue & mask) == constraint); | 594 match = ((codeValue & mask) == constraint); |
591 if (!match) break; | 595 if (!match) break; |
592 } | 596 } |
593 | 597 |
594 return match; | 598 return match; |
595 } | 599 } |
596 | 600 |
597 #if defined(__i386__) || defined(__x86_64__) | 601 #if defined(__i386__) || defined(__x86_64__) |
598 static Boolean | 602 static Boolean |
599 eatKnownInstructions( | 603 eatKnownInstructions( |
600 » unsigned char *code, | 604 » unsigned char» *code, |
601 » uint64_t* newInstruction, | 605 » uint64_t» » *newInstruction, |
602 » int* howManyEaten, | 606 » int» » » » *howManyEaten, |
603 » char* originalInstructions ) | 607 » char» » » *originalInstructions, |
| 608 » int» » » » *originalInstructionCount, |
| 609 » uint8_t»» » *originalInstructionSizes ) |
604 { | 610 { |
605 Boolean allInstructionsKnown = true; | 611 Boolean allInstructionsKnown = true; |
606 int totalEaten = 0; | 612 int totalEaten = 0; |
607 unsigned char* ptr = code; | 613 unsigned char* ptr = code; |
608 int remainsToEat = 5; // a JMP instruction takes 5 bytes | 614 int remainsToEat = 5; // a JMP instruction takes 5 bytes |
| 615 int instructionIndex = 0; |
609 | 616 |
610 if (howManyEaten) *howManyEaten = 0; | 617 if (howManyEaten) *howManyEaten = 0; |
| 618 if (originalInstructionCount) *originalInstructionCount = 0; |
611 while (remainsToEat > 0) { | 619 while (remainsToEat > 0) { |
612 Boolean curInstructionKnown = false; | 620 Boolean curInstructionKnown = false; |
613 | 621 |
614 // See if instruction matches one we know | 622 // See if instruction matches one we know |
615 AsmInstructionMatch* curInstr = possibleInstructions; | 623 AsmInstructionMatch* curInstr = possibleInstructions; |
616 do { | 624 do { |
617 if ((curInstructionKnown = codeMatchesInstruction(ptr, c
urInstr))) break; | 625 if ((curInstructionKnown = codeMatchesInstruction(ptr, c
urInstr))) break; |
618 curInstr++; | 626 curInstr++; |
619 } while (curInstr->length > 0); | 627 } while (curInstr->length > 0); |
620 | 628 |
621 // if all instruction matches failed, we don't know current inst
ruction then, stop here | 629 // if all instruction matches failed, we don't know current inst
ruction then, stop here |
622 if (!curInstructionKnown) { | 630 if (!curInstructionKnown) { |
623 allInstructionsKnown = false; | 631 allInstructionsKnown = false; |
624 fprintf(stderr, "mach_override: some instructions unknow
n! Need to update mach_override.c\n"); | 632 fprintf(stderr, "mach_override: some instructions unknow
n! Need to update mach_override.c\n"); |
625 break; | 633 break; |
626 } | 634 } |
627 | 635 |
628 // At this point, we've matched curInstr | 636 // At this point, we've matched curInstr |
629 int eaten = curInstr->length; | 637 int eaten = curInstr->length; |
630 ptr += eaten; | 638 ptr += eaten; |
631 remainsToEat -= eaten; | 639 remainsToEat -= eaten; |
632 totalEaten += eaten; | 640 totalEaten += eaten; |
| 641 |
| 642 if (originalInstructionSizes) originalInstructionSizes[instructi
onIndex] = eaten; |
| 643 instructionIndex += 1; |
| 644 if (originalInstructionCount) *originalInstructionCount = instru
ctionIndex; |
633 } | 645 } |
634 | 646 |
635 | 647 |
636 if (howManyEaten) *howManyEaten = totalEaten; | 648 if (howManyEaten) *howManyEaten = totalEaten; |
637 | 649 |
638 if (originalInstructions) { | 650 if (originalInstructions) { |
639 Boolean enoughSpaceForOriginalInstructions = (totalEaten < kOrig
inalInstructionsSize); | 651 Boolean enoughSpaceForOriginalInstructions = (totalEaten < kOrig
inalInstructionsSize); |
640 | 652 |
641 if (enoughSpaceForOriginalInstructions) { | 653 if (enoughSpaceForOriginalInstructions) { |
642 memset(originalInstructions, 0x90 /* NOP */, kOriginalIn
structionsSize); // fill instructions with NOP | 654 memset(originalInstructions, 0x90 /* NOP */, kOriginalIn
structionsSize); // fill instructions with NOP |
(...skipping 10 matching lines...) Expand all Loading... |
653 currentFirst64BitsOfCode = OSSwapInt64(currentFirst64BitsOfCode)
; // back to memory representation | 665 currentFirst64BitsOfCode = OSSwapInt64(currentFirst64BitsOfCode)
; // back to memory representation |
654 currentFirst64BitsOfCode &= 0x0000000000FFFFFFLL; | 666 currentFirst64BitsOfCode &= 0x0000000000FFFFFFLL; |
655 | 667 |
656 // keep only last 3 instructions bytes, first 5 will be replaced
by JMP instr | 668 // keep only last 3 instructions bytes, first 5 will be replaced
by JMP instr |
657 *newInstruction &= 0xFFFFFFFFFF000000LL; // clear last 3 bytes | 669 *newInstruction &= 0xFFFFFFFFFF000000LL; // clear last 3 bytes |
658 *newInstruction |= (currentFirst64BitsOfCode & 0x0000000000FFFFF
FLL); // set last 3 bytes | 670 *newInstruction |= (currentFirst64BitsOfCode & 0x0000000000FFFFF
FLL); // set last 3 bytes |
659 } | 671 } |
660 | 672 |
661 return allInstructionsKnown; | 673 return allInstructionsKnown; |
662 } | 674 } |
| 675 |
| 676 static void |
| 677 fixupInstructions( |
| 678 void *originalFunction, |
| 679 void *escapeIsland, |
| 680 void *instructionsToFix, |
| 681 int instructionCount, |
| 682 uint8_t *instructionSizes ) |
| 683 { |
| 684 int index; |
| 685 for (index = 0;index < instructionCount;index += 1) |
| 686 { |
| 687 if (*(uint8_t*)instructionsToFix == 0xE9) // 32-bit jump relativ
e |
| 688 { |
| 689 uint32_t offset = (uintptr_t)originalFunction - (uintptr
_t)escapeIsland; |
| 690 uint32_t *jumpOffsetPtr = (uint32_t*)((uintptr_t)instruc
tionsToFix + 1); |
| 691 *jumpOffsetPtr += offset; |
| 692 } |
| 693 |
| 694 originalFunction = (void*)((uintptr_t)originalFunction + instruc
tionSizes[index]); |
| 695 escapeIsland = (void*)((uintptr_t)escapeIsland + instructionSize
s[index]); |
| 696 instructionsToFix = (void*)((uintptr_t)instructionsToFix + instr
uctionSizes[index]); |
| 697 } |
| 698 } |
663 #endif | 699 #endif |
664 | 700 |
665 #if defined(__i386__) | 701 #if defined(__i386__) |
666 __asm( | 702 __asm( |
667 ".text;" | 703 ".text;" |
668 ".align 2, 0x90;" | 704 ".align 2, 0x90;" |
669 "_atomic_mov64:;" | 705 "_atomic_mov64:;" |
670 " pushl %ebp;" | 706 " pushl %ebp;" |
671 " movl %esp, %ebp;" | 707 " movl %esp, %ebp;" |
672 " pushl %esi;" | 708 " pushl %esi;" |
(...skipping 26 matching lines...) Expand all Loading... |
699 ); | 735 ); |
700 #elif defined(__x86_64__) | 736 #elif defined(__x86_64__) |
701 void atomic_mov64( | 737 void atomic_mov64( |
702 uint64_t *targetAddress, | 738 uint64_t *targetAddress, |
703 uint64_t value ) | 739 uint64_t value ) |
704 { | 740 { |
705 *targetAddress = value; | 741 *targetAddress = value; |
706 } | 742 } |
707 #endif | 743 #endif |
708 #endif | 744 #endif |
OLD | NEW |