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