Home | History | Annotate | Download | only in mach_override
      1 // mach_override.c semver:1.2.0
      2 //   Copyright (c) 2003-2012 Jonathan 'Wolf' Rentzsch: http://rentzsch.com
      3 //   Some rights reserved: http://opensource.org/licenses/mit
      4 //   https://github.com/rentzsch/mach_override
      5 
      6 #include "mach_override.h"
      7 #if defined(__i386__) || defined(__x86_64__)
      8 #include "udis86.h"
      9 #endif
     10 
     11 #include <mach-o/dyld.h>
     12 #include <mach/mach_init.h>
     13 #include <mach/vm_map.h>
     14 #include <mach/vm_statistics.h>
     15 #include <sys/mman.h>
     16 
     17 #include <CoreServices/CoreServices.h>
     18 
     19 /**************************
     20 *
     21 *	Constants
     22 *
     23 **************************/
     24 #pragma mark	-
     25 #pragma mark	(Constants)
     26 
     27 #if defined(__ppc__) || defined(__POWERPC__)
     28 
     29 long kIslandTemplate[] = {
     30 	0x9001FFFC,	//	stw		r0,-4(SP)
     31 	0x3C00DEAD,	//	lis		r0,0xDEAD
     32 	0x6000BEEF,	//	ori		r0,r0,0xBEEF
     33 	0x7C0903A6,	//	mtctr	r0
     34 	0x8001FFFC,	//	lwz		r0,-4(SP)
     35 	0x60000000,	//	nop		; optionally replaced
     36 	0x4E800420 	//	bctr
     37 };
     38 
     39 #define kAddressHi			3
     40 #define kAddressLo			5
     41 #define kInstructionHi		10
     42 #define kInstructionLo		11
     43 
     44 #elif defined(__i386__)
     45 
     46 #define kOriginalInstructionsSize 16
     47 
     48 char kIslandTemplate[] = {
     49 	// kOriginalInstructionsSize nop instructions so that we
     50 	// should have enough space to host original instructions
     51 	0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
     52 	0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
     53 	// Now the real jump instruction
     54 	0xE9, 0xEF, 0xBE, 0xAD, 0xDE
     55 };
     56 
     57 #define kInstructions	0
     58 #define kJumpAddress    kInstructions + kOriginalInstructionsSize + 1
     59 #elif defined(__x86_64__)
     60 
     61 #define kOriginalInstructionsSize 32
     62 
     63 #define kJumpAddress    kOriginalInstructionsSize + 6
     64 
     65 char kIslandTemplate[] = {
     66 	// kOriginalInstructionsSize nop instructions so that we
     67 	// should have enough space to host original instructions
     68 	0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
     69 	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,
     72 	// Now the real jump instruction
     73 	0xFF, 0x25, 0x00, 0x00, 0x00, 0x00,
     74         0x00, 0x00, 0x00, 0x00,
     75         0x00, 0x00, 0x00, 0x00
     76 };
     77 
     78 #endif
     79 
     80 #define	kAllocateHigh		1
     81 #define	kAllocateNormal		0
     82 
     83 /**************************
     84 *
     85 *	Data Types
     86 *
     87 **************************/
     88 #pragma mark	-
     89 #pragma mark	(Data Types)
     90 
     91 typedef	struct	{
     92 	char	instructions[sizeof(kIslandTemplate)];
     93 	int		allocatedHigh;
     94 }	BranchIsland;
     95 
     96 /**************************
     97 *
     98 *	Funky Protos
     99 *
    100 **************************/
    101 #pragma mark	-
    102 #pragma mark	(Funky Protos)
    103 
    104 	mach_error_t
    105 allocateBranchIsland(
    106 		BranchIsland	**island,
    107 		int				allocateHigh,
    108 		void *originalFunctionAddress);
    109 
    110 	mach_error_t
    111 freeBranchIsland(
    112 		BranchIsland	*island );
    113 
    114 #if defined(__ppc__) || defined(__POWERPC__)
    115 	mach_error_t
    116 setBranchIslandTarget(
    117 		BranchIsland	*island,
    118 		const void		*branchTo,
    119 		long			instruction );
    120 #endif
    121 
    122 #if defined(__i386__) || defined(__x86_64__)
    123 mach_error_t
    124 setBranchIslandTarget_i386(
    125 						   BranchIsland	*island,
    126 						   const void		*branchTo,
    127 						   char*			instructions );
    128 void
    129 atomic_mov64(
    130 		uint64_t *targetAddress,
    131 		uint64_t value );
    132 
    133 	static Boolean
    134 eatKnownInstructions(
    135 	unsigned char	*code,
    136 	uint64_t		*newInstruction,
    137 	int				*howManyEaten,
    138 	char			*originalInstructions,
    139 	int				*originalInstructionCount,
    140 	uint8_t			*originalInstructionSizes );
    141 
    142 	static void
    143 fixupInstructions(
    144     void		*originalFunction,
    145     void		*escapeIsland,
    146     void		*instructionsToFix,
    147 	int			instructionCount,
    148 	uint8_t		*instructionSizes );
    149 #endif
    150 
    151 /*******************************************************************************
    152 *
    153 *	Interface
    154 *
    155 *******************************************************************************/
    156 #pragma mark	-
    157 #pragma mark	(Interface)
    158 
    159 #if defined(__i386__) || defined(__x86_64__)
    160 mach_error_t makeIslandExecutable(void *address) {
    161 	mach_error_t err = err_none;
    162     uintptr_t page = (uintptr_t)address & ~(uintptr_t)(PAGE_SIZE - 1);
    163     int e = err_none;
    164     e |= mprotect((void *)page, PAGE_SIZE, PROT_EXEC | PROT_READ);
    165     e |= msync((void *)page, PAGE_SIZE, MS_INVALIDATE );
    166     if (e) {
    167         err = err_cannot_override;
    168     }
    169     return err;
    170 }
    171 #endif
    172 
    173     mach_error_t
    174 mach_override_ptr(
    175 	void *originalFunctionAddress,
    176     const void *overrideFunctionAddress,
    177     void **originalFunctionReentryIsland )
    178 {
    179 	assert( originalFunctionAddress );
    180 	assert( overrideFunctionAddress );
    181 
    182 	// this addresses overriding such functions as AudioOutputUnitStart()
    183 	// test with modified DefaultOutputUnit project
    184 #if defined(__x86_64__)
    185     for(;;){
    186         if(*(uint16_t*)originalFunctionAddress==0x25FF)    // jmp qword near [rip+0x????????]
    187             originalFunctionAddress=*(void**)((char*)originalFunctionAddress+6+*(int32_t *)((uint16_t*)originalFunctionAddress+1));
    188         else break;
    189     }
    190 #elif defined(__i386__)
    191     for(;;){
    192         if(*(uint16_t*)originalFunctionAddress==0x25FF)    // jmp *0x????????
    193             originalFunctionAddress=**(void***)((uint16_t*)originalFunctionAddress+1);
    194         else break;
    195     }
    196 #endif
    197 
    198 	long	*originalFunctionPtr = (long*) originalFunctionAddress;
    199 	mach_error_t	err = err_none;
    200 
    201 #if defined(__ppc__) || defined(__POWERPC__)
    202 	//	Ensure first instruction isn't 'mfctr'.
    203 	#define	kMFCTRMask			0xfc1fffff
    204 	#define	kMFCTRInstruction	0x7c0903a6
    205 
    206 	long	originalInstruction = *originalFunctionPtr;
    207 	if( !err && ((originalInstruction & kMFCTRMask) == kMFCTRInstruction) )
    208 		err = err_cannot_override;
    209 #elif defined(__i386__) || defined(__x86_64__)
    210 	int eatenCount = 0;
    211 	int originalInstructionCount = 0;
    212 	char originalInstructions[kOriginalInstructionsSize];
    213 	uint8_t originalInstructionSizes[kOriginalInstructionsSize];
    214 	uint64_t jumpRelativeInstruction = 0; // JMP
    215 
    216 	Boolean overridePossible = eatKnownInstructions ((unsigned char *)originalFunctionPtr,
    217 										&jumpRelativeInstruction, &eatenCount,
    218 										originalInstructions, &originalInstructionCount,
    219 										originalInstructionSizes );
    220 	if (eatenCount > kOriginalInstructionsSize) {
    221 		//printf ("Too many instructions eaten\n");
    222 		overridePossible = false;
    223 	}
    224 	if (!overridePossible) err = err_cannot_override;
    225 	if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__);
    226 #endif
    227 
    228 	//	Make the original function implementation writable.
    229 	if( !err ) {
    230 		err = vm_protect( mach_task_self(),
    231 				(vm_address_t) originalFunctionPtr, 8, false,
    232 				(VM_PROT_ALL | VM_PROT_COPY) );
    233 		if( err )
    234 			err = vm_protect( mach_task_self(),
    235 					(vm_address_t) originalFunctionPtr, 8, false,
    236 					(VM_PROT_DEFAULT | VM_PROT_COPY) );
    237 	}
    238 	if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__);
    239 
    240 	//	Allocate and target the escape island to the overriding function.
    241 	BranchIsland	*escapeIsland = NULL;
    242 	if( !err )
    243 		err = allocateBranchIsland( &escapeIsland, kAllocateHigh, originalFunctionAddress );
    244 		if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__);
    245 
    246 
    247 #if defined(__ppc__) || defined(__POWERPC__)
    248 	if( !err )
    249 		err = setBranchIslandTarget( escapeIsland, overrideFunctionAddress, 0 );
    250 
    251 	//	Build the branch absolute instruction to the escape island.
    252 	long	branchAbsoluteInstruction = 0; // Set to 0 just to silence warning.
    253 	if( !err ) {
    254 		long escapeIslandAddress = ((long) escapeIsland) & 0x3FFFFFF;
    255 		branchAbsoluteInstruction = 0x48000002 | escapeIslandAddress;
    256 	}
    257 #elif defined(__i386__) || defined(__x86_64__)
    258         if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__);
    259 
    260 	if( !err )
    261 		err = setBranchIslandTarget_i386( escapeIsland, overrideFunctionAddress, 0 );
    262 
    263 	if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__);
    264 	// Build the jump relative instruction to the escape island
    265 #endif
    266 
    267 
    268 #if defined(__i386__) || defined(__x86_64__)
    269 	if (!err) {
    270 		uint32_t addressOffset = ((char*)escapeIsland - (char*)originalFunctionPtr - 5);
    271 		addressOffset = OSSwapInt32(addressOffset);
    272 
    273 		jumpRelativeInstruction |= 0xE900000000000000LL;
    274 		jumpRelativeInstruction |= ((uint64_t)addressOffset & 0xffffffff) << 24;
    275 		jumpRelativeInstruction = OSSwapInt64(jumpRelativeInstruction);
    276 	}
    277 #endif
    278 
    279 	//	Optionally allocate & return the reentry island. This may contain relocated
    280 	//  jmp instructions and so has all the same addressing reachability requirements
    281 	//  the escape island has to the original function, except the escape island is
    282 	//  technically our original function.
    283 	BranchIsland	*reentryIsland = NULL;
    284 	if( !err && originalFunctionReentryIsland ) {
    285 		err = allocateBranchIsland( &reentryIsland, kAllocateHigh, escapeIsland);
    286 		if( !err )
    287 			*originalFunctionReentryIsland = reentryIsland;
    288 	}
    289 
    290 #if defined(__ppc__) || defined(__POWERPC__)
    291 	//	Atomically:
    292 	//	o If the reentry island was allocated:
    293 	//		o Insert the original instruction into the reentry island.
    294 	//		o Target the reentry island at the 2nd instruction of the
    295 	//		  original function.
    296 	//	o Replace the original instruction with the branch absolute.
    297 	if( !err ) {
    298 		int escapeIslandEngaged = false;
    299 		do {
    300 			if( reentryIsland )
    301 				err = setBranchIslandTarget( reentryIsland,
    302 						(void*) (originalFunctionPtr+1), originalInstruction );
    303 			if( !err ) {
    304 				escapeIslandEngaged = CompareAndSwap( originalInstruction,
    305 										branchAbsoluteInstruction,
    306 										(UInt32*)originalFunctionPtr );
    307 				if( !escapeIslandEngaged ) {
    308 					//	Someone replaced the instruction out from under us,
    309 					//	re-read the instruction, make sure it's still not
    310 					//	'mfctr' and try again.
    311 					originalInstruction = *originalFunctionPtr;
    312 					if( (originalInstruction & kMFCTRMask) == kMFCTRInstruction)
    313 						err = err_cannot_override;
    314 				}
    315 			}
    316 		} while( !err && !escapeIslandEngaged );
    317 	}
    318 #elif defined(__i386__) || defined(__x86_64__)
    319 	// Atomically:
    320 	//	o If the reentry island was allocated:
    321 	//		o Insert the original instructions into the reentry island.
    322 	//		o Target the reentry island at the first non-replaced
    323 	//        instruction of the original function.
    324 	//	o Replace the original first instructions with the jump relative.
    325 	//
    326 	// Note that on i386, we do not support someone else changing the code under our feet
    327 	if ( !err ) {
    328 		fixupInstructions(originalFunctionPtr, reentryIsland, originalInstructions,
    329 					originalInstructionCount, originalInstructionSizes );
    330 
    331 		if( reentryIsland )
    332 			err = setBranchIslandTarget_i386( reentryIsland,
    333 										 (void*) ((char *)originalFunctionPtr+eatenCount), originalInstructions );
    334 		// try making islands executable before planting the jmp
    335 #if defined(__x86_64__) || defined(__i386__)
    336         if( !err )
    337             err = makeIslandExecutable(escapeIsland);
    338         if( !err && reentryIsland )
    339             err = makeIslandExecutable(reentryIsland);
    340 #endif
    341 		if ( !err )
    342 			atomic_mov64((uint64_t *)originalFunctionPtr, jumpRelativeInstruction);
    343 		mach_error_t prot_err = err_none;
    344 		prot_err = vm_protect( mach_task_self(),
    345 				       (vm_address_t) originalFunctionPtr, 8, false,
    346 				       (VM_PROT_READ | VM_PROT_EXECUTE) );
    347 		if(prot_err) fprintf(stderr, "err = %x %s:%d\n", prot_err, __FILE__, __LINE__);
    348 	}
    349 #endif
    350 
    351 	//	Clean up on error.
    352 	if( err ) {
    353 		if( reentryIsland )
    354 			freeBranchIsland( reentryIsland );
    355 		if( escapeIsland )
    356 			freeBranchIsland( escapeIsland );
    357 	}
    358 
    359 	return err;
    360 }
    361 
    362 /*******************************************************************************
    363 *
    364 *	Implementation
    365 *
    366 *******************************************************************************/
    367 #pragma mark	-
    368 #pragma mark	(Implementation)
    369 
    370 /*******************************************************************************
    371 	Implementation: Allocates memory for a branch island.
    372 
    373 	@param	island			<-	The allocated island.
    374 	@param	allocateHigh	->	Whether to allocate the island at the end of the
    375 								address space (for use with the branch absolute
    376 								instruction).
    377 	@result					<-	mach_error_t
    378 
    379 	***************************************************************************/
    380 
    381 	mach_error_t
    382 allocateBranchIsland(
    383 		BranchIsland	**island,
    384 		int				allocateHigh,
    385 		void *originalFunctionAddress)
    386 {
    387 	assert( island );
    388 
    389 	mach_error_t	err = err_none;
    390 
    391 	if( allocateHigh ) {
    392 		assert( sizeof( BranchIsland ) <= PAGE_SIZE );
    393 		vm_address_t page = 0;
    394 #if defined(__i386__)
    395 		err = vm_allocate( mach_task_self(), &page, PAGE_SIZE, VM_FLAGS_ANYWHERE );
    396 		if( err == err_none )
    397 			*island = (BranchIsland*) page;
    398 #else
    399 
    400 #if defined(__ppc__) || defined(__POWERPC__)
    401 		vm_address_t first = 0xfeffffff;
    402 		vm_address_t last = 0xfe000000 + PAGE_SIZE;
    403 #elif defined(__x86_64__)
    404 		// 64-bit ASLR is in bits 13-28
    405 		vm_address_t first = ((uint64_t)originalFunctionAddress & ~( (0xFUL << 28) | (PAGE_SIZE - 1) ) ) | (0x1UL << 31);
    406 		vm_address_t last = (uint64_t)originalFunctionAddress & ~((0x1UL << 32) - 1);
    407 #endif
    408 
    409 		page = first;
    410 		int allocated = 0;
    411 		vm_map_t task_self = mach_task_self();
    412 
    413 		while( !err && !allocated && page != last ) {
    414 
    415 			err = vm_allocate( task_self, &page, PAGE_SIZE, 0 );
    416 			if( err == err_none )
    417 				allocated = 1;
    418 			else if( err == KERN_NO_SPACE ) {
    419 #if defined(__x86_64__)
    420 				page -= PAGE_SIZE;
    421 #else
    422 				page += PAGE_SIZE;
    423 #endif
    424 				err = err_none;
    425 			}
    426 		}
    427 		if( allocated )
    428 			*island = (BranchIsland*) page;
    429 		else if( !allocated && !err )
    430 			err = KERN_NO_SPACE;
    431 #endif
    432 	} else {
    433 		void *block = malloc( sizeof( BranchIsland ) );
    434 		if( block )
    435 			*island = block;
    436 		else
    437 			err = KERN_NO_SPACE;
    438 	}
    439 	if( !err )
    440 		(**island).allocatedHigh = allocateHigh;
    441 
    442 	return err;
    443 }
    444 
    445 /*******************************************************************************
    446 	Implementation: Deallocates memory for a branch island.
    447 
    448 	@param	island	->	The island to deallocate.
    449 	@result			<-	mach_error_t
    450 
    451 	***************************************************************************/
    452 
    453 	mach_error_t
    454 freeBranchIsland(
    455 		BranchIsland	*island )
    456 {
    457 	assert( island );
    458 	assert( (*(long*)&island->instructions[0]) == kIslandTemplate[0] );
    459 	assert( island->allocatedHigh );
    460 
    461 	mach_error_t	err = err_none;
    462 
    463 	if( island->allocatedHigh ) {
    464 		assert( sizeof( BranchIsland ) <= PAGE_SIZE );
    465 		err = vm_deallocate(mach_task_self(), (vm_address_t) island, PAGE_SIZE );
    466 	} else {
    467 		free( island );
    468 	}
    469 
    470 	return err;
    471 }
    472 
    473 /*******************************************************************************
    474 	Implementation: Sets the branch island's target, with an optional
    475 	instruction.
    476 
    477 	@param	island		->	The branch island to insert target into.
    478 	@param	branchTo	->	The address of the target.
    479 	@param	instruction	->	Optional instruction to execute prior to branch. Set
    480 							to zero for nop.
    481 	@result				<-	mach_error_t
    482 
    483 	***************************************************************************/
    484 #if defined(__ppc__) || defined(__POWERPC__)
    485 	mach_error_t
    486 setBranchIslandTarget(
    487 		BranchIsland	*island,
    488 		const void		*branchTo,
    489 		long			instruction )
    490 {
    491 	//	Copy over the template code.
    492     bcopy( kIslandTemplate, island->instructions, sizeof( kIslandTemplate ) );
    493 
    494     //	Fill in the address.
    495     ((short*)island->instructions)[kAddressLo] = ((long) branchTo) & 0x0000FFFF;
    496     ((short*)island->instructions)[kAddressHi]
    497     	= (((long) branchTo) >> 16) & 0x0000FFFF;
    498 
    499     //	Fill in the (optional) instuction.
    500     if( instruction != 0 ) {
    501         ((short*)island->instructions)[kInstructionLo]
    502         	= instruction & 0x0000FFFF;
    503         ((short*)island->instructions)[kInstructionHi]
    504         	= (instruction >> 16) & 0x0000FFFF;
    505     }
    506 
    507     //MakeDataExecutable( island->instructions, sizeof( kIslandTemplate ) );
    508 	msync( island->instructions, sizeof( kIslandTemplate ), MS_INVALIDATE );
    509 
    510     return err_none;
    511 }
    512 #endif
    513 
    514 #if defined(__i386__)
    515 	mach_error_t
    516 setBranchIslandTarget_i386(
    517 	BranchIsland	*island,
    518 	const void		*branchTo,
    519 	char*			instructions )
    520 {
    521 
    522 	//	Copy over the template code.
    523     bcopy( kIslandTemplate, island->instructions, sizeof( kIslandTemplate ) );
    524 
    525 	// copy original instructions
    526 	if (instructions) {
    527 		bcopy (instructions, island->instructions + kInstructions, kOriginalInstructionsSize);
    528 	}
    529 
    530     // Fill in the address.
    531     int32_t addressOffset = (char *)branchTo - (island->instructions + kJumpAddress + 4);
    532     *((int32_t *)(island->instructions + kJumpAddress)) = addressOffset;
    533 
    534     msync( island->instructions, sizeof( kIslandTemplate ), MS_INVALIDATE );
    535     return err_none;
    536 }
    537 
    538 #elif defined(__x86_64__)
    539 mach_error_t
    540 setBranchIslandTarget_i386(
    541         BranchIsland	*island,
    542         const void		*branchTo,
    543         char*			instructions )
    544 {
    545     // Copy over the template code.
    546     bcopy( kIslandTemplate, island->instructions, sizeof( kIslandTemplate ) );
    547 
    548     // Copy original instructions.
    549     if (instructions) {
    550         bcopy (instructions, island->instructions, kOriginalInstructionsSize);
    551     }
    552 
    553     //	Fill in the address.
    554     *((uint64_t *)(island->instructions + kJumpAddress)) = (uint64_t)branchTo;
    555     msync( island->instructions, sizeof( kIslandTemplate ), MS_INVALIDATE );
    556 
    557     return err_none;
    558 }
    559 #endif
    560 
    561 
    562 #if defined(__i386__) || defined(__x86_64__)
    563 	static Boolean
    564 eatKnownInstructions(
    565 	unsigned char	*code,
    566 	uint64_t		*newInstruction,
    567 	int				*howManyEaten,
    568 	char			*originalInstructions,
    569 	int				*originalInstructionCount,
    570 	uint8_t			*originalInstructionSizes )
    571 {
    572 	Boolean allInstructionsKnown = true;
    573 	int totalEaten = 0;
    574 	int remainsToEat = 5; // a JMP instruction takes 5 bytes
    575 	int instructionIndex = 0;
    576 	ud_t ud_obj;
    577 
    578 	if (howManyEaten) *howManyEaten = 0;
    579 	if (originalInstructionCount) *originalInstructionCount = 0;
    580 	ud_init(&ud_obj);
    581 #if defined(__i386__)
    582 	ud_set_mode(&ud_obj, 32);
    583 #else
    584 	ud_set_mode(&ud_obj, 64);
    585 #endif
    586 	ud_set_input_buffer(&ud_obj, code, 64); // Assume that 'code' points to at least 64bytes of data.
    587 	while (remainsToEat > 0) {
    588 		if (!ud_disassemble(&ud_obj)) {
    589 		    allInstructionsKnown = false;
    590 		    fprintf(stderr, "mach_override: some instructions unknown! Need to update libudis86\n");
    591 		    break;
    592 		}
    593 
    594 		// At this point, we've matched curInstr
    595 		int eaten = ud_insn_len(&ud_obj);
    596 		remainsToEat -= eaten;
    597 		totalEaten += eaten;
    598 
    599 		if (originalInstructionSizes) originalInstructionSizes[instructionIndex] = eaten;
    600 		instructionIndex += 1;
    601 		if (originalInstructionCount) *originalInstructionCount = instructionIndex;
    602 	}
    603 
    604 
    605 	if (howManyEaten) *howManyEaten = totalEaten;
    606 
    607 	if (originalInstructions) {
    608 		Boolean enoughSpaceForOriginalInstructions = (totalEaten < kOriginalInstructionsSize);
    609 
    610 		if (enoughSpaceForOriginalInstructions) {
    611 			memset(originalInstructions, 0x90 /* NOP */, kOriginalInstructionsSize); // fill instructions with NOP
    612 			bcopy(code, originalInstructions, totalEaten);
    613 		} else {
    614 			// printf ("Not enough space in island to store original instructions. Adapt the island definition and kOriginalInstructionsSize\n");
    615 			return false;
    616 		}
    617 	}
    618 
    619 	if (allInstructionsKnown) {
    620 		// save last 3 bytes of first 64bits of codre we'll replace
    621 		uint64_t currentFirst64BitsOfCode = *((uint64_t *)code);
    622 		currentFirst64BitsOfCode = OSSwapInt64(currentFirst64BitsOfCode); // back to memory representation
    623 		currentFirst64BitsOfCode &= 0x0000000000FFFFFFLL;
    624 
    625 		// keep only last 3 instructions bytes, first 5 will be replaced by JMP instr
    626 		*newInstruction &= 0xFFFFFFFFFF000000LL; // clear last 3 bytes
    627 		*newInstruction |= (currentFirst64BitsOfCode & 0x0000000000FFFFFFLL); // set last 3 bytes
    628 	}
    629 
    630 	return allInstructionsKnown;
    631 }
    632 
    633 	static void
    634 fixupInstructions(
    635     void		*originalFunction,
    636     void		*escapeIsland,
    637     void		*instructionsToFix,
    638 	int			instructionCount,
    639 	uint8_t		*instructionSizes )
    640 {
    641 	int	index;
    642 	for (index = 0;index < instructionCount;index += 1)
    643 	{
    644 		if (*(uint8_t*)instructionsToFix == 0xE9) // 32-bit jump relative
    645 		{
    646 			uint32_t offset = (uintptr_t)originalFunction - (uintptr_t)escapeIsland;
    647 			uint32_t *jumpOffsetPtr = (uint32_t*)((uintptr_t)instructionsToFix + 1);
    648 			*jumpOffsetPtr += offset;
    649 		}
    650 
    651 		originalFunction = (void*)((uintptr_t)originalFunction + instructionSizes[index]);
    652 		escapeIsland = (void*)((uintptr_t)escapeIsland + instructionSizes[index]);
    653 		instructionsToFix = (void*)((uintptr_t)instructionsToFix + instructionSizes[index]);
    654     }
    655 }
    656 
    657 #if defined(__i386__)
    658 __asm(
    659 			".text;"
    660 			".align 2, 0x90;"
    661 			"_atomic_mov64:;"
    662 			"	pushl %ebp;"
    663 			"	movl %esp, %ebp;"
    664 			"	pushl %esi;"
    665 			"	pushl %ebx;"
    666 			"	pushl %ecx;"
    667 			"	pushl %eax;"
    668 			"	pushl %edx;"
    669 
    670 			// atomic push of value to an address
    671 			// we use cmpxchg8b, which compares content of an address with
    672 			// edx:eax. If they are equal, it atomically puts 64bit value
    673 			// ecx:ebx in address.
    674 			// We thus put contents of address in edx:eax to force ecx:ebx
    675 			// in address
    676 			"	mov		8(%ebp), %esi;"  // esi contains target address
    677 			"	mov		12(%ebp), %ebx;"
    678 			"	mov		16(%ebp), %ecx;" // ecx:ebx now contains value to put in target address
    679 			"	mov		(%esi), %eax;"
    680 			"	mov		4(%esi), %edx;"  // edx:eax now contains value currently contained in target address
    681 			"	lock; cmpxchg8b	(%esi);" // atomic move.
    682 
    683 			// restore registers
    684 			"	popl %edx;"
    685 			"	popl %eax;"
    686 			"	popl %ecx;"
    687 			"	popl %ebx;"
    688 			"	popl %esi;"
    689 			"	popl %ebp;"
    690 			"	ret"
    691 );
    692 #elif defined(__x86_64__)
    693 void atomic_mov64(
    694 		uint64_t *targetAddress,
    695 		uint64_t value )
    696 {
    697     *targetAddress = value;
    698 }
    699 #endif
    700 #endif
    701