1 // Copied from upstream at revision 195c13743fe0ebc658714e2a9567d86529f20443.
2 // mach_override.c semver:1.2.0
3 // Copyright (c) 2003-2012 Jonathan 'Wolf' Rentzsch: http://rentzsch.com
4 // Some rights reserved: http://opensource.org/licenses/mit
5 // https://github.com/rentzsch/mach_override
6
7 #include "mach_override.h"
8
9 #include <mach-o/dyld.h>
10 #include <mach/mach_host.h>
11 #include <mach/mach_init.h>
12 #include <mach/vm_map.h>
13 #include <sys/mman.h>
14
15 #include <CoreServices/CoreServices.h>
16
17 /**************************
18 *
19 * Constants
20 *
21 **************************/
22 #pragma mark -
23 #pragma mark (Constants)
24
25 #define kPageSize 4096
26 #if defined(__ppc__) || defined(__POWERPC__)
27
28 long kIslandTemplate[] = {
29 0x9001FFFC, // stw r0,-4(SP)
30 0x3C00DEAD, // lis r0,0xDEAD
31 0x6000BEEF, // ori r0,r0,0xBEEF
32 0x7C0903A6, // mtctr r0
33 0x8001FFFC, // lwz r0,-4(SP)
34 0x60000000, // nop ; optionally replaced
35 0x4E800420 // bctr
36 };
37
38 #define kAddressHi 3
39 #define kAddressLo 5
40 #define kInstructionHi 10
41 #define kInstructionLo 11
42
43 #elif defined(__i386__)
44
45 #define kOriginalInstructionsSize 16
46 // On X86 we migh need to instert an add with a 32 bit immediate after the
47 // original instructions.
48 #define kMaxFixupSizeIncrease 5
49
50 unsigned char kIslandTemplate[] = {
51 // kOriginalInstructionsSize nop instructions so that we
52 // should have enough space to host original instructions
53 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
54 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
55 // Now the real jump instruction
56 0xE9, 0xEF, 0xBE, 0xAD, 0xDE
57 };
58
59 #define kInstructions 0
60 #define kJumpAddress kInstructions + kOriginalInstructionsSize + 1
61 #elif defined(__x86_64__)
62
63 #define kOriginalInstructionsSize 32
64 // On X86-64 we never need to instert a new instruction.
65 #define kMaxFixupSizeIncrease 0
66
67 #define kJumpAddress kOriginalInstructionsSize + 6
68
69 unsigned char kIslandTemplate[] = {
70 // kOriginalInstructionsSize nop instructions so that we
71 // should have enough space to host original instructions
72 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
73 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
74 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
75 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
76 // Now the real jump instruction
77 0xFF, 0x25, 0x00, 0x00, 0x00, 0x00,
78 0x00, 0x00, 0x00, 0x00,
79 0x00, 0x00, 0x00, 0x00
80 };
81
82 #endif
83
84 /**************************
85 *
86 * Data Types
87 *
88 **************************/
89 #pragma mark -
90 #pragma mark (Data Types)
91
92 typedef struct {
93 char instructions[sizeof(kIslandTemplate)];
94 } BranchIsland;
95
96 /**************************
97 *
98 * Funky Protos
99 *
100 **************************/
101 #pragma mark -
102 #pragma mark (Funky Protos)
103
104 static mach_error_t
105 allocateBranchIsland(
106 BranchIsland **island,
107 void *originalFunctionAddress);
108
109 mach_error_t
110 freeBranchIsland(
111 BranchIsland *island );
112
113 #if defined(__ppc__) || defined(__POWERPC__)
114 mach_error_t
115 setBranchIslandTarget(
116 BranchIsland *island,
117 const void *branchTo,
118 long instruction );
119 #endif
120
121 #if defined(__i386__) || defined(__x86_64__)
122 mach_error_t
123 setBranchIslandTarget_i386(
124 BranchIsland *island,
125 const void *branchTo,
126 char* instructions );
127 void
128 atomic_mov64(
129 uint64_t *targetAddress,
130 uint64_t value );
131
132 static Boolean
133 eatKnownInstructions(
134 unsigned char *code,
135 uint64_t *newInstruction,
136 int *howManyEaten,
137 char *originalInstructions,
138 int *originalInstructionCount,
139 uint8_t *originalInstructionSizes );
140
141 static void
142 fixupInstructions(
143 uint32_t offset,
144 void *instructionsToFix,
145 int instructionCount,
146 uint8_t *instructionSizes );
147 #endif
148
149 /*******************************************************************************
150 *
151 * Interface
152 *
153 *******************************************************************************/
154 #pragma mark -
155 #pragma mark (Interface)
156
157 #if defined(__i386__) || defined(__x86_64__)
makeIslandExecutable(void * address)158 mach_error_t makeIslandExecutable(void *address) {
159 mach_error_t err = err_none;
160 uintptr_t page = (uintptr_t)address & ~(uintptr_t)(kPageSize-1);
161 int e = err_none;
162 e |= mprotect((void *)page, kPageSize, PROT_EXEC | PROT_READ | PROT_WRITE);
163 e |= msync((void *)page, kPageSize, MS_INVALIDATE );
164 if (e) {
165 err = err_cannot_override;
166 }
167 return err;
168 }
169 #endif
170
171 mach_error_t
mach_override_ptr(void * originalFunctionAddress,const void * overrideFunctionAddress,void ** originalFunctionReentryIsland)172 mach_override_ptr(
173 void *originalFunctionAddress,
174 const void *overrideFunctionAddress,
175 void **originalFunctionReentryIsland )
176 {
177 assert( originalFunctionAddress );
178 assert( overrideFunctionAddress );
179
180 // this addresses overriding such functions as AudioOutputUnitStart()
181 // test with modified DefaultOutputUnit project
182 #if defined(__x86_64__)
183 for(;;){
184 if(*(uint16_t*)originalFunctionAddress==0x25FF) // jmp qword near [rip+0x????????]
185 originalFunctionAddress=*(void**)((char*)originalFunctionAddress+6+*(int32_t *)((uint16_t*)originalFunctionAddress+1));
186 else break;
187 }
188 #elif defined(__i386__)
189 for(;;){
190 if(*(uint16_t*)originalFunctionAddress==0x25FF) // jmp *0x????????
191 originalFunctionAddress=**(void***)((uint16_t*)originalFunctionAddress+1);
192 else break;
193 }
194 #endif
195
196 long *originalFunctionPtr = (long*) originalFunctionAddress;
197 mach_error_t err = err_none;
198
199 #if defined(__ppc__) || defined(__POWERPC__)
200 // Ensure first instruction isn't 'mfctr'.
201 #define kMFCTRMask 0xfc1fffff
202 #define kMFCTRInstruction 0x7c0903a6
203
204 long originalInstruction = *originalFunctionPtr;
205 if( !err && ((originalInstruction & kMFCTRMask) == kMFCTRInstruction) )
206 err = err_cannot_override;
207 #elif defined(__i386__) || defined(__x86_64__)
208 int eatenCount = 0;
209 int originalInstructionCount = 0;
210 char originalInstructions[kOriginalInstructionsSize];
211 uint8_t originalInstructionSizes[kOriginalInstructionsSize];
212 uint64_t jumpRelativeInstruction = 0; // JMP
213
214 Boolean overridePossible = eatKnownInstructions ((unsigned char *)originalFunctionPtr,
215 &jumpRelativeInstruction, &eatenCount,
216 originalInstructions, &originalInstructionCount,
217 originalInstructionSizes );
218 if (eatenCount + kMaxFixupSizeIncrease > kOriginalInstructionsSize) {
219 //printf ("Too many instructions eaten\n");
220 overridePossible = false;
221 }
222 if (!overridePossible) err = err_cannot_override;
223 if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__);
224 #endif
225
226 // Make the original function implementation writable.
227 if( !err ) {
228 err = vm_protect( mach_task_self(),
229 (vm_address_t) originalFunctionPtr, 8, false,
230 (VM_PROT_ALL | VM_PROT_COPY) );
231 if( err )
232 err = vm_protect( mach_task_self(),
233 (vm_address_t) originalFunctionPtr, 8, false,
234 (VM_PROT_DEFAULT | VM_PROT_COPY) );
235 }
236 if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__);
237
238 // Allocate and target the escape island to the overriding function.
239 BranchIsland *escapeIsland = NULL;
240 if( !err ) {
241 err = allocateBranchIsland( &escapeIsland, originalFunctionAddress );
242 if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__);
243 }
244
245 #if defined(__ppc__) || defined(__POWERPC__)
246 if( !err )
247 err = setBranchIslandTarget( escapeIsland, overrideFunctionAddress, 0 );
248
249 // Build the branch absolute instruction to the escape island.
250 long branchAbsoluteInstruction = 0; // Set to 0 just to silence warning.
251 if( !err ) {
252 long escapeIslandAddress = ((long) escapeIsland) & 0x3FFFFFF;
253 branchAbsoluteInstruction = 0x48000002 | escapeIslandAddress;
254 }
255 #elif defined(__i386__) || defined(__x86_64__)
256 if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__);
257
258 if( !err )
259 err = setBranchIslandTarget_i386( escapeIsland, overrideFunctionAddress, 0 );
260
261 if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__);
262 // Build the jump relative instruction to the escape island
263 #endif
264
265
266 #if defined(__i386__) || defined(__x86_64__)
267 if (!err) {
268 uint32_t addressOffset = ((char*)escapeIsland - (char*)originalFunctionPtr - 5);
269 addressOffset = OSSwapInt32(addressOffset);
270
271 jumpRelativeInstruction |= 0xE900000000000000LL;
272 jumpRelativeInstruction |= ((uint64_t)addressOffset & 0xffffffff) << 24;
273 jumpRelativeInstruction = OSSwapInt64(jumpRelativeInstruction);
274 }
275 #endif
276
277 // Optionally allocate & return the reentry island. This may contain relocated
278 // jmp instructions and so has all the same addressing reachability requirements
279 // the escape island has to the original function, except the escape island is
280 // technically our original function.
281 BranchIsland *reentryIsland = NULL;
282 if( !err && originalFunctionReentryIsland ) {
283 err = allocateBranchIsland( &reentryIsland, escapeIsland);
284 if( !err )
285 *originalFunctionReentryIsland = reentryIsland;
286 }
287
288 #if defined(__ppc__) || defined(__POWERPC__)
289 // Atomically:
290 // o If the reentry island was allocated:
291 // o Insert the original instruction into the reentry island.
292 // o Target the reentry island at the 2nd instruction of the
293 // original function.
294 // o Replace the original instruction with the branch absolute.
295 if( !err ) {
296 int escapeIslandEngaged = false;
297 do {
298 if( reentryIsland )
299 err = setBranchIslandTarget( reentryIsland,
300 (void*) (originalFunctionPtr+1), originalInstruction );
301 if( !err ) {
302 escapeIslandEngaged = CompareAndSwap( originalInstruction,
303 branchAbsoluteInstruction,
304 (UInt32*)originalFunctionPtr );
305 if( !escapeIslandEngaged ) {
306 // Someone replaced the instruction out from under us,
307 // re-read the instruction, make sure it's still not
308 // 'mfctr' and try again.
309 originalInstruction = *originalFunctionPtr;
310 if( (originalInstruction & kMFCTRMask) == kMFCTRInstruction)
311 err = err_cannot_override;
312 }
313 }
314 } while( !err && !escapeIslandEngaged );
315 }
316 #elif defined(__i386__) || defined(__x86_64__)
317 // Atomically:
318 // o If the reentry island was allocated:
319 // o Insert the original instructions into the reentry island.
320 // o Target the reentry island at the first non-replaced
321 // instruction of the original function.
322 // o Replace the original first instructions with the jump relative.
323 //
324 // Note that on i386, we do not support someone else changing the code under our feet
325 if ( !err ) {
326 uint32_t offset = (uintptr_t)originalFunctionPtr - (uintptr_t)reentryIsland;
327 fixupInstructions(offset, originalInstructions,
328 originalInstructionCount, originalInstructionSizes );
329
330 if( reentryIsland )
331 err = setBranchIslandTarget_i386( reentryIsland,
332 (void*) ((char *)originalFunctionPtr+eatenCount), originalInstructions );
333 // try making islands executable before planting the jmp
334 #if defined(__x86_64__) || defined(__i386__)
335 if( !err )
336 err = makeIslandExecutable(escapeIsland);
337 if( !err && reentryIsland )
338 err = makeIslandExecutable(reentryIsland);
339 #endif
340 if ( !err )
341 atomic_mov64((uint64_t *)originalFunctionPtr, jumpRelativeInstruction);
342 }
343 #endif
344
345 // Clean up on error.
346 if( err ) {
347 if( reentryIsland )
348 freeBranchIsland( reentryIsland );
349 if( escapeIsland )
350 freeBranchIsland( escapeIsland );
351 }
352
353 return err;
354 }
355
356 /*******************************************************************************
357 *
358 * Implementation
359 *
360 *******************************************************************************/
361 #pragma mark -
362 #pragma mark (Implementation)
363
jump_in_range(intptr_t from,intptr_t to)364 static bool jump_in_range(intptr_t from, intptr_t to) {
365 intptr_t field_value = to - from - 5;
366 int32_t field_value_32 = field_value;
367 return field_value == field_value_32;
368 }
369
370 /*******************************************************************************
371 Implementation: Allocates memory for a branch island.
372
373 @param island <- The allocated island.
374 @result <- mach_error_t
375
376 ***************************************************************************/
377
378 static mach_error_t
allocateBranchIslandAux(BranchIsland ** island,void * originalFunctionAddress,bool forward)379 allocateBranchIslandAux(
380 BranchIsland **island,
381 void *originalFunctionAddress,
382 bool forward)
383 {
384 assert( island );
385 assert( sizeof( BranchIsland ) <= kPageSize );
386
387 vm_map_t task_self = mach_task_self();
388 vm_address_t original_address = (vm_address_t) originalFunctionAddress;
389 vm_address_t address = original_address;
390
391 for (;;) {
392 vm_size_t vmsize = 0;
393 memory_object_name_t object = 0;
394 kern_return_t kr = 0;
395 vm_region_flavor_t flavor = VM_REGION_BASIC_INFO;
396 // Find the region the address is in.
397 #if __WORDSIZE == 32
398 vm_region_basic_info_data_t info;
399 mach_msg_type_number_t info_count = VM_REGION_BASIC_INFO_COUNT;
400 kr = vm_region(task_self, &address, &vmsize, flavor,
401 (vm_region_info_t)&info, &info_count, &object);
402 #else
403 vm_region_basic_info_data_64_t info;
404 mach_msg_type_number_t info_count = VM_REGION_BASIC_INFO_COUNT_64;
405 kr = vm_region_64(task_self, &address, &vmsize, flavor,
406 (vm_region_info_t)&info, &info_count, &object);
407 #endif
408 if (kr != KERN_SUCCESS)
409 return kr;
410 assert((address & (kPageSize - 1)) == 0);
411
412 // Go to the first page before or after this region
413 vm_address_t new_address = forward ? address + vmsize : address - kPageSize;
414 #if __WORDSIZE == 64
415 if(!jump_in_range(original_address, new_address))
416 break;
417 #endif
418 address = new_address;
419
420 // Try to allocate this page.
421 kr = vm_allocate(task_self, &address, kPageSize, 0);
422 if (kr == KERN_SUCCESS) {
423 *island = (BranchIsland*) address;
424 return err_none;
425 }
426 if (kr != KERN_NO_SPACE)
427 return kr;
428 }
429
430 return KERN_NO_SPACE;
431 }
432
433 static mach_error_t
allocateBranchIsland(BranchIsland ** island,void * originalFunctionAddress)434 allocateBranchIsland(
435 BranchIsland **island,
436 void *originalFunctionAddress)
437 {
438 mach_error_t err =
439 allocateBranchIslandAux(island, originalFunctionAddress, true);
440 if (!err)
441 return err;
442 return allocateBranchIslandAux(island, originalFunctionAddress, false);
443 }
444
445
446 /*******************************************************************************
447 Implementation: Deallocates memory for a branch island.
448
449 @param island -> The island to deallocate.
450 @result <- mach_error_t
451
452 ***************************************************************************/
453
454 mach_error_t
freeBranchIsland(BranchIsland * island)455 freeBranchIsland(
456 BranchIsland *island )
457 {
458 assert( island );
459 assert( (*(long*)&island->instructions[0]) == kIslandTemplate[0] );
460 assert( sizeof( BranchIsland ) <= kPageSize );
461 return vm_deallocate( mach_task_self(), (vm_address_t) island,
462 kPageSize );
463 }
464
465 /*******************************************************************************
466 Implementation: Sets the branch island's target, with an optional
467 instruction.
468
469 @param island -> The branch island to insert target into.
470 @param branchTo -> The address of the target.
471 @param instruction -> Optional instruction to execute prior to branch. Set
472 to zero for nop.
473 @result <- mach_error_t
474
475 ***************************************************************************/
476 #if defined(__ppc__) || defined(__POWERPC__)
477 mach_error_t
setBranchIslandTarget(BranchIsland * island,const void * branchTo,long instruction)478 setBranchIslandTarget(
479 BranchIsland *island,
480 const void *branchTo,
481 long instruction )
482 {
483 // Copy over the template code.
484 bcopy( kIslandTemplate, island->instructions, sizeof( kIslandTemplate ) );
485
486 // Fill in the address.
487 ((short*)island->instructions)[kAddressLo] = ((long) branchTo) & 0x0000FFFF;
488 ((short*)island->instructions)[kAddressHi]
489 = (((long) branchTo) >> 16) & 0x0000FFFF;
490
491 // Fill in the (optional) instuction.
492 if( instruction != 0 ) {
493 ((short*)island->instructions)[kInstructionLo]
494 = instruction & 0x0000FFFF;
495 ((short*)island->instructions)[kInstructionHi]
496 = (instruction >> 16) & 0x0000FFFF;
497 }
498
499 //MakeDataExecutable( island->instructions, sizeof( kIslandTemplate ) );
500 msync( island->instructions, sizeof( kIslandTemplate ), MS_INVALIDATE );
501
502 return err_none;
503 }
504 #endif
505
506 #if defined(__i386__)
507 mach_error_t
setBranchIslandTarget_i386(BranchIsland * island,const void * branchTo,char * instructions)508 setBranchIslandTarget_i386(
509 BranchIsland *island,
510 const void *branchTo,
511 char* instructions )
512 {
513
514 // Copy over the template code.
515 bcopy( kIslandTemplate, island->instructions, sizeof( kIslandTemplate ) );
516
517 // copy original instructions
518 if (instructions) {
519 bcopy (instructions, island->instructions + kInstructions, kOriginalInstructionsSize);
520 }
521
522 // Fill in the address.
523 int32_t addressOffset = (char *)branchTo - (island->instructions + kJumpAddress + 4);
524 *((int32_t *)(island->instructions + kJumpAddress)) = addressOffset;
525
526 msync( island->instructions, sizeof( kIslandTemplate ), MS_INVALIDATE );
527 return err_none;
528 }
529
530 #elif defined(__x86_64__)
531 mach_error_t
setBranchIslandTarget_i386(BranchIsland * island,const void * branchTo,char * instructions)532 setBranchIslandTarget_i386(
533 BranchIsland *island,
534 const void *branchTo,
535 char* instructions )
536 {
537 // Copy over the template code.
538 bcopy( kIslandTemplate, island->instructions, sizeof( kIslandTemplate ) );
539
540 // Copy original instructions.
541 if (instructions) {
542 bcopy (instructions, island->instructions, kOriginalInstructionsSize);
543 }
544
545 // Fill in the address.
546 *((uint64_t *)(island->instructions + kJumpAddress)) = (uint64_t)branchTo;
547 msync( island->instructions, sizeof( kIslandTemplate ), MS_INVALIDATE );
548
549 return err_none;
550 }
551 #endif
552
553
554 #if defined(__i386__) || defined(__x86_64__)
555 // simplistic instruction matching
556 typedef struct {
557 unsigned int length; // max 15
558 unsigned char mask[15]; // sequence of bytes in memory order
559 unsigned char constraint[15]; // sequence of bytes in memory order
560 } AsmInstructionMatch;
561
562 #if defined(__i386__)
563 static AsmInstructionMatch possibleInstructions[] = {
564 // clang-format off
565 { 0x5, {0xFF, 0x00, 0x00, 0x00, 0x00}, {0xE9, 0x00, 0x00, 0x00, 0x00} }, // jmp 0x????????
566 { 0x5, {0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, {0x55, 0x89, 0xe5, 0xc9, 0xc3} }, // push %ebp; mov %esp,%ebp; leave; ret
567 { 0x1, {0xFF}, {0x90} }, // nop
568 { 0x1, {0xFF}, {0x55} }, // push %esp
569 { 0x2, {0xFF, 0xFF}, {0x89, 0xE5} }, // mov %esp,%ebp
570 { 0x1, {0xFF}, {0x53} }, // push %ebx
571 { 0x3, {0xFF, 0xFF, 0x00}, {0x83, 0xEC, 0x00} }, // sub 0x??, %esp
572 { 0x6, {0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00}, {0x81, 0xEC, 0x00, 0x00, 0x00, 0x00} }, // sub 0x??, %esp with 32bit immediate
573 { 0x1, {0xFF}, {0x57} }, // push %edi
574 { 0x1, {0xFF}, {0x56} }, // push %esi
575 { 0x2, {0xFF, 0xFF}, {0x31, 0xC0} }, // xor %eax, %eax
576 { 0x3, {0xFF, 0x4F, 0x00}, {0x8B, 0x45, 0x00} }, // mov $imm(%ebp), %reg
577 { 0x3, {0xFF, 0x4C, 0x00}, {0x8B, 0x40, 0x00} }, // mov $imm(%eax-%edx), %reg
578 { 0x4, {0xFF, 0xFF, 0xFF, 0x00}, {0x8B, 0x4C, 0x24, 0x00} }, // mov $imm(%esp), %ecx
579 { 0x5, {0xFF, 0x00, 0x00, 0x00, 0x00}, {0xB8, 0x00, 0x00, 0x00, 0x00} }, // mov $imm, %eax
580 { 0x6, {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, {0xE8, 0x00, 0x00, 0x00, 0x00, 0x58} }, // call $imm; pop %eax
581 { 0x0 }
582 // clang-format on
583 };
584 #elif defined(__x86_64__)
585 static AsmInstructionMatch possibleInstructions[] = {
586 // clang-format off
587 { 0x5, {0xFF, 0x00, 0x00, 0x00, 0x00}, {0xE9, 0x00, 0x00, 0x00, 0x00} }, // jmp 0x????????
588 { 0x1, {0xFF}, {0x90} }, // nop
589 { 0x1, {0xF8}, {0x50} }, // push %rX
590 { 0x3, {0xFF, 0xFF, 0xFF}, {0x48, 0x89, 0xE5} }, // mov %rsp,%rbp
591 { 0x4, {0xFF, 0xFF, 0xFF, 0x00}, {0x48, 0x83, 0xEC, 0x00} }, // sub 0x??, %rsp
592 { 0x4, {0xFB, 0xFF, 0x00, 0x00}, {0x48, 0x89, 0x00, 0x00} }, // move onto rbp
593 { 0x4, {0xFF, 0xFF, 0xFF, 0xFF}, {0x40, 0x0f, 0xbe, 0xce} }, // movsbl %sil, %ecx
594 { 0x2, {0xFF, 0x00}, {0x41, 0x00} }, // push %rXX
595 { 0x2, {0xFF, 0x00}, {0x85, 0x00} }, // test %rX,%rX
596 { 0x5, {0xF8, 0x00, 0x00, 0x00, 0x00}, {0xB8, 0x00, 0x00, 0x00, 0x00} }, // mov $imm, %reg
597 { 0x3, {0xFF, 0xFF, 0x00}, {0xFF, 0x77, 0x00} }, // pushq $imm(%rdi)
598 { 0x2, {0xFF, 0xFF}, {0x31, 0xC0} }, // xor %eax, %eax
599 { 0x2, {0xFF, 0xFF}, {0x89, 0xF8} }, // mov %edi, %eax
600
601 //leaq offset(%rip),%rax
602 { 0x7, {0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00}, {0x48, 0x8d, 0x05, 0x00, 0x00, 0x00, 0x00} },
603
604 { 0x0 }
605 // clang-format on
606 };
607 #endif
608
codeMatchesInstruction(unsigned char * code,AsmInstructionMatch * instruction)609 static Boolean codeMatchesInstruction(unsigned char *code, AsmInstructionMatch* instruction)
610 {
611 Boolean match = true;
612
613 size_t i;
614 for (i=0; i<instruction->length; i++) {
615 unsigned char mask = instruction->mask[i];
616 unsigned char constraint = instruction->constraint[i];
617 unsigned char codeValue = code[i];
618
619 match = ((codeValue & mask) == constraint);
620 if (!match) break;
621 }
622
623 return match;
624 }
625
626 #if defined(__i386__) || defined(__x86_64__)
627 static Boolean
eatKnownInstructions(unsigned char * code,uint64_t * newInstruction,int * howManyEaten,char * originalInstructions,int * originalInstructionCount,uint8_t * originalInstructionSizes)628 eatKnownInstructions(
629 unsigned char *code,
630 uint64_t *newInstruction,
631 int *howManyEaten,
632 char *originalInstructions,
633 int *originalInstructionCount,
634 uint8_t *originalInstructionSizes )
635 {
636 Boolean allInstructionsKnown = true;
637 int totalEaten = 0;
638 unsigned char* ptr = code;
639 int remainsToEat = 5; // a JMP instruction takes 5 bytes
640 int instructionIndex = 0;
641
642 if (howManyEaten) *howManyEaten = 0;
643 if (originalInstructionCount) *originalInstructionCount = 0;
644 while (remainsToEat > 0) {
645 Boolean curInstructionKnown = false;
646
647 // See if instruction matches one we know
648 AsmInstructionMatch* curInstr = possibleInstructions;
649 do {
650 if ((curInstructionKnown = codeMatchesInstruction(ptr, curInstr))) break;
651 curInstr++;
652 } while (curInstr->length > 0);
653
654 // if all instruction matches failed, we don't know current instruction then, stop here
655 if (!curInstructionKnown) {
656 allInstructionsKnown = false;
657 fprintf(stderr, "mach_override: some instructions unknown! Need to update mach_override.c\n");
658 break;
659 }
660
661 // At this point, we've matched curInstr
662 int eaten = curInstr->length;
663 ptr += eaten;
664 remainsToEat -= eaten;
665 totalEaten += eaten;
666
667 if (originalInstructionSizes) originalInstructionSizes[instructionIndex] = eaten;
668 instructionIndex += 1;
669 if (originalInstructionCount) *originalInstructionCount = instructionIndex;
670 }
671
672
673 if (howManyEaten) *howManyEaten = totalEaten;
674
675 if (originalInstructions) {
676 Boolean enoughSpaceForOriginalInstructions = (totalEaten < kOriginalInstructionsSize);
677
678 if (enoughSpaceForOriginalInstructions) {
679 memset(originalInstructions, 0x90 /* NOP */, kOriginalInstructionsSize); // fill instructions with NOP
680 bcopy(code, originalInstructions, totalEaten);
681 } else {
682 // printf ("Not enough space in island to store original instructions. Adapt the island definition and kOriginalInstructionsSize\n");
683 return false;
684 }
685 }
686
687 if (allInstructionsKnown) {
688 // save last 3 bytes of first 64bits of codre we'll replace
689 uint64_t currentFirst64BitsOfCode = *((uint64_t *)code);
690 currentFirst64BitsOfCode = OSSwapInt64(currentFirst64BitsOfCode); // back to memory representation
691 currentFirst64BitsOfCode &= 0x0000000000FFFFFFLL;
692
693 // keep only last 3 instructions bytes, first 5 will be replaced by JMP instr
694 *newInstruction &= 0xFFFFFFFFFF000000LL; // clear last 3 bytes
695 *newInstruction |= (currentFirst64BitsOfCode & 0x0000000000FFFFFFLL); // set last 3 bytes
696 }
697
698 return allInstructionsKnown;
699 }
700
701 static void
fixupInstructions(uint32_t offset,void * instructionsToFix,int instructionCount,uint8_t * instructionSizes)702 fixupInstructions(
703 uint32_t offset,
704 void *instructionsToFix,
705 int instructionCount,
706 uint8_t *instructionSizes )
707 {
708 // The start of "leaq offset(%rip),%rax"
709 static const uint8_t LeaqHeader[] = {0x48, 0x8d, 0x05};
710
711 int index;
712 for (index = 0;index < instructionCount;index += 1)
713 {
714 if (*(uint8_t*)instructionsToFix == 0xE9) // 32-bit jump relative
715 {
716 uint32_t *jumpOffsetPtr = (uint32_t*)((uintptr_t)instructionsToFix + 1);
717 *jumpOffsetPtr += offset;
718 }
719
720 // leaq offset(%rip),%rax
721 if (memcmp(instructionsToFix, LeaqHeader, 3) == 0) {
722 uint32_t *LeaqOffsetPtr = (uint32_t*)((uintptr_t)instructionsToFix + 3);
723 *LeaqOffsetPtr += offset;
724 }
725
726 // 32-bit call relative to the next addr; pop %eax
727 if (*(uint8_t*)instructionsToFix == 0xE8)
728 {
729 // Just this call is larger than the jump we use, so we
730 // know this is the last instruction.
731 assert(index == (instructionCount - 1));
732 assert(instructionSizes[index] == 6);
733
734 // Insert "addl $offset, %eax" in the end so that when
735 // we jump to the rest of the function %eax has the
736 // value it would have if eip had been pushed by the
737 // call in its original position.
738 uint8_t *op = instructionsToFix;
739 op += 6;
740 *op = 0x05; // addl
741 uint32_t *addImmPtr = (uint32_t*)(op + 1);
742 *addImmPtr = offset;
743 }
744
745 instructionsToFix = (void*)((uintptr_t)instructionsToFix + instructionSizes[index]);
746 }
747 }
748 #endif
749
750 #if defined(__i386__)
751 __asm(
752 ".text;"
753 ".align 2, 0x90;"
754 "_atomic_mov64:;"
755 " pushl %ebp;"
756 " movl %esp, %ebp;"
757 " pushl %esi;"
758 " pushl %ebx;"
759 " pushl %ecx;"
760 " pushl %eax;"
761 " pushl %edx;"
762
763 // atomic push of value to an address
764 // we use cmpxchg8b, which compares content of an address with
765 // edx:eax. If they are equal, it atomically puts 64bit value
766 // ecx:ebx in address.
767 // We thus put contents of address in edx:eax to force ecx:ebx
768 // in address
769 " mov 8(%ebp), %esi;" // esi contains target address
770 " mov 12(%ebp), %ebx;"
771 " mov 16(%ebp), %ecx;" // ecx:ebx now contains value to put in target address
772 " mov (%esi), %eax;"
773 " mov 4(%esi), %edx;" // edx:eax now contains value currently contained in target address
774 " lock; cmpxchg8b (%esi);" // atomic move.
775
776 // restore registers
777 " popl %edx;"
778 " popl %eax;"
779 " popl %ecx;"
780 " popl %ebx;"
781 " popl %esi;"
782 " popl %ebp;"
783 " ret"
784 );
785 #elif defined(__x86_64__)
atomic_mov64(uint64_t * targetAddress,uint64_t value)786 void atomic_mov64(
787 uint64_t *targetAddress,
788 uint64_t value )
789 {
790 *targetAddress = value;
791 }
792 #endif
793 #endif
794