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