Skip to content

Commit

Permalink
Allow mach_override to patch and relocate code that has already been …
Browse files Browse the repository at this point in the history
…patched or might otherwise contain relative jmp instructions. This fixes incompatibility with Rogue Amoeba's Instant On component.
  • Loading branch information
lapcat committed Oct 10, 2011
1 parent 820b779 commit f8e0c42
Showing 1 changed file with 68 additions and 15 deletions.
83 changes: 68 additions & 15 deletions mach_override/mach_override.c
Expand Up @@ -134,7 +134,17 @@ eatKnownInstructions(
unsigned char *code, unsigned char *code,
uint64_t *newInstruction, uint64_t *newInstruction,
int *howManyEaten, int *howManyEaten,
char *originalInstructions ); char *originalInstructions,
int *originalInstructionCount,
uint8_t *originalInstructionSizes );

static void
fixupInstructions(
void *originalFunction,
void *escapeIsland,
void *instructionsToFix,
int instructionCount,
uint8_t *instructionSizes );
#endif #endif


/******************************************************************************* /*******************************************************************************
Expand Down Expand Up @@ -172,17 +182,16 @@ mach_override_ptr(


// this addresses overriding such functions as AudioOutputUnitStart() // this addresses overriding such functions as AudioOutputUnitStart()
// test with modified DefaultOutputUnit project // test with modified DefaultOutputUnit project
#if defined(__x86_64__) || defined(__i386__)
for(;;){
if(*(unsigned char*)originalFunctionAddress==0xE9) // jmp .+0x????????
originalFunctionAddress=(void*)((char*)originalFunctionAddress+5+*(int32_t *)((char*)originalFunctionAddress+1));
#if defined(__x86_64__) #if defined(__x86_64__)
else if(*(uint16_t*)originalFunctionAddress==0x25FF) // jmp qword near [rip+0x????????] for(;;){
if(*(uint16_t*)originalFunctionAddress==0x25FF) // jmp qword near [rip+0x????????]
originalFunctionAddress=*(void**)((char*)originalFunctionAddress+6+*(int32_t *)((uint16_t*)originalFunctionAddress+1)); originalFunctionAddress=*(void**)((char*)originalFunctionAddress+6+*(int32_t *)((uint16_t*)originalFunctionAddress+1));
else break;
}
#elif defined(__i386__) #elif defined(__i386__)
else if(*(uint16_t*)originalFunctionAddress==0x25FF) // jmp *0x???????? for(;;){
if(*(uint16_t*)originalFunctionAddress==0x25FF) // jmp *0x????????
originalFunctionAddress=**(void***)((uint16_t*)originalFunctionAddress+1); originalFunctionAddress=**(void***)((uint16_t*)originalFunctionAddress+1);
#endif
else break; else break;
} }
#endif #endif
Expand All @@ -200,11 +209,15 @@ mach_override_ptr(
err = err_cannot_override; err = err_cannot_override;
#elif defined(__i386__) || defined(__x86_64__) #elif defined(__i386__) || defined(__x86_64__)
int eatenCount = 0; int eatenCount = 0;
int originalInstructionCount = 0;
char originalInstructions[kOriginalInstructionsSize]; char originalInstructions[kOriginalInstructionsSize];
uint8_t originalInstructionSizes[kOriginalInstructionsSize];
uint64_t jumpRelativeInstruction = 0; // JMP uint64_t jumpRelativeInstruction = 0; // JMP


Boolean overridePossible = eatKnownInstructions ((unsigned char *)originalFunctionPtr, Boolean overridePossible = eatKnownInstructions ((unsigned char *)originalFunctionPtr,
&jumpRelativeInstruction, &eatenCount, originalInstructions); &jumpRelativeInstruction, &eatenCount,
originalInstructions, &originalInstructionCount,
originalInstructionSizes );
if (eatenCount > kOriginalInstructionsSize) { if (eatenCount > kOriginalInstructionsSize) {
//printf ("Too many instructions eaten\n"); //printf ("Too many instructions eaten\n");
overridePossible = false; overridePossible = false;
Expand Down Expand Up @@ -264,10 +277,13 @@ mach_override_ptr(
} }
#endif #endif


// Optionally allocate & return the reentry island. // Optionally allocate & return the reentry island. This may contain relocated
// jmp instructions and so has all the same addressing reachability requirements
// the escape island has to the original function, except the escape island is
// technically our original function.
BranchIsland *reentryIsland = NULL; BranchIsland *reentryIsland = NULL;
if( !err && originalFunctionReentryIsland ) { if( !err && originalFunctionReentryIsland ) {
err = allocateBranchIsland( &reentryIsland, kAllocateNormal, NULL); err = allocateBranchIsland( &reentryIsland, kAllocateHigh, escapeIsland);
if( !err ) if( !err )
*originalFunctionReentryIsland = reentryIsland; *originalFunctionReentryIsland = reentryIsland;
} }
Expand Down Expand Up @@ -310,6 +326,9 @@ mach_override_ptr(
// //
// Note that on i386, we do not support someone else changing the code under our feet // Note that on i386, we do not support someone else changing the code under our feet
if ( !err ) { if ( !err ) {
fixupInstructions(originalFunctionPtr, reentryIsland, originalInstructions,
originalInstructionCount, originalInstructionSizes );

if( reentryIsland ) if( reentryIsland )
err = setBranchIslandTarget_i386( reentryIsland, err = setBranchIslandTarget_i386( reentryIsland,
(void*) ((char *)originalFunctionPtr+eatenCount), originalInstructions ); (void*) ((char *)originalFunctionPtr+eatenCount), originalInstructions );
Expand Down Expand Up @@ -550,6 +569,7 @@ typedef struct {


#if defined(__i386__) #if defined(__i386__)
static AsmInstructionMatch possibleInstructions[] = { static AsmInstructionMatch possibleInstructions[] = {
{ 0x5, {0xFF, 0x00, 0x00, 0x00, 0x00}, {0xE9, 0x00, 0x00, 0x00, 0x00} }, // jmp 0x????????
{ 0x5, {0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, {0x55, 0x89, 0xe5, 0xc9, 0xc3} }, // push %ebp; mov %esp,%ebp; leave; ret { 0x5, {0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, {0x55, 0x89, 0xe5, 0xc9, 0xc3} }, // push %ebp; mov %esp,%ebp; leave; ret
{ 0x1, {0xFF}, {0x90} }, // nop { 0x1, {0xFF}, {0x90} }, // nop
{ 0x1, {0xFF}, {0x55} }, // push %esp { 0x1, {0xFF}, {0x55} }, // push %esp
Expand All @@ -567,6 +587,7 @@ static AsmInstructionMatch possibleInstructions[] = {
}; };
#elif defined(__x86_64__) #elif defined(__x86_64__)
static AsmInstructionMatch possibleInstructions[] = { static AsmInstructionMatch possibleInstructions[] = {
{ 0x5, {0xFF, 0x00, 0x00, 0x00, 0x00}, {0xE9, 0x00, 0x00, 0x00, 0x00} }, // jmp 0x????????
{ 0x1, {0xFF}, {0x90} }, // nop { 0x1, {0xFF}, {0x90} }, // nop
{ 0x1, {0xF8}, {0x50} }, // push %rX { 0x1, {0xF8}, {0x50} }, // push %rX
{ 0x3, {0xFF, 0xFF, 0xFF}, {0x48, 0x89, 0xE5} }, // mov %rsp,%rbp { 0x3, {0xFF, 0xFF, 0xFF}, {0x48, 0x89, 0xE5} }, // mov %rsp,%rbp
Expand Down Expand Up @@ -600,17 +621,21 @@ static Boolean codeMatchesInstruction(unsigned char *code, AsmInstructionMatch*
#if defined(__i386__) || defined(__x86_64__) #if defined(__i386__) || defined(__x86_64__)
static Boolean static Boolean
eatKnownInstructions( eatKnownInstructions(
unsigned char *code, unsigned char *code,
uint64_t* newInstruction, uint64_t *newInstruction,
int* howManyEaten, int *howManyEaten,
char* originalInstructions ) char *originalInstructions,
int *originalInstructionCount,
uint8_t *originalInstructionSizes )
{ {
Boolean allInstructionsKnown = true; Boolean allInstructionsKnown = true;
int totalEaten = 0; int totalEaten = 0;
unsigned char* ptr = code; unsigned char* ptr = code;
int remainsToEat = 5; // a JMP instruction takes 5 bytes int remainsToEat = 5; // a JMP instruction takes 5 bytes
int instructionIndex = 0;


if (howManyEaten) *howManyEaten = 0; if (howManyEaten) *howManyEaten = 0;
if (originalInstructionCount) *originalInstructionCount = 0;
while (remainsToEat > 0) { while (remainsToEat > 0) {
Boolean curInstructionKnown = false; Boolean curInstructionKnown = false;


Expand All @@ -633,6 +658,10 @@ eatKnownInstructions(
ptr += eaten; ptr += eaten;
remainsToEat -= eaten; remainsToEat -= eaten;
totalEaten += eaten; totalEaten += eaten;

if (originalInstructionSizes) originalInstructionSizes[instructionIndex] = eaten;
instructionIndex += 1;
if (originalInstructionCount) *originalInstructionCount = instructionIndex;
} }




Expand Down Expand Up @@ -663,6 +692,30 @@ eatKnownInstructions(


return allInstructionsKnown; return allInstructionsKnown;
} }

static void
fixupInstructions(
void *originalFunction,
void *escapeIsland,
void *instructionsToFix,
int instructionCount,
uint8_t *instructionSizes )
{
int index;
for (index = 0;index < instructionCount;index += 1)
{
if (*(uint8_t*)instructionsToFix == 0xE9) // 32-bit jump relative
{
uint32_t offset = (uintptr_t)originalFunction - (uintptr_t)escapeIsland;
uint32_t *jumpOffsetPtr = (uint32_t*)((uintptr_t)instructionsToFix + 1);
*jumpOffsetPtr += offset;
}

originalFunction = (void*)((uintptr_t)originalFunction + instructionSizes[index]);
escapeIsland = (void*)((uintptr_t)escapeIsland + instructionSizes[index]);
instructionsToFix = (void*)((uintptr_t)instructionsToFix + instructionSizes[index]);
}
}
#endif #endif


#if defined(__i386__) #if defined(__i386__)
Expand Down

0 comments on commit f8e0c42

Please sign in to comment.