1 /*******************************************************************************
2 mach_override.c
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 #ifdef __APPLE__
8
9 #include "mach_override.h"
10
11 #include <mach-o/dyld.h>
12 #include <mach/mach_host.h>
13 #include <mach/mach_init.h>
14 #include <mach/vm_map.h>
15 #include <sys/mman.h>
16
17 #include <CoreServices/CoreServices.h>
18
19 //#define DEBUG_DISASM 1
20 #undef DEBUG_DISASM
21
22 /**************************
23 *
24 * Constants
25 *
26 **************************/
27 #pragma mark -
28 #pragma mark (Constants)
29
30 #if defined(__ppc__) || defined(__POWERPC__)
31
32 static
33 long kIslandTemplate[] = {
34 0x9001FFFC, // stw r0,-4(SP)
35 0x3C00DEAD, // lis r0,0xDEAD
36 0x6000BEEF, // ori r0,r0,0xBEEF
37 0x7C0903A6, // mtctr r0
38 0x8001FFFC, // lwz r0,-4(SP)
39 0x60000000, // nop ; optionally replaced
40 0x4E800420 // bctr
41 };
42
43 #define kAddressHi 3
44 #define kAddressLo 5
45 #define kInstructionHi 10
46 #define kInstructionLo 11
47
48 #elif defined(__i386__)
49
50 #define kOriginalInstructionsSize 16
51
52 static
53 char kIslandTemplate[] = {
54 // kOriginalInstructionsSize nop instructions so that we
55 // should have enough space to host original instructions
56 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
57 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
58 // Now the real jump instruction
59 0xE9, 0xEF, 0xBE, 0xAD, 0xDE
60 };
61
62 #define kInstructions 0
63 #define kJumpAddress kInstructions + kOriginalInstructionsSize + 1
64 #elif defined(__x86_64__)
65
66 #define kOriginalInstructionsSize 32
67
68 #define kJumpAddress kOriginalInstructionsSize + 6
69
70 static
71 char kIslandTemplate[] = {
72 // kOriginalInstructionsSize nop instructions so that we
73 // should have enough space to host original instructions
74 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
75 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
76 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
77 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
78 // Now the real jump instruction
79 0xFF, 0x25, 0x00, 0x00, 0x00, 0x00,
80 0x00, 0x00, 0x00, 0x00,
81 0x00, 0x00, 0x00, 0x00
82 };
83
84 #endif
85
86 #define kAllocateHigh 1
87 #define kAllocateNormal 0
88
89 /**************************
90 *
91 * Data Types
92 *
93 **************************/
94 #pragma mark -
95 #pragma mark (Data Types)
96
97 typedef struct {
98 char instructions[sizeof(kIslandTemplate)];
99 int allocatedHigh;
100 } BranchIsland;
101
102 /**************************
103 *
104 * Funky Protos
105 *
106 **************************/
107 #pragma mark -
108 #pragma mark (Funky Protos)
109
110
111 static mach_error_t
112 allocateBranchIsland(
113 BranchIsland **island,
114 int allocateHigh,
115 void *originalFunctionAddress) __attribute__((visibility("hidden")));
116
117 static mach_error_t
118 freeBranchIsland(
119 BranchIsland *island ) __attribute__((visibility("hidden")));
120
121 static mach_error_t
122 defaultIslandMalloc(
123 void **ptr, size_t unused_size, void *hint) __attribute__((visibility("hidden")));
124
125 static mach_error_t
126 defaultIslandFree(
127 void *ptr) __attribute__((visibility("hidden")));
128
129 #if defined(__ppc__) || defined(__POWERPC__)
130 static mach_error_t
131 setBranchIslandTarget(
132 BranchIsland *island,
133 const void *branchTo,
134 long instruction ) __attribute__((visibility("hidden")));
135 #endif
136
137 #if defined(__i386__) || defined(__x86_64__)
138 static mach_error_t
139 setBranchIslandTarget_i386(
140 BranchIsland *island,
141 const void *branchTo,
142 char* instructions ) __attribute__((visibility("hidden")));
143 // Can't be made static because there's no C implementation for atomic_mov64
144 // on i386.
145 void
146 atomic_mov64(
147 uint64_t *targetAddress,
148 uint64_t value ) __attribute__((visibility("hidden")));
149
150 static Boolean
151 eatKnownInstructions(
152 unsigned char *code,
153 uint64_t *newInstruction,
154 int *howManyEaten,
155 char *originalInstructions,
156 int *originalInstructionCount,
157 uint8_t *originalInstructionSizes ) __attribute__((visibility("hidden")));
158
159 static void
160 fixupInstructions(
161 void *originalFunction,
162 void *escapeIsland,
163 void *instructionsToFix,
164 int instructionCount,
165 uint8_t *instructionSizes ) __attribute__((visibility("hidden")));
166
167 #ifdef DEBUG_DISASM
168 static void
169 dump16Bytes(
170 void *ptr);
171 #endif // DEBUG_DISASM
172 #endif
173
174 /*******************************************************************************
175 *
176 * Interface
177 *
178 *******************************************************************************/
179 #pragma mark -
180 #pragma mark (Interface)
181
182 #if defined(__i386__) || defined(__x86_64__)
makeIslandExecutable(void * address)183 static mach_error_t makeIslandExecutable(void *address) {
184 mach_error_t err = err_none;
185 vm_size_t pageSize;
186 host_page_size( mach_host_self(), &pageSize );
187 uintptr_t page = (uintptr_t)address & ~(uintptr_t)(pageSize-1);
188 int e = err_none;
189 e |= mprotect((void *)page, pageSize, PROT_EXEC | PROT_READ | PROT_WRITE);
190 e |= msync((void *)page, pageSize, MS_INVALIDATE );
191 if (e) {
192 err = err_cannot_override;
193 }
194 return err;
195 }
196 #endif
197
198 static mach_error_t
defaultIslandMalloc(void ** ptr,size_t unused_size,void * hint)199 defaultIslandMalloc(
200 void **ptr, size_t unused_size, void *hint) {
201 return allocateBranchIsland( (BranchIsland**)ptr, kAllocateHigh, hint );
202 }
203 static mach_error_t
defaultIslandFree(void * ptr)204 defaultIslandFree(
205 void *ptr) {
206 return freeBranchIsland(ptr);
207 }
208
209 mach_error_t
__asan_mach_override_ptr(void * originalFunctionAddress,const void * overrideFunctionAddress,void ** originalFunctionReentryIsland)210 __asan_mach_override_ptr(
211 void *originalFunctionAddress,
212 const void *overrideFunctionAddress,
213 void **originalFunctionReentryIsland )
214 {
215 return __asan_mach_override_ptr_custom(originalFunctionAddress,
216 overrideFunctionAddress,
217 originalFunctionReentryIsland,
218 defaultIslandMalloc,
219 defaultIslandFree);
220 }
221
222 mach_error_t
__asan_mach_override_ptr_custom(void * originalFunctionAddress,const void * overrideFunctionAddress,void ** originalFunctionReentryIsland,island_malloc * alloc,island_free * dealloc)223 __asan_mach_override_ptr_custom(
224 void *originalFunctionAddress,
225 const void *overrideFunctionAddress,
226 void **originalFunctionReentryIsland,
227 island_malloc *alloc,
228 island_free *dealloc)
229 {
230 assert( originalFunctionAddress );
231 assert( overrideFunctionAddress );
232
233 // this addresses overriding such functions as AudioOutputUnitStart()
234 // test with modified DefaultOutputUnit project
235 #if defined(__x86_64__)
236 for(;;){
237 if(*(uint16_t*)originalFunctionAddress==0x25FF) // jmp qword near [rip+0x????????]
238 originalFunctionAddress=*(void**)((char*)originalFunctionAddress+6+*(int32_t *)((uint16_t*)originalFunctionAddress+1));
239 else break;
240 }
241 #elif defined(__i386__)
242 for(;;){
243 if(*(uint16_t*)originalFunctionAddress==0x25FF) // jmp *0x????????
244 originalFunctionAddress=**(void***)((uint16_t*)originalFunctionAddress+1);
245 else break;
246 }
247 #endif
248 #ifdef DEBUG_DISASM
249 {
250 fprintf(stderr, "Replacing function at %p\n", originalFunctionAddress);
251 fprintf(stderr, "First 16 bytes of the function: ");
252 unsigned char *orig = (unsigned char *)originalFunctionAddress;
253 int i;
254 for (i = 0; i < 16; i++) {
255 fprintf(stderr, "%x ", (unsigned int) orig[i]);
256 }
257 fprintf(stderr, "\n");
258 fprintf(stderr,
259 "To disassemble, save the following function as disas.c"
260 " and run:\n gcc -c disas.c && gobjdump -d disas.o\n"
261 "The first 16 bytes of the original function will start"
262 " after four nop instructions.\n");
263 fprintf(stderr, "\nvoid foo() {\n asm volatile(\"nop;nop;nop;nop;\");\n");
264 int j = 0;
265 for (j = 0; j < 2; j++) {
266 fprintf(stderr, " asm volatile(\".byte ");
267 for (i = 8 * j; i < 8 * (j+1) - 1; i++) {
268 fprintf(stderr, "0x%x, ", (unsigned int) orig[i]);
269 }
270 fprintf(stderr, "0x%x;\");\n", (unsigned int) orig[8 * (j+1) - 1]);
271 }
272 fprintf(stderr, "}\n\n");
273 }
274 #endif
275
276 long *originalFunctionPtr = (long*) originalFunctionAddress;
277 mach_error_t err = err_none;
278
279 #if defined(__ppc__) || defined(__POWERPC__)
280 // Ensure first instruction isn't 'mfctr'.
281 #define kMFCTRMask 0xfc1fffff
282 #define kMFCTRInstruction 0x7c0903a6
283
284 long originalInstruction = *originalFunctionPtr;
285 if( !err && ((originalInstruction & kMFCTRMask) == kMFCTRInstruction) )
286 err = err_cannot_override;
287 #elif defined(__i386__) || defined(__x86_64__)
288 int eatenCount = 0;
289 int originalInstructionCount = 0;
290 char originalInstructions[kOriginalInstructionsSize];
291 uint8_t originalInstructionSizes[kOriginalInstructionsSize];
292 uint64_t jumpRelativeInstruction = 0; // JMP
293
294 Boolean overridePossible = eatKnownInstructions ((unsigned char *)originalFunctionPtr,
295 &jumpRelativeInstruction, &eatenCount,
296 originalInstructions, &originalInstructionCount,
297 originalInstructionSizes );
298 #ifdef DEBUG_DISASM
299 if (!overridePossible) fprintf(stderr, "overridePossible = false @%d\n", __LINE__);
300 #endif
301 if (eatenCount > kOriginalInstructionsSize) {
302 #ifdef DEBUG_DISASM
303 fprintf(stderr, "Too many instructions eaten\n");
304 #endif
305 overridePossible = false;
306 }
307 if (!overridePossible) err = err_cannot_override;
308 if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__);
309 #endif
310
311 // Make the original function implementation writable.
312 if( !err ) {
313 err = vm_protect( mach_task_self(),
314 (vm_address_t) originalFunctionPtr, 8, false,
315 (VM_PROT_ALL | VM_PROT_COPY) );
316 if( err )
317 err = vm_protect( mach_task_self(),
318 (vm_address_t) originalFunctionPtr, 8, false,
319 (VM_PROT_DEFAULT | VM_PROT_COPY) );
320 }
321 if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__);
322
323 // Allocate and target the escape island to the overriding function.
324 BranchIsland *escapeIsland = NULL;
325 if( !err )
326 err = alloc( (void**)&escapeIsland, sizeof(BranchIsland), originalFunctionAddress );
327 if ( err ) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__);
328
329 #if defined(__ppc__) || defined(__POWERPC__)
330 if( !err )
331 err = setBranchIslandTarget( escapeIsland, overrideFunctionAddress, 0 );
332
333 // Build the branch absolute instruction to the escape island.
334 long branchAbsoluteInstruction = 0; // Set to 0 just to silence warning.
335 if( !err ) {
336 long escapeIslandAddress = ((long) escapeIsland) & 0x3FFFFFF;
337 branchAbsoluteInstruction = 0x48000002 | escapeIslandAddress;
338 }
339 #elif defined(__i386__) || defined(__x86_64__)
340 if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__);
341
342 if( !err )
343 err = setBranchIslandTarget_i386( escapeIsland, overrideFunctionAddress, 0 );
344
345 if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__);
346 // Build the jump relative instruction to the escape island
347 #endif
348
349
350 #if defined(__i386__) || defined(__x86_64__)
351 if (!err) {
352 uint32_t addressOffset = ((char*)escapeIsland - (char*)originalFunctionPtr - 5);
353 addressOffset = OSSwapInt32(addressOffset);
354
355 jumpRelativeInstruction |= 0xE900000000000000LL;
356 jumpRelativeInstruction |= ((uint64_t)addressOffset & 0xffffffff) << 24;
357 jumpRelativeInstruction = OSSwapInt64(jumpRelativeInstruction);
358 }
359 #endif
360
361 // Optionally allocate & return the reentry island. This may contain relocated
362 // jmp instructions and so has all the same addressing reachability requirements
363 // the escape island has to the original function, except the escape island is
364 // technically our original function.
365 BranchIsland *reentryIsland = NULL;
366 if( !err && originalFunctionReentryIsland ) {
367 err = alloc( (void**)&reentryIsland, sizeof(BranchIsland), escapeIsland);
368 if( !err )
369 *originalFunctionReentryIsland = reentryIsland;
370 }
371
372 #if defined(__ppc__) || defined(__POWERPC__)
373 // Atomically:
374 // o If the reentry island was allocated:
375 // o Insert the original instruction into the reentry island.
376 // o Target the reentry island at the 2nd instruction of the
377 // original function.
378 // o Replace the original instruction with the branch absolute.
379 if( !err ) {
380 int escapeIslandEngaged = false;
381 do {
382 if( reentryIsland )
383 err = setBranchIslandTarget( reentryIsland,
384 (void*) (originalFunctionPtr+1), originalInstruction );
385 if( !err ) {
386 escapeIslandEngaged = CompareAndSwap( originalInstruction,
387 branchAbsoluteInstruction,
388 (UInt32*)originalFunctionPtr );
389 if( !escapeIslandEngaged ) {
390 // Someone replaced the instruction out from under us,
391 // re-read the instruction, make sure it's still not
392 // 'mfctr' and try again.
393 originalInstruction = *originalFunctionPtr;
394 if( (originalInstruction & kMFCTRMask) == kMFCTRInstruction)
395 err = err_cannot_override;
396 }
397 }
398 } while( !err && !escapeIslandEngaged );
399 }
400 #elif defined(__i386__) || defined(__x86_64__)
401 // Atomically:
402 // o If the reentry island was allocated:
403 // o Insert the original instructions into the reentry island.
404 // o Target the reentry island at the first non-replaced
405 // instruction of the original function.
406 // o Replace the original first instructions with the jump relative.
407 //
408 // Note that on i386, we do not support someone else changing the code under our feet
409 if ( !err ) {
410 fixupInstructions(originalFunctionPtr, reentryIsland, originalInstructions,
411 originalInstructionCount, originalInstructionSizes );
412
413 if( reentryIsland )
414 err = setBranchIslandTarget_i386( reentryIsland,
415 (void*) ((char *)originalFunctionPtr+eatenCount), originalInstructions );
416 // try making islands executable before planting the jmp
417 #if defined(__x86_64__) || defined(__i386__)
418 if( !err )
419 err = makeIslandExecutable(escapeIsland);
420 if( !err && reentryIsland )
421 err = makeIslandExecutable(reentryIsland);
422 #endif
423 if ( !err )
424 atomic_mov64((uint64_t *)originalFunctionPtr, jumpRelativeInstruction);
425 }
426 #endif
427
428 // Clean up on error.
429 if( err ) {
430 if( reentryIsland )
431 dealloc( reentryIsland );
432 if( escapeIsland )
433 dealloc( escapeIsland );
434 }
435
436 #ifdef DEBUG_DISASM
437 {
438 fprintf(stderr, "First 16 bytes of the function after slicing: ");
439 unsigned char *orig = (unsigned char *)originalFunctionAddress;
440 int i;
441 for (i = 0; i < 16; i++) {
442 fprintf(stderr, "%x ", (unsigned int) orig[i]);
443 }
444 fprintf(stderr, "\n");
445 }
446 #endif
447 return err;
448 }
449
450 /*******************************************************************************
451 *
452 * Implementation
453 *
454 *******************************************************************************/
455 #pragma mark -
456 #pragma mark (Implementation)
457
458 /***************************************************************************//**
459 Implementation: Allocates memory for a branch island.
460
461 @param island <- The allocated island.
462 @param allocateHigh -> Whether to allocate the island at the end of the
463 address space (for use with the branch absolute
464 instruction).
465 @result <- mach_error_t
466
467 ***************************************************************************/
468
469 static mach_error_t
allocateBranchIsland(BranchIsland ** island,int allocateHigh,void * originalFunctionAddress)470 allocateBranchIsland(
471 BranchIsland **island,
472 int allocateHigh,
473 void *originalFunctionAddress)
474 {
475 assert( island );
476
477 mach_error_t err = err_none;
478
479 if( allocateHigh ) {
480 vm_size_t pageSize;
481 err = host_page_size( mach_host_self(), &pageSize );
482 if( !err ) {
483 assert( sizeof( BranchIsland ) <= pageSize );
484 #if defined(__ppc__) || defined(__POWERPC__)
485 vm_address_t first = 0xfeffffff;
486 vm_address_t last = 0xfe000000 + pageSize;
487 #elif defined(__x86_64__)
488 vm_address_t first = ((uint64_t)originalFunctionAddress & ~(uint64_t)(((uint64_t)1 << 31) - 1)) | ((uint64_t)1 << 31); // start in the middle of the page?
489 vm_address_t last = 0x0;
490 #else
491 vm_address_t first = 0xffc00000;
492 vm_address_t last = 0xfffe0000;
493 #endif
494
495 vm_address_t page = first;
496 int allocated = 0;
497 vm_map_t task_self = mach_task_self();
498
499 while( !err && !allocated && page != last ) {
500
501 err = vm_allocate( task_self, &page, pageSize, 0 );
502 if( err == err_none )
503 allocated = 1;
504 else if( err == KERN_NO_SPACE ) {
505 #if defined(__x86_64__)
506 page -= pageSize;
507 #else
508 page += pageSize;
509 #endif
510 err = err_none;
511 }
512 }
513 if( allocated )
514 *island = (BranchIsland*) page;
515 else if( !allocated && !err )
516 err = KERN_NO_SPACE;
517 }
518 } else {
519 void *block = malloc( sizeof( BranchIsland ) );
520 if( block )
521 *island = block;
522 else
523 err = KERN_NO_SPACE;
524 }
525 if( !err )
526 (**island).allocatedHigh = allocateHigh;
527
528 return err;
529 }
530
531 /***************************************************************************//**
532 Implementation: Deallocates memory for a branch island.
533
534 @param island -> The island to deallocate.
535 @result <- mach_error_t
536
537 ***************************************************************************/
538
539 static mach_error_t
freeBranchIsland(BranchIsland * island)540 freeBranchIsland(
541 BranchIsland *island )
542 {
543 assert( island );
544 assert( (*(long*)&island->instructions[0]) == kIslandTemplate[0] );
545 assert( island->allocatedHigh );
546
547 mach_error_t err = err_none;
548
549 if( island->allocatedHigh ) {
550 vm_size_t pageSize;
551 err = host_page_size( mach_host_self(), &pageSize );
552 if( !err ) {
553 assert( sizeof( BranchIsland ) <= pageSize );
554 err = vm_deallocate(
555 mach_task_self(),
556 (vm_address_t) island, pageSize );
557 }
558 } else {
559 free( island );
560 }
561
562 return err;
563 }
564
565 /***************************************************************************//**
566 Implementation: Sets the branch island's target, with an optional
567 instruction.
568
569 @param island -> The branch island to insert target into.
570 @param branchTo -> The address of the target.
571 @param instruction -> Optional instruction to execute prior to branch. Set
572 to zero for nop.
573 @result <- mach_error_t
574
575 ***************************************************************************/
576 #if defined(__ppc__) || defined(__POWERPC__)
577 static mach_error_t
setBranchIslandTarget(BranchIsland * island,const void * branchTo,long instruction)578 setBranchIslandTarget(
579 BranchIsland *island,
580 const void *branchTo,
581 long instruction )
582 {
583 // Copy over the template code.
584 bcopy( kIslandTemplate, island->instructions, sizeof( kIslandTemplate ) );
585
586 // Fill in the address.
587 ((short*)island->instructions)[kAddressLo] = ((long) branchTo) & 0x0000FFFF;
588 ((short*)island->instructions)[kAddressHi]
589 = (((long) branchTo) >> 16) & 0x0000FFFF;
590
591 // Fill in the (optional) instuction.
592 if( instruction != 0 ) {
593 ((short*)island->instructions)[kInstructionLo]
594 = instruction & 0x0000FFFF;
595 ((short*)island->instructions)[kInstructionHi]
596 = (instruction >> 16) & 0x0000FFFF;
597 }
598
599 //MakeDataExecutable( island->instructions, sizeof( kIslandTemplate ) );
600 msync( island->instructions, sizeof( kIslandTemplate ), MS_INVALIDATE );
601
602 return err_none;
603 }
604 #endif
605
606 #if defined(__i386__)
607 static mach_error_t
setBranchIslandTarget_i386(BranchIsland * island,const void * branchTo,char * instructions)608 setBranchIslandTarget_i386(
609 BranchIsland *island,
610 const void *branchTo,
611 char* instructions )
612 {
613
614 // Copy over the template code.
615 bcopy( kIslandTemplate, island->instructions, sizeof( kIslandTemplate ) );
616
617 // copy original instructions
618 if (instructions) {
619 bcopy (instructions, island->instructions + kInstructions, kOriginalInstructionsSize);
620 }
621
622 // Fill in the address.
623 int32_t addressOffset = (char *)branchTo - (island->instructions + kJumpAddress + 4);
624 *((int32_t *)(island->instructions + kJumpAddress)) = addressOffset;
625
626 msync( island->instructions, sizeof( kIslandTemplate ), MS_INVALIDATE );
627 return err_none;
628 }
629
630 #elif defined(__x86_64__)
631 static mach_error_t
setBranchIslandTarget_i386(BranchIsland * island,const void * branchTo,char * instructions)632 setBranchIslandTarget_i386(
633 BranchIsland *island,
634 const void *branchTo,
635 char* instructions )
636 {
637 // Copy over the template code.
638 bcopy( kIslandTemplate, island->instructions, sizeof( kIslandTemplate ) );
639
640 // Copy original instructions.
641 if (instructions) {
642 bcopy (instructions, island->instructions, kOriginalInstructionsSize);
643 }
644
645 // Fill in the address.
646 *((uint64_t *)(island->instructions + kJumpAddress)) = (uint64_t)branchTo;
647 msync( island->instructions, sizeof( kIslandTemplate ), MS_INVALIDATE );
648
649 return err_none;
650 }
651 #endif
652
653
654 #if defined(__i386__) || defined(__x86_64__)
655 // simplistic instruction matching
656 typedef struct {
657 unsigned int length; // max 15
658 unsigned char mask[15]; // sequence of bytes in memory order
659 unsigned char constraint[15]; // sequence of bytes in memory order
660 } AsmInstructionMatch;
661
662 #if defined(__i386__)
663 static AsmInstructionMatch possibleInstructions[] = {
664 { 0x5, {0xFF, 0x00, 0x00, 0x00, 0x00}, {0xE9, 0x00, 0x00, 0x00, 0x00} }, // jmp 0x????????
665 { 0x5, {0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, {0x55, 0x89, 0xe5, 0xc9, 0xc3} }, // push %esp; mov %esp,%ebp; leave; ret
666 { 0x1, {0xFF}, {0x90} }, // nop
667 { 0x1, {0xF8}, {0x50} }, // push %reg
668 { 0x2, {0xFF, 0xFF}, {0x89, 0xE5} }, // mov %esp,%ebp
669 { 0x3, {0xFF, 0xFF, 0xFF}, {0x89, 0x1C, 0x24} }, // mov %ebx,(%esp)
670 { 0x3, {0xFF, 0xFF, 0x00}, {0x83, 0xEC, 0x00} }, // sub 0x??, %esp
671 { 0x6, {0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00}, {0x81, 0xEC, 0x00, 0x00, 0x00, 0x00} }, // sub 0x??, %esp with 32bit immediate
672 { 0x2, {0xFF, 0xFF}, {0x31, 0xC0} }, // xor %eax, %eax
673 { 0x3, {0xFF, 0x4F, 0x00}, {0x8B, 0x45, 0x00} }, // mov $imm(%ebp), %reg
674 { 0x3, {0xFF, 0x4C, 0x00}, {0x8B, 0x40, 0x00} }, // mov $imm(%eax-%edx), %reg
675 { 0x3, {0xFF, 0xCF, 0x00}, {0x8B, 0x4D, 0x00} }, // mov $imm(%rpb), %reg
676 { 0x3, {0xFF, 0x4F, 0x00}, {0x8A, 0x4D, 0x00} }, // mov $imm(%ebp), %cl
677 { 0x4, {0xFF, 0xFF, 0xFF, 0x00}, {0x8B, 0x4C, 0x24, 0x00} }, // mov $imm(%esp), %ecx
678 { 0x4, {0xFF, 0x00, 0x00, 0x00}, {0x8B, 0x00, 0x00, 0x00} }, // mov r16,r/m16 or r32,r/m32
679 { 0x5, {0xFF, 0x00, 0x00, 0x00, 0x00}, {0xB9, 0x00, 0x00, 0x00, 0x00} }, // mov $imm, %ecx
680 { 0x5, {0xFF, 0x00, 0x00, 0x00, 0x00}, {0xB8, 0x00, 0x00, 0x00, 0x00} }, // mov $imm, %eax
681 { 0x4, {0xFF, 0xFF, 0xFF, 0x00}, {0x66, 0x0F, 0xEF, 0x00} }, // pxor xmm2/128, xmm1
682 { 0x2, {0xFF, 0xFF}, {0xDB, 0xE3} }, // fninit
683 { 0x5, {0xFF, 0x00, 0x00, 0x00, 0x00}, {0xE8, 0x00, 0x00, 0x00, 0x00} }, // call $imm
684 { 0x4, {0xFF, 0xFF, 0xFF, 0x00}, {0x0F, 0xBE, 0x55, 0x00} }, // movsbl $imm(%ebp), %edx
685 { 0x0 }
686 };
687 #elif defined(__x86_64__)
688 // TODO(glider): disassembling the "0x48, 0x89" sequences is trickier than it's done below.
689 // If it stops working, refer to http://ref.x86asm.net/geek.html#modrm_byte_32_64 to do it
690 // more accurately.
691 // Note: 0x48 is in fact the REX.W prefix, but it might be wrong to treat it as a separate
692 // instruction.
693 static AsmInstructionMatch possibleInstructions[] = {
694 { 0x5, {0xFF, 0x00, 0x00, 0x00, 0x00}, {0xE9, 0x00, 0x00, 0x00, 0x00} }, // jmp 0x????????
695 { 0x1, {0xFF}, {0x90} }, // nop
696 { 0x1, {0xF8}, {0x50} }, // push %rX
697 { 0x1, {0xFF}, {0x65} }, // GS prefix
698 { 0x3, {0xFF, 0xFF, 0xFF}, {0x48, 0x89, 0xE5} }, // mov %rsp,%rbp
699 { 0x4, {0xFF, 0xFF, 0xFF, 0x00}, {0x48, 0x83, 0xEC, 0x00} }, // sub 0x??, %rsp
700 { 0x4, {0xFB, 0xFF, 0x07, 0x00}, {0x48, 0x89, 0x05, 0x00} }, // move onto rbp
701 { 0x3, {0xFB, 0xFF, 0x00}, {0x48, 0x89, 0x00} }, // mov %reg, %reg
702 { 0x3, {0xFB, 0xFF, 0x00}, {0x49, 0x89, 0x00} }, // mov %reg, %reg (REX.WB)
703 { 0x2, {0xFF, 0x00}, {0x41, 0x00} }, // push %rXX
704 { 0x2, {0xFF, 0x00}, {0x84, 0x00} }, // test %rX8,%rX8
705 { 0x2, {0xFF, 0x00}, {0x85, 0x00} }, // test %rX,%rX
706 { 0x2, {0xFF, 0x00}, {0x77, 0x00} }, // ja $i8
707 { 0x2, {0xFF, 0x00}, {0x74, 0x00} }, // je $i8
708 { 0x5, {0xF8, 0x00, 0x00, 0x00, 0x00}, {0xB8, 0x00, 0x00, 0x00, 0x00} }, // mov $imm, %reg
709 { 0x3, {0xFF, 0xFF, 0x00}, {0xFF, 0x77, 0x00} }, // pushq $imm(%rdi)
710 { 0x2, {0xFF, 0xFF}, {0x31, 0xC0} }, // xor %eax, %eax
711 { 0x5, {0xFF, 0x00, 0x00, 0x00, 0x00}, {0x25, 0x00, 0x00, 0x00, 0x00} }, // and $imm, %eax
712 { 0x3, {0xFF, 0xFF, 0xFF}, {0x80, 0x3F, 0x00} }, // cmpb $imm, (%rdi)
713
714 { 0x8, {0xFF, 0xFF, 0xCF, 0xFF, 0x00, 0x00, 0x00, 0x00},
715 {0x48, 0x8B, 0x04, 0x25, 0x00, 0x00, 0x00, 0x00}, }, // mov $imm, %{rax,rdx,rsp,rsi}
716 { 0x4, {0xFF, 0xFF, 0xFF, 0x00}, {0x48, 0x83, 0xFA, 0x00}, }, // cmp $i8, %rdx
717 { 0x4, {0xFF, 0xFF, 0x00, 0x00}, {0x83, 0x7f, 0x00, 0x00}, }, // cmpl $imm, $imm(%rdi)
718 { 0xa, {0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
719 {0x48, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }, // mov $imm, %rax
720 { 0x6, {0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00},
721 {0x81, 0xE6, 0x00, 0x00, 0x00, 0x00} }, // and $imm, %esi
722 { 0x6, {0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00},
723 {0xFF, 0x25, 0x00, 0x00, 0x00, 0x00} }, // jmpq *(%rip)
724 { 0x4, {0xFF, 0xFF, 0xFF, 0x00}, {0x66, 0x0F, 0xEF, 0x00} }, // pxor xmm2/128, xmm1
725 { 0x2, {0xFF, 0x00}, {0x89, 0x00} }, // mov r/m32,r32 or r/m16,r16
726 { 0x3, {0xFF, 0xFF, 0xFF}, {0x49, 0x89, 0xF8} }, // mov %rdi,%r8
727 { 0x4, {0xFF, 0xFF, 0xFF, 0xFF}, {0x40, 0x0F, 0xBE, 0xCE} }, // movsbl %sil,%ecx
728 { 0x3, {0xFF, 0xFF, 0xFF}, {0x0F, 0xBE, 0xCE} }, // movsbl, %dh, %ecx
729 { 0x3, {0xFF, 0xFF, 0x00}, {0xFF, 0x77, 0x00} }, // pushq $imm(%rdi)
730 { 0x2, {0xFF, 0xFF}, {0xDB, 0xE3} }, // fninit
731 { 0x3, {0xFF, 0xFF, 0xFF}, {0x48, 0x85, 0xD2} }, // test %rdx,%rdx
732 { 0x0 }
733 };
734 #endif
735
codeMatchesInstruction(unsigned char * code,AsmInstructionMatch * instruction)736 static Boolean codeMatchesInstruction(unsigned char *code, AsmInstructionMatch* instruction)
737 {
738 Boolean match = true;
739
740 size_t i;
741 assert(instruction);
742 #ifdef DEBUG_DISASM
743 fprintf(stderr, "Matching: ");
744 #endif
745 for (i=0; i<instruction->length; i++) {
746 unsigned char mask = instruction->mask[i];
747 unsigned char constraint = instruction->constraint[i];
748 unsigned char codeValue = code[i];
749 #ifdef DEBUG_DISASM
750 fprintf(stderr, "%x ", (unsigned)codeValue);
751 #endif
752 match = ((codeValue & mask) == constraint);
753 if (!match) break;
754 }
755 #ifdef DEBUG_DISASM
756 if (match) {
757 fprintf(stderr, " OK\n");
758 } else {
759 fprintf(stderr, " FAIL\n");
760 }
761 #endif
762 return match;
763 }
764
765 #if defined(__i386__) || defined(__x86_64__)
766 static Boolean
eatKnownInstructions(unsigned char * code,uint64_t * newInstruction,int * howManyEaten,char * originalInstructions,int * originalInstructionCount,uint8_t * originalInstructionSizes)767 eatKnownInstructions(
768 unsigned char *code,
769 uint64_t *newInstruction,
770 int *howManyEaten,
771 char *originalInstructions,
772 int *originalInstructionCount,
773 uint8_t *originalInstructionSizes )
774 {
775 Boolean allInstructionsKnown = true;
776 int totalEaten = 0;
777 unsigned char* ptr = code;
778 int remainsToEat = 5; // a JMP instruction takes 5 bytes
779 int instructionIndex = 0;
780
781 if (howManyEaten) *howManyEaten = 0;
782 if (originalInstructionCount) *originalInstructionCount = 0;
783 while (remainsToEat > 0) {
784 Boolean curInstructionKnown = false;
785
786 // See if instruction matches one we know
787 AsmInstructionMatch* curInstr = possibleInstructions;
788 do {
789 if ((curInstructionKnown = codeMatchesInstruction(ptr, curInstr))) break;
790 curInstr++;
791 } while (curInstr->length > 0);
792
793 // if all instruction matches failed, we don't know current instruction then, stop here
794 if (!curInstructionKnown) {
795 allInstructionsKnown = false;
796 fprintf(stderr, "mach_override: some instructions unknown! Need to update mach_override.c\n");
797 break;
798 }
799
800 // At this point, we've matched curInstr
801 int eaten = curInstr->length;
802 ptr += eaten;
803 remainsToEat -= eaten;
804 totalEaten += eaten;
805
806 if (originalInstructionSizes) originalInstructionSizes[instructionIndex] = eaten;
807 instructionIndex += 1;
808 if (originalInstructionCount) *originalInstructionCount = instructionIndex;
809 }
810
811
812 if (howManyEaten) *howManyEaten = totalEaten;
813
814 if (originalInstructions) {
815 Boolean enoughSpaceForOriginalInstructions = (totalEaten < kOriginalInstructionsSize);
816
817 if (enoughSpaceForOriginalInstructions) {
818 memset(originalInstructions, 0x90 /* NOP */, kOriginalInstructionsSize); // fill instructions with NOP
819 bcopy(code, originalInstructions, totalEaten);
820 } else {
821 #ifdef DEBUG_DISASM
822 fprintf(stderr, "Not enough space in island to store original instructions. Adapt the island definition and kOriginalInstructionsSize\n");
823 #endif
824 return false;
825 }
826 }
827
828 if (allInstructionsKnown) {
829 // save last 3 bytes of first 64bits of codre we'll replace
830 uint64_t currentFirst64BitsOfCode = *((uint64_t *)code);
831 currentFirst64BitsOfCode = OSSwapInt64(currentFirst64BitsOfCode); // back to memory representation
832 currentFirst64BitsOfCode &= 0x0000000000FFFFFFLL;
833
834 // keep only last 3 instructions bytes, first 5 will be replaced by JMP instr
835 *newInstruction &= 0xFFFFFFFFFF000000LL; // clear last 3 bytes
836 *newInstruction |= (currentFirst64BitsOfCode & 0x0000000000FFFFFFLL); // set last 3 bytes
837 }
838
839 return allInstructionsKnown;
840 }
841
842 static void
fixupInstructions(void * originalFunction,void * escapeIsland,void * instructionsToFix,int instructionCount,uint8_t * instructionSizes)843 fixupInstructions(
844 void *originalFunction,
845 void *escapeIsland,
846 void *instructionsToFix,
847 int instructionCount,
848 uint8_t *instructionSizes )
849 {
850 void *initialOriginalFunction = originalFunction;
851 int index, fixed_size, code_size = 0;
852 for (index = 0;index < instructionCount;index += 1)
853 code_size += instructionSizes[index];
854
855 #ifdef DEBUG_DISASM
856 void *initialInstructionsToFix = instructionsToFix;
857 fprintf(stderr, "BEFORE FIXING:\n");
858 dump16Bytes(initialOriginalFunction);
859 dump16Bytes(initialInstructionsToFix);
860 #endif // DEBUG_DISASM
861
862 for (index = 0;index < instructionCount;index += 1)
863 {
864 fixed_size = instructionSizes[index];
865 if ((*(uint8_t*)instructionsToFix == 0xE9) || // 32-bit jump relative
866 (*(uint8_t*)instructionsToFix == 0xE8)) // 32-bit call relative
867 {
868 uint32_t offset = (uintptr_t)originalFunction - (uintptr_t)escapeIsland;
869 uint32_t *jumpOffsetPtr = (uint32_t*)((uintptr_t)instructionsToFix + 1);
870 *jumpOffsetPtr += offset;
871 }
872 if ((*(uint8_t*)instructionsToFix == 0x74) || // Near jump if equal (je), 2 bytes.
873 (*(uint8_t*)instructionsToFix == 0x77)) // Near jump if above (ja), 2 bytes.
874 {
875 // We replace a near je/ja instruction, "7P JJ", with a 32-bit je/ja, "0F 8P WW XX YY ZZ".
876 // This is critical, otherwise a near jump will likely fall outside the original function.
877 uint32_t offset = (uintptr_t)initialOriginalFunction - (uintptr_t)escapeIsland;
878 uint32_t jumpOffset = *(uint8_t*)((uintptr_t)instructionsToFix + 1);
879 *(uint8_t*)(instructionsToFix + 1) = *(uint8_t*)instructionsToFix + 0x10;
880 *(uint8_t*)instructionsToFix = 0x0F;
881 uint32_t *jumpOffsetPtr = (uint32_t*)((uintptr_t)instructionsToFix + 2 );
882 *jumpOffsetPtr = offset + jumpOffset;
883 fixed_size = 6;
884 }
885
886 originalFunction = (void*)((uintptr_t)originalFunction + instructionSizes[index]);
887 escapeIsland = (void*)((uintptr_t)escapeIsland + instructionSizes[index]);
888 instructionsToFix = (void*)((uintptr_t)instructionsToFix + fixed_size);
889
890 // Expanding short instructions into longer ones may overwrite the next instructions,
891 // so we must restore them.
892 code_size -= fixed_size;
893 if ((code_size > 0) && (fixed_size != instructionSizes[index])) {
894 bcopy(originalFunction, instructionsToFix, code_size);
895 }
896 }
897 #ifdef DEBUG_DISASM
898 fprintf(stderr, "AFTER_FIXING:\n");
899 dump16Bytes(initialOriginalFunction);
900 dump16Bytes(initialInstructionsToFix);
901 #endif // DEBUG_DISASM
902 }
903
904 #ifdef DEBUG_DISASM
905 #define HEX_DIGIT(x) ((((x) % 16) < 10) ? ('0' + ((x) % 16)) : ('A' + ((x) % 16 - 10)))
906
907 static void
dump16Bytes(void * ptr)908 dump16Bytes(
909 void *ptr) {
910 int i;
911 char buf[3];
912 uint8_t *bytes = (uint8_t*)ptr;
913 for (i = 0; i < 16; i++) {
914 buf[0] = HEX_DIGIT(bytes[i] / 16);
915 buf[1] = HEX_DIGIT(bytes[i] % 16);
916 buf[2] = ' ';
917 write(2, buf, 3);
918 }
919 write(2, "\n", 1);
920 }
921 #endif // DEBUG_DISASM
922 #endif
923
924 #if defined(__i386__)
925 __asm(
926 ".text;"
927 ".align 2, 0x90;"
928 "_atomic_mov64:;"
929 " pushl %ebp;"
930 " movl %esp, %ebp;"
931 " pushl %esi;"
932 " pushl %ebx;"
933 " pushl %ecx;"
934 " pushl %eax;"
935 " pushl %edx;"
936
937 // atomic push of value to an address
938 // we use cmpxchg8b, which compares content of an address with
939 // edx:eax. If they are equal, it atomically puts 64bit value
940 // ecx:ebx in address.
941 // We thus put contents of address in edx:eax to force ecx:ebx
942 // in address
943 " mov 8(%ebp), %esi;" // esi contains target address
944 " mov 12(%ebp), %ebx;"
945 " mov 16(%ebp), %ecx;" // ecx:ebx now contains value to put in target address
946 " mov (%esi), %eax;"
947 " mov 4(%esi), %edx;" // edx:eax now contains value currently contained in target address
948 " lock; cmpxchg8b (%esi);" // atomic move.
949
950 // restore registers
951 " popl %edx;"
952 " popl %eax;"
953 " popl %ecx;"
954 " popl %ebx;"
955 " popl %esi;"
956 " popl %ebp;"
957 " ret"
958 );
959 #elif defined(__x86_64__)
atomic_mov64(uint64_t * targetAddress,uint64_t value)960 void atomic_mov64(
961 uint64_t *targetAddress,
962 uint64_t value )
963 {
964 *targetAddress = value;
965 }
966 #endif
967 #endif
968 #endif // __APPLE__
969