Skip to content

Commit

Permalink
Merge pull request #22 from lapcat/master
Browse files Browse the repository at this point in the history
A few fixes, including compatibility with Rogue Amoeba's Instant On.
rentzsch committed Oct 12, 2011
2 parents 0b55645 + f8e0c42 commit b5c0803
Showing 2 changed files with 79 additions and 18 deletions.
83 changes: 68 additions & 15 deletions mach_override/mach_override.c
Original file line number Diff line number Diff line change
@@ -134,7 +134,17 @@ eatKnownInstructions(
unsigned char *code,
uint64_t *newInstruction,
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

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

// this addresses overriding such functions as AudioOutputUnitStart()
// 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__)
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));
else break;
}
#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);
#endif
else break;
}
#endif
@@ -200,11 +209,15 @@ mach_override_ptr(
err = err_cannot_override;
#elif defined(__i386__) || defined(__x86_64__)
int eatenCount = 0;
int originalInstructionCount = 0;
char originalInstructions[kOriginalInstructionsSize];
uint8_t originalInstructionSizes[kOriginalInstructionsSize];
uint64_t jumpRelativeInstruction = 0; // JMP

Boolean overridePossible = eatKnownInstructions ((unsigned char *)originalFunctionPtr,
&jumpRelativeInstruction, &eatenCount, originalInstructions);
&jumpRelativeInstruction, &eatenCount,
originalInstructions, &originalInstructionCount,
originalInstructionSizes );
if (eatenCount > kOriginalInstructionsSize) {
//printf ("Too many instructions eaten\n");
overridePossible = false;
@@ -264,10 +277,13 @@ mach_override_ptr(
}
#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;
if( !err && originalFunctionReentryIsland ) {
err = allocateBranchIsland( &reentryIsland, kAllocateNormal, NULL);
err = allocateBranchIsland( &reentryIsland, kAllocateHigh, escapeIsland);
if( !err )
*originalFunctionReentryIsland = reentryIsland;
}
@@ -310,6 +326,9 @@ mach_override_ptr(
//
// Note that on i386, we do not support someone else changing the code under our feet
if ( !err ) {
fixupInstructions(originalFunctionPtr, reentryIsland, originalInstructions,
originalInstructionCount, originalInstructionSizes );

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

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

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

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

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


@@ -663,6 +692,30 @@ eatKnownInstructions(

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

#if defined(__i386__)
14 changes: 11 additions & 3 deletions mach_override/test_mach_override.cp
Original file line number Diff line number Diff line change
@@ -2,6 +2,7 @@
#include <assert.h>
#include <string.h>
#include <errno.h>
#include <CoreServices/CoreServices.h>
#include "mach_override.h"

#define assertStrEqual( EXPECTED, ACTUAL ) if( strcmp( (EXPECTED), (ACTUAL) ) != 0 ) { printf( "EXPECTED: %s\nACTUAL: %s\n", (EXPECTED), (ACTUAL)); assert( strcmp( (EXPECTED), (ACTUAL) ) == 0 ); }
@@ -40,17 +41,22 @@ void testLocalFunctionOverrideByPointer() {
#pragma mark Test System Override by Pointer

char* (*strerrorPtr)(int) = strerror;
const char* strerrReturnValue = "Unknown error: 0";

void testSystemFunctionOverrideByPointer() {
SInt32 sysv;
if (Gestalt( gestaltSystemVersion, &sysv ) == noErr && sysv >= 0x1070)
strerrReturnValue = "Undefined error: 0";

// Test original.
assertStrEqual( "Unknown error: 0", strerrorPtr( 0 ) );
assertStrEqual( strerrReturnValue, strerrorPtr( 0 ) );

// Override system function by pointer.
kern_return_t err;
MACH_OVERRIDE( char*, strerror, (int errnum), err ) {
// Test calling through the reentry island back into the original
// implementation.
assertStrEqual( "Unknown error: 0", strerror_reenter( 0 ) );
assertStrEqual( strerrReturnValue, strerror_reenter( 0 ) );

return (char *)"strerrorOverride";
} END_MACH_OVERRIDE(strerror);
@@ -63,6 +69,7 @@ void testSystemFunctionOverrideByPointer() {
//------------------------------------------------------------------------------
#pragma mark Test System Override by Name

/* The following is commented out because it does not compile.
int strerror_rOverride( int errnum, char *strerrbuf, size_t buflen );
int (*strerror_rPtr)( int, char*, size_t ) = strerror_r;
int (*gReentry_strerror_r)( int, char*, size_t );
@@ -86,14 +93,15 @@ int strerror_rOverride( int errnum, char *strerrbuf, size_t buflen ) {
return 0;
}
*/

//------------------------------------------------------------------------------
#pragma mark main

int main( int argc, const char *argv[] ) {
testLocalFunctionOverrideByPointer();
testSystemFunctionOverrideByPointer();
testSystemFunctionOverrideByName();
//testSystemFunctionOverrideByName();

printf( "success\n" );
return 0;

0 comments on commit b5c0803

Please sign in to comment.