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> |
(...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
163 | 163 |
164 mach_error_t | 164 mach_error_t |
165 mach_override_ptr( | 165 mach_override_ptr( |
166 void *originalFunctionAddress, | 166 void *originalFunctionAddress, |
167 const void *overrideFunctionAddress, | 167 const void *overrideFunctionAddress, |
168 void **originalFunctionReentryIsland ) | 168 void **originalFunctionReentryIsland ) |
169 { | 169 { |
170 assert( originalFunctionAddress ); | 170 assert( originalFunctionAddress ); |
171 assert( overrideFunctionAddress ); | 171 assert( overrideFunctionAddress ); |
172 | 172 |
| 173 // this addresses overriding such functions as AudioOutputUnitStart() |
| 174 // test with modified DefaultOutputUnit project |
| 175 #if defined(__x86_64__) || defined(__i386__) |
| 176 for(;;){ |
| 177 if(*(unsigned char*)originalFunctionAddress==0xE9) // jmp .+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 #elif defined(__i386__) |
| 183 else if(*(uint16_t*)originalFunctionAddress==0x25FF) // jmp *0x??????
?? |
| 184 originalFunctionAddress=**(void***)((uint16_t*)originalFunctionAddre
ss+1); |
| 185 #endif |
| 186 else break; |
| 187 } |
| 188 #endif |
| 189 |
173 long *originalFunctionPtr = (long*) originalFunctionAddress; | 190 long *originalFunctionPtr = (long*) originalFunctionAddress; |
174 mach_error_t err = err_none; | 191 mach_error_t err = err_none; |
175 | 192 |
176 #if defined(__ppc__) || defined(__POWERPC__) | 193 #if defined(__ppc__) || defined(__POWERPC__) |
177 // Ensure first instruction isn't 'mfctr'. | 194 // Ensure first instruction isn't 'mfctr'. |
178 #define kMFCTRMask 0xfc1fffff | 195 #define kMFCTRMask 0xfc1fffff |
179 #define kMFCTRInstruction 0x7c0903a6 | 196 #define kMFCTRInstruction 0x7c0903a6 |
180 | 197 |
181 long originalInstruction = *originalFunctionPtr; | 198 long originalInstruction = *originalFunctionPtr; |
182 if( !err && ((originalInstruction & kMFCTRMask) == kMFCTRInstruction) ) | 199 if( !err && ((originalInstruction & kMFCTRMask) == kMFCTRInstruction) ) |
183 err = err_cannot_override; | 200 err = err_cannot_override; |
184 #elif defined(__i386__) || defined(__x86_64__) | 201 #elif defined(__i386__) || defined(__x86_64__) |
185 int eatenCount = 0; | 202 int eatenCount = 0; |
186 char originalInstructions[kOriginalInstructionsSize]; | 203 char originalInstructions[kOriginalInstructionsSize]; |
187 uint64_t jumpRelativeInstruction = 0; // JMP | 204 uint64_t jumpRelativeInstruction = 0; // JMP |
188 | 205 |
189 Boolean overridePossible = eatKnownInstructions ((unsigned char *)origin
alFunctionPtr, | 206 Boolean overridePossible = eatKnownInstructions ((unsigned char *)origin
alFunctionPtr, |
190
&jumpRelativeInstruction, &eatenCount, originalInstructions); | 207
&jumpRelativeInstruction, &eatenCount, originalInstructions); |
191 if (eatenCount > kOriginalInstructionsSize) { | 208 if (eatenCount > kOriginalInstructionsSize) { |
192 //printf ("Too many instructions eaten\n"); | 209 //printf ("Too many instructions eaten\n"); |
193 overridePossible = false; | 210 overridePossible = false; |
194 } | 211 } |
195 if (!overridePossible) err = err_cannot_override; | 212 if (!overridePossible) err = err_cannot_override; |
196 » if (err) printf("err = %x %d\n", err, __LINE__); | 213 » if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__); |
197 #endif | 214 #endif |
198 | 215 |
199 // Make the original function implementation writable. | 216 // Make the original function implementation writable. |
200 if( !err ) { | 217 if( !err ) { |
201 err = vm_protect( mach_task_self(), | 218 err = vm_protect( mach_task_self(), |
202 » » » » (vm_address_t) originalFunctionPtr, | 219 » » » » (vm_address_t) originalFunctionPtr, 8, false, |
203 » » » » sizeof(long), false, (VM_PROT_ALL | VM_PROT_COPY
) ); | 220 » » » » (VM_PROT_ALL | VM_PROT_COPY) ); |
204 if( err ) | 221 if( err ) |
205 err = vm_protect( mach_task_self(), | 222 err = vm_protect( mach_task_self(), |
206 » » » » » (vm_address_t) originalFunctionPtr, size
of(long), false, | 223 » » » » » (vm_address_t) originalFunctionPtr, 8, f
alse, |
207 (VM_PROT_DEFAULT | VM_PROT_COPY) ); | 224 (VM_PROT_DEFAULT | VM_PROT_COPY) ); |
208 } | 225 } |
209 » if (err) printf("err = %x %d\n", err, __LINE__); | 226 » if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__); |
210 | 227 |
211 // Allocate and target the escape island to the overriding function
. | 228 // Allocate and target the escape island to the overriding function
. |
212 BranchIsland *escapeIsland = NULL; | 229 BranchIsland *escapeIsland = NULL; |
213 if( !err ) | 230 if( !err ) |
214 err = allocateBranchIsland( &escapeIsland, kAllocateHigh, origin
alFunctionAddress ); | 231 err = allocateBranchIsland( &escapeIsland, kAllocateHigh, origin
alFunctionAddress ); |
215 » » if (err) printf("err = %x %d\n", err, __LINE__); | 232 » » if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LI
NE__); |
216 | 233 |
217 | 234 |
218 #if defined(__ppc__) || defined(__POWERPC__) | 235 #if defined(__ppc__) || defined(__POWERPC__) |
219 if( !err ) | 236 if( !err ) |
220 err = setBranchIslandTarget( escapeIsland, overrideFunctionAddre
ss, 0 ); | 237 err = setBranchIslandTarget( escapeIsland, overrideFunctionAddre
ss, 0 ); |
221 | 238 |
222 // Build the branch absolute instruction to the escape island. | 239 // Build the branch absolute instruction to the escape island. |
223 long branchAbsoluteInstruction = 0; // Set to 0 just to silence warni
ng. | 240 long branchAbsoluteInstruction = 0; // Set to 0 just to silence warni
ng. |
224 if( !err ) { | 241 if( !err ) { |
225 long escapeIslandAddress = ((long) escapeIsland) & 0x3FFFFFF; | 242 long escapeIslandAddress = ((long) escapeIsland) & 0x3FFFFFF; |
226 branchAbsoluteInstruction = 0x48000002 | escapeIslandAddress; | 243 branchAbsoluteInstruction = 0x48000002 | escapeIslandAddress; |
227 } | 244 } |
228 #elif defined(__i386__) || defined(__x86_64__) | 245 #elif defined(__i386__) || defined(__x86_64__) |
229 if (err) printf("err = %x %d\n", err, __LINE__); | 246 if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__); |
230 | 247 |
231 if( !err ) | 248 if( !err ) |
232 err = setBranchIslandTarget_i386( escapeIsland, overrideFunction
Address, 0 ); | 249 err = setBranchIslandTarget_i386( escapeIsland, overrideFunction
Address, 0 ); |
233 | 250 |
234 » if (err) printf("err = %x %d\n", err, __LINE__); | 251 » if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__); |
235 // Build the jump relative instruction to the escape island | 252 // Build the jump relative instruction to the escape island |
236 #endif | 253 #endif |
237 | 254 |
238 | 255 |
239 #if defined(__i386__) || defined(__x86_64__) | 256 #if defined(__i386__) || defined(__x86_64__) |
240 if (!err) { | 257 if (!err) { |
241 » » uint32_t addressOffset = ((void*)escapeIsland - (void*)originalF
unctionPtr - 5); | 258 » » uint32_t addressOffset = ((char*)escapeIsland - (char*)originalF
unctionPtr - 5); |
242 addressOffset = OSSwapInt32(addressOffset); | 259 addressOffset = OSSwapInt32(addressOffset); |
243 | 260 |
244 jumpRelativeInstruction |= 0xE900000000000000LL; | 261 jumpRelativeInstruction |= 0xE900000000000000LL; |
245 jumpRelativeInstruction |= ((uint64_t)addressOffset & 0xffffffff
) << 24; | 262 jumpRelativeInstruction |= ((uint64_t)addressOffset & 0xffffffff
) << 24; |
246 jumpRelativeInstruction = OSSwapInt64(jumpRelativeInstruction);
| 263 jumpRelativeInstruction = OSSwapInt64(jumpRelativeInstruction);
|
247 } | 264 } |
248 #endif | 265 #endif |
249 | 266 |
250 // Optionally allocate & return the reentry island. | 267 // Optionally allocate & return the reentry island. |
251 BranchIsland *reentryIsland = NULL; | 268 BranchIsland *reentryIsland = NULL; |
252 if( !err && originalFunctionReentryIsland ) { | 269 if( !err && originalFunctionReentryIsland ) { |
253 » » err = allocateBranchIsland( &reentryIsland, kAllocateNormal, NUL
L); | 270 » » err = allocateBranchIsland( &reentryIsland, kAllocateHigh, NULL)
; |
254 if( !err ) | 271 if( !err ) |
255 *originalFunctionReentryIsland = reentryIsland; | 272 *originalFunctionReentryIsland = reentryIsland; |
256 } | 273 } |
257 | 274 |
258 #if defined(__ppc__) || defined(__POWERPC__) | 275 #if defined(__ppc__) || defined(__POWERPC__) |
259 // Atomically: | 276 // Atomically: |
260 // o If the reentry island was allocated: | 277 // o If the reentry island was allocated: |
261 // o Insert the original instruction into the reentry islan
d. | 278 // o Insert the original instruction into the reentry islan
d. |
262 // o Target the reentry island at the 2nd instruction of th
e | 279 // o Target the reentry island at the 2nd instruction of th
e |
263 // original function. | 280 // original function. |
(...skipping 25 matching lines...) Expand all Loading... |
289 // o Insert the original instructions into the reentry isla
nd. | 306 // o Insert the original instructions into the reentry isla
nd. |
290 // o Target the reentry island at the first non-replaced | 307 // o Target the reentry island at the first non-replaced |
291 // instruction of the original function. | 308 // instruction of the original function. |
292 // o Replace the original first instructions with the jump relative
. | 309 // o Replace the original first instructions with the jump relative
. |
293 // | 310 // |
294 // Note that on i386, we do not support someone else changing the code u
nder our feet | 311 // Note that on i386, we do not support someone else changing the code u
nder our feet |
295 if ( !err ) { | 312 if ( !err ) { |
296 if( reentryIsland ) | 313 if( reentryIsland ) |
297 err = setBranchIslandTarget_i386( reentryIsland, | 314 err = setBranchIslandTarget_i386( reentryIsland, |
298
(void*) ((char *)originalFunctionPtr+eatenCount), originalInstructions ); | 315
(void*) ((char *)originalFunctionPtr+eatenCount), originalInstructions ); |
| 316 // try making islands executable before planting the jmp |
| 317 #if defined(__x86_64__) || defined(__i386__) |
| 318 if( !err ) |
| 319 err = makeIslandExecutable(escapeIsland); |
| 320 if( !err && reentryIsland ) |
| 321 err = makeIslandExecutable(reentryIsland); |
| 322 #endif |
299 if ( !err ) | 323 if ( !err ) |
300 atomic_mov64((uint64_t *)originalFunctionPtr, jumpRelati
veInstruction); | 324 atomic_mov64((uint64_t *)originalFunctionPtr, jumpRelati
veInstruction); |
301 } | 325 } |
302 #endif | 326 #endif |
303 | 327 |
304 #if defined(__i386__) || defined(__x86_64__) | |
305 if ( !err ) | |
306 err = makeIslandExecutable( escapeIsland ); | |
307 if ( !err && reentryIsland ) | |
308 err = makeIslandExecutable( reentryIsland ); | |
309 #endif | |
310 | |
311 // Clean up on error. | 328 // Clean up on error. |
312 if( err ) { | 329 if( err ) { |
313 if( reentryIsland ) | 330 if( reentryIsland ) |
314 freeBranchIsland( reentryIsland ); | 331 freeBranchIsland( reentryIsland ); |
315 if( escapeIsland ) | 332 if( escapeIsland ) |
316 freeBranchIsland( escapeIsland ); | 333 freeBranchIsland( escapeIsland ); |
317 } | 334 } |
318 | 335 |
319 return err; | 336 return err; |
320 } | 337 } |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
373 else if( err == KERN_NO_SPACE ) { | 390 else if( err == KERN_NO_SPACE ) { |
374 #if defined(__x86_64__) | 391 #if defined(__x86_64__) |
375 page -= pageSize; | 392 page -= pageSize; |
376 #else | 393 #else |
377 page += pageSize; | 394 page += pageSize; |
378 #endif | 395 #endif |
379 err = err_none; | 396 err = err_none; |
380 } | 397 } |
381 } | 398 } |
382 if( allocated ) | 399 if( allocated ) |
383 » » » » *island = (void*) page; | 400 » » » » *island = (BranchIsland*) page; |
384 else if( !allocated && !err ) | 401 else if( !allocated && !err ) |
385 err = KERN_NO_SPACE; | 402 err = KERN_NO_SPACE; |
386 } | 403 } |
387 } else { | 404 } else { |
388 void *block = malloc( sizeof( BranchIsland ) ); | 405 void *block = malloc( sizeof( BranchIsland ) ); |
389 if( block ) | 406 if( block ) |
390 *island = block; | 407 *island = block; |
391 else | 408 else |
392 err = KERN_NO_SPACE; | 409 err = KERN_NO_SPACE; |
393 } | 410 } |
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
523 #if defined(__i386__) || defined(__x86_64__) | 540 #if defined(__i386__) || defined(__x86_64__) |
524 // simplistic instruction matching | 541 // simplistic instruction matching |
525 typedef struct { | 542 typedef struct { |
526 unsigned int length; // max 15 | 543 unsigned int length; // max 15 |
527 unsigned char mask[15]; // sequence of bytes in memory order | 544 unsigned char mask[15]; // sequence of bytes in memory order |
528 unsigned char constraint[15]; // sequence of bytes in memory order | 545 unsigned char constraint[15]; // sequence of bytes in memory order |
529 } AsmInstructionMatch; | 546 } AsmInstructionMatch; |
530 | 547 |
531 #if defined(__i386__) | 548 #if defined(__i386__) |
532 static AsmInstructionMatch possibleInstructions[] = { | 549 static AsmInstructionMatch possibleInstructions[] = { |
| 550 { 0x5, {0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, {0x55, 0x89, 0xe5, 0xc9, 0xc3} },
// push %ebp; mov %esp,%ebp; leave; ret |
533 { 0x1, {0xFF}, {0x90} },
// nop | 551 { 0x1, {0xFF}, {0x90} },
// nop |
534 { 0x1, {0xFF}, {0x55} },
// push %esp | 552 { 0x1, {0xFF}, {0x55} },
// push %esp |
535 { 0x2, {0xFF, 0xFF}, {0x89, 0xE5} },
// mov %esp,%ebp | 553 { 0x2, {0xFF, 0xFF}, {0x89, 0xE5} },
// mov %esp,%ebp |
536 { 0x1, {0xFF}, {0x53} },
// push %ebx | 554 { 0x1, {0xFF}, {0x53} },
// push %ebx |
537 { 0x3, {0xFF, 0xFF, 0x00}, {0x83, 0xEC, 0x00} },
// sub 0x??, %esp | 555 { 0x3, {0xFF, 0xFF, 0x00}, {0x83, 0xEC, 0x00} },
// sub 0x??, %esp |
538 { 0x6, {0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00}, {0x81, 0xEC, 0x00, 0x00, 0x
00, 0x00} }, // sub 0x??, %esp with 32bit immediate | 556 { 0x6, {0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00}, {0x81, 0xEC, 0x00, 0x00, 0x
00, 0x00} }, // sub 0x??, %esp with 32bit immediate |
539 { 0x1, {0xFF}, {0x57} },
// push %edi | 557 { 0x1, {0xFF}, {0x57} },
// push %edi |
540 { 0x1, {0xFF}, {0x56} },
// push %esi | 558 { 0x1, {0xFF}, {0x56} },
// push %esi |
541 { 0x2, {0xFF, 0xFF}, {0x31, 0xC0} },
// xor %eax, %eax | 559 { 0x2, {0xFF, 0xFF}, {0x31, 0xC0} },
// xor %eax, %eax |
| 560 { 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 |
| 562 { 0x4, {0xFF, 0xFF, 0xFF, 0x00}, {0x8B, 0x4C, 0x24, 0x00} }, // mov $im
m(%esp), %ecx |
542 { 0x0 } | 563 { 0x0 } |
543 }; | 564 }; |
544 #elif defined(__x86_64__) | 565 #elif defined(__x86_64__) |
545 static AsmInstructionMatch possibleInstructions[] = { | 566 static AsmInstructionMatch possibleInstructions[] = { |
546 { 0x1, {0xFF}, {0x90} },
// nop | 567 { 0x1, {0xFF}, {0x90} },
// nop |
547 { 0x1, {0xF8}, {0x50} },
// push %rX | 568 { 0x1, {0xF8}, {0x50} },
// push %rX |
548 { 0x3, {0xFF, 0xFF, 0xFF}, {0x48, 0x89, 0xE5} },
// mov %rsp,%rbp | 569 { 0x3, {0xFF, 0xFF, 0xFF}, {0x48, 0x89, 0xE5} },
// mov %rsp,%rbp |
549 { 0x4, {0xFF, 0xFF, 0xFF, 0x00}, {0x48, 0x83, 0xEC, 0x00} },
// sub 0x??, %rsp | 570 { 0x4, {0xFF, 0xFF, 0xFF, 0x00}, {0x48, 0x83, 0xEC, 0x00} },
// sub 0x??, %rsp |
550 { 0x4, {0xFB, 0xFF, 0x00, 0x00}, {0x48, 0x89, 0x00, 0x00} },
// move onto rbp | 571 { 0x4, {0xFB, 0xFF, 0x00, 0x00}, {0x48, 0x89, 0x00, 0x00} },
// move onto rbp |
551 { 0x2, {0xFF, 0x00}, {0x41, 0x00} },
// push %rXX | 572 { 0x2, {0xFF, 0x00}, {0x41, 0x00} },
// push %rXX |
552 { 0x2, {0xFF, 0x00}, {0x85, 0x00} },
// test %rX,%rX | 573 { 0x2, {0xFF, 0x00}, {0x85, 0x00} },
// test %rX,%rX |
| 574 { 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) |
553 { 0x0 } | 576 { 0x0 } |
554 }; | 577 }; |
555 #endif | 578 #endif |
556 | 579 |
557 static Boolean codeMatchesInstruction(unsigned char *code, AsmInstructionMatch*
instruction) | 580 static Boolean codeMatchesInstruction(unsigned char *code, AsmInstructionMatch*
instruction) |
558 { | 581 { |
559 Boolean match = true; | 582 Boolean match = true; |
560 | 583 |
561 size_t i; | 584 size_t i; |
562 for (i=0; i<instruction->length; i++) { | 585 for (i=0; i<instruction->length; i++) { |
(...skipping 28 matching lines...) Expand all Loading... |
591 // See if instruction matches one we know | 614 // See if instruction matches one we know |
592 AsmInstructionMatch* curInstr = possibleInstructions; | 615 AsmInstructionMatch* curInstr = possibleInstructions; |
593 do { | 616 do { |
594 if ((curInstructionKnown = codeMatchesInstruction(ptr, c
urInstr))) break; | 617 if ((curInstructionKnown = codeMatchesInstruction(ptr, c
urInstr))) break; |
595 curInstr++; | 618 curInstr++; |
596 } while (curInstr->length > 0); | 619 } while (curInstr->length > 0); |
597 | 620 |
598 // if all instruction matches failed, we don't know current inst
ruction then, stop here | 621 // if all instruction matches failed, we don't know current inst
ruction then, stop here |
599 if (!curInstructionKnown) { | 622 if (!curInstructionKnown) { |
600 allInstructionsKnown = false; | 623 allInstructionsKnown = false; |
| 624 fprintf(stderr, "mach_override: some instructions unknow
n! Need to update mach_override.c\n"); |
601 break; | 625 break; |
602 } | 626 } |
603 | 627 |
604 // At this point, we've matched curInstr | 628 // At this point, we've matched curInstr |
605 int eaten = curInstr->length; | 629 int eaten = curInstr->length; |
606 ptr += eaten; | 630 ptr += eaten; |
607 remainsToEat -= eaten; | 631 remainsToEat -= eaten; |
608 totalEaten += eaten; | 632 totalEaten += eaten; |
609 } | 633 } |
610 | 634 |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
675 ); | 699 ); |
676 #elif defined(__x86_64__) | 700 #elif defined(__x86_64__) |
677 void atomic_mov64( | 701 void atomic_mov64( |
678 uint64_t *targetAddress, | 702 uint64_t *targetAddress, |
679 uint64_t value ) | 703 uint64_t value ) |
680 { | 704 { |
681 *targetAddress = value; | 705 *targetAddress = value; |
682 } | 706 } |
683 #endif | 707 #endif |
684 #endif | 708 #endif |
OLD | NEW |