IOReturn IOFireWireSBP2LibORB::setCommandBuffersAsRanges( FWSBP2VirtualRange * ranges, UInt32 withCount, UInt32 withDirection, UInt32 offset, UInt32 length ) { IOReturn status = kIOReturnSuccess; uint32_t len = 0; uint64_t params[6]; FWLOG(( "IOFireWireSBP2LibORB : setCommandBuffersAsRanges\n" )); // printf( "IOFireWireSBP2LibORB : setCommandBuffersAsRanges\n" ); // // create or grow range scratch // UInt32 range_length = withCount * sizeof(FWSBP2PrivateVirtualRange); if( fRangeScratchLength < range_length ) { if( fRangeScratch != NULL ) { // delete it vm_deallocate( mach_task_self(), (vm_address_t)fRangeScratch, fRangeScratchLength ); fRangeScratch = NULL; fRangeScratchLength = 0; } // alloc a bigger one vm_allocate( mach_task_self(), (vm_address_t*)&fRangeScratch, range_length, true /*anywhere*/ ); if( fRangeScratch != NULL ) { fRangeScratchLength = range_length; } } // // fill range scratch // if( fRangeScratch != NULL ) { for( UInt32 i = 0; i < withCount; i++ ) { fRangeScratch[i].address = (uint64_t)ranges[i].address; fRangeScratch[i].length = ranges[i].length; ROSETTA_ONLY( fRangeScratch[i].address = OSSwapInt64( fRangeScratch[i].address ); fRangeScratch[i].length = OSSwapInt64( fRangeScratch[i].length ); ); } }
void swap_segment_command_64( struct segment_command_64* sg, enum NXByteOrder target_byte_sex) { /* char segname[16] */ sg->cmd = OSSwapInt32(sg->cmd); sg->cmdsize = OSSwapInt32(sg->cmdsize); sg->vmaddr = OSSwapInt64(sg->vmaddr); sg->vmsize = OSSwapInt64(sg->vmsize); sg->fileoff = OSSwapInt64(sg->fileoff); sg->filesize = OSSwapInt64(sg->filesize); sg->maxprot = OSSwapInt32(sg->maxprot); sg->initprot = OSSwapInt32(sg->initprot); sg->nsects = OSSwapInt32(sg->nsects); sg->flags = OSSwapInt32(sg->flags); }
void swap_x86_exception_state64( x86_exception_state64_t *exc, enum NXByteOrder target_byte_sex) { exc->trapno = OSSwapInt32(exc->trapno); exc->err = OSSwapInt32(exc->err); exc->faultvaddr = OSSwapInt64(exc->faultvaddr); }
void swap_x86_debug_state64( x86_debug_state64_t *debug, enum NXByteOrder target_byte_sex) { debug->dr0 = OSSwapInt64(debug->dr0); debug->dr1 = OSSwapInt64(debug->dr1); debug->dr2 = OSSwapInt64(debug->dr2); debug->dr3 = OSSwapInt64(debug->dr3); debug->dr4 = OSSwapInt64(debug->dr4); debug->dr5 = OSSwapInt64(debug->dr5); debug->dr6 = OSSwapInt64(debug->dr6); debug->dr7 = OSSwapInt64(debug->dr7); }
void dosect64(void *start, struct section_64 *sect, bool needsFlip, struct gcinfo *gcip) { if (debug) printf("section %s from segment %s\n", sect->sectname, sect->segname); if (strcmp(sect->segname, "__OBJC") && strcmp(sect->segname, "__DATA")) return; if (strcmp(sect->sectname, "__image_info") && strncmp(sect->sectname, "__objc_imageinfo", 16)) return; gcip->hasObjC = true; gcip->hasInfo = true; if (needsFlip) { sect->offset = OSSwapInt32(sect->offset); sect->size = OSSwapInt64(sect->size); } // these guys aren't inline - they point elsewhere gcip->flags = iiflags(start + sect->offset, sect->size, needsFlip); }
void swap_section_64( struct section_64 *s, uint32_t nsects, enum NXByteOrder target_byte_sex) { uint32_t i; for(i = 0; i < nsects; i++){ /* sectname[16] */ /* segname[16] */ s[i].addr = OSSwapInt64(s[i].addr); s[i].size = OSSwapInt64(s[i].size); s[i].offset = OSSwapInt32(s[i].offset); s[i].align = OSSwapInt32(s[i].align); s[i].reloff = OSSwapInt32(s[i].reloff); s[i].nreloc = OSSwapInt32(s[i].nreloc); s[i].flags = OSSwapInt32(s[i].flags); s[i].reserved1 = OSSwapInt32(s[i].reserved1); s[i].reserved2 = OSSwapInt32(s[i].reserved2); s[i].reserved3 = OSSwapInt32(s[i].reserved3); } }
void swap_routines_command_64( struct routines_command_64 *r_cmd, enum NXByteOrder target_byte_sex) { r_cmd->cmd = OSSwapInt32(r_cmd->cmd); r_cmd->cmdsize = OSSwapInt32(r_cmd->cmdsize); r_cmd->init_address = OSSwapInt64(r_cmd->init_address); r_cmd->init_module = OSSwapInt64(r_cmd->init_module); r_cmd->reserved1 = OSSwapInt64(r_cmd->reserved1); r_cmd->reserved2 = OSSwapInt64(r_cmd->reserved2); r_cmd->reserved3 = OSSwapInt64(r_cmd->reserved3); r_cmd->reserved4 = OSSwapInt64(r_cmd->reserved4); r_cmd->reserved5 = OSSwapInt64(r_cmd->reserved5); r_cmd->reserved6 = OSSwapInt64(r_cmd->reserved6); }
void swap_nlist_64( struct nlist_64 *symbols, uint32_t nsymbols, enum NXByteOrder target_byte_sex) { uint32_t i; for(i = 0; i < nsymbols; i++){ symbols[i].n_un.n_strx = OSSwapInt32(symbols[i].n_un.n_strx); /* n_type */ /* n_sect */ symbols[i].n_desc = OSSwapInt16(symbols[i].n_desc); symbols[i].n_value = OSSwapInt64(symbols[i].n_value); } }
void doseg64(void *start, struct segment_command_64 *seg, bool needsFlip, struct gcinfo *gcip) { if (debug) printf("segment name: %s\n", seg->segname); if (seg->segname[0] && strcmp("__OBJC", seg->segname) && strcmp("__DATA", seg->segname)) return; gcip->hasObjC = true; // lets do sections if (needsFlip) { seg->fileoff = OSSwapInt64(seg->fileoff); seg->nsects = OSSwapInt32(seg->nsects); } int nsects; struct section_64 *sect = (struct section_64 *)(seg + 1); for (int nsects = 0; nsects < seg->nsects; ++nsects) { // sections directly follow dosect64(start, sect + nsects, needsFlip, gcip); } }
void swap_dylib_module_64( struct dylib_module_64 *mods, uint32_t nmods, enum NXByteOrder target_byte_sex) { uint32_t i; for(i = 0; i < nmods; i++){ mods[i].module_name = OSSwapInt32(mods[i].module_name); mods[i].iextdefsym = OSSwapInt32(mods[i].iextdefsym); mods[i].nextdefsym = OSSwapInt32(mods[i].nextdefsym); mods[i].irefsym = OSSwapInt32(mods[i].irefsym); mods[i].nrefsym = OSSwapInt32(mods[i].nrefsym); mods[i].ilocalsym = OSSwapInt32(mods[i].ilocalsym); mods[i].nlocalsym = OSSwapInt32(mods[i].nlocalsym); mods[i].iextrel = OSSwapInt32(mods[i].iextrel); mods[i].nextrel = OSSwapInt32(mods[i].nextrel); mods[i].iinit_iterm = OSSwapInt32(mods[i].iinit_iterm); mods[i].ninit_nterm = OSSwapInt32(mods[i].ninit_nterm); mods[i].objc_module_info_size = OSSwapInt32(mods[i].objc_module_info_size); mods[i].objc_module_info_addr = OSSwapInt64(mods[i].objc_module_info_addr); } }
void swap_i860_thread_state_regs( struct i860_thread_state_regs *cpu, enum NXByteOrder target_byte_sex) { int i; for(i = 0; i < 31; i++) cpu->ireg[i] = OSSwapInt32(cpu->ireg[i]); for(i = 0; i < 30; i++) cpu->freg[i] = OSSwapInt32(cpu->freg[i]); cpu->psr = OSSwapInt32(cpu->psr); cpu->epsr = OSSwapInt32(cpu->epsr); cpu->db = OSSwapInt32(cpu->db); cpu->pc = OSSwapInt32(cpu->pc); cpu->_padding_ = OSSwapInt32(cpu->_padding_); cpu->Mres3 = OSSwapInt64(cpu->Mres3); cpu->Ares3 = OSSwapInt64(cpu->Ares3); cpu->Mres2 = OSSwapInt64(cpu->Mres2); cpu->Ares2 = OSSwapInt64(cpu->Ares2); cpu->Mres1 = OSSwapInt64(cpu->Mres1); cpu->Ares1 = OSSwapInt64(cpu->Ares1); cpu->Ires1 = OSSwapInt64(cpu->Ires1); cpu->Lres3m = OSSwapInt64(cpu->Lres3m); cpu->Lres2m = OSSwapInt64(cpu->Lres2m); cpu->Lres1m = OSSwapInt64(cpu->Lres1m); cpu->KR = OSSwapInt64(cpu->KR); cpu->KI = OSSwapInt64(cpu->KI); cpu->T = OSSwapInt64(cpu->T); cpu->Fsr3 = OSSwapInt32(cpu->Fsr3); cpu->Fsr2 = OSSwapInt32(cpu->Fsr2); cpu->Fsr1 = OSSwapInt32(cpu->Fsr1); cpu->Mergelo32 = OSSwapInt32(cpu->Mergelo32); cpu->Mergehi32 = OSSwapInt32(cpu->Mergehi32); }
IOReturn SamplePCIUserClientClassName::method2( SampleStructForMethod2 * structIn, SampleResultsForMethod2 * structOut, IOByteCount inputSize, IOByteCount * outputSize ) { IOReturn err; IOMemoryDescriptor * memDesc = 0; UInt32 param1 = structIn->parameter1; uint64_t clientAddr = structIn->data_pointer; uint64_t size = structIn->data_length; // Rosetta if (fCrossEndian) { param1 = OSSwapInt32(param1); } IOLog("SamplePCIUserClient::method2(" UInt32_x_FORMAT ")\n", param1); IOLog( "fClientShared->string == \"%s\"\n", fClientShared->string ); structOut->results1 = 0x87654321; // Rosetta if (fCrossEndian) { structOut->results1 = OSSwapInt64(structOut->results1); clientAddr = OSSwapInt64(clientAddr); size = OSSwapInt64(size); } do { #if defined(__ppc__) && (MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_4) // construct a memory descriptor for the out of line client memory // old 32 bit API - this will fail and log a backtrace if the task is 64 bit IOLog("The Pre-Leopard way to construct a memory descriptor\n"); memDesc = IOMemoryDescriptor::withAddress( (vm_address_t) clientAddr, (IOByteCount) size, kIODirectionNone, fTask ); if (memDesc == NULL) { IOLog("IOMemoryDescriptor::withAddress failed\n"); err = kIOReturnVMError; continue; } #else // 64 bit API - works on all tasks, whether 64 bit or 32 bit IOLog("The Leopard and later way to construct a memory descriptor\n"); memDesc = IOMemoryDescriptor::withAddressRange( clientAddr, size, kIODirectionNone, fTask ); if (memDesc == NULL) { IOLog("IOMemoryDescriptor::withAddresswithAddressRange failed\n"); err = kIOReturnVMError; continue; } #endif // Wire it and make sure we can write it err = memDesc->prepare( kIODirectionOutIn ); if (kIOReturnSuccess != err) { IOLog("IOMemoryDescriptor::prepare failed(0x%08x)\n", err); continue; } // Generate a DMA list for the client memory err = fDriver->generateDMAAddresses(memDesc); // Other methods to access client memory: // readBytes/writeBytes allow programmed I/O to/from an offset in the buffer char pioBuffer[ 200 ]; memDesc->readBytes(32, &pioBuffer, sizeof(pioBuffer)); IOLog("readBytes: \"%s\"\n", pioBuffer); // map() will create a mapping in the kernel address space. IOMemoryMap* memMap = memDesc->map(); if (memMap) { char* address = (char *) memMap->getVirtualAddress(); IOLog("kernel mapped: \"%s\"\n", address + 32); memMap->release(); } else { IOLog("memDesc map(kernel) failed\n"); } // this map() will create a mapping in the users (the client of this IOUserClient) address space. #if MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_4 memMap = memDesc->map(fTask, 0, kIOMapAnywhere); #else memMap = memDesc->createMappingInTask(fTask, 0, kIOMapAnywhere); #endif if (memMap) { #if MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_4 IOLog("The pre-Leopard way to construct a memory descriptor\n"); // old 32 bit API - this will truncate and log a backtrace if the task is 64 bit IOVirtualAddress address32 = memMap->getVirtualAddress(); IOLog("user32 mapped: " VirtAddr_FORMAT "\n", address32); #else IOLog("The Leopard and later way to construct a memory descriptor\n"); // new 64 bit API - same for 32 bit and 64 bit client tasks mach_vm_address_t address64 = memMap->getAddress(); IOLog("user64 mapped: 0x%016llx\n", address64); memMap->release(); #endif } else { IOLog("memDesc map(user) failed\n"); } // Done with the I/O now. memDesc->complete( kIODirectionOutIn ); } while ( false ); if (memDesc) memDesc->release(); return err; }
mach_error_t mach_override_ptr( void *originalFunctionAddress, const void *overrideFunctionAddress, void **originalFunctionReentryIsland ) { assert( originalFunctionAddress ); assert( overrideFunctionAddress ); long *originalFunctionPtr = (long*) originalFunctionAddress; mach_error_t err = err_none; #if defined(__ppc__) || defined(__POWERPC__) // Ensure first instruction isn't 'mfctr'. #define kMFCTRMask 0xfc1fffff #define kMFCTRInstruction 0x7c0903a6 long originalInstruction = *originalFunctionPtr; if( !err && ((originalInstruction & kMFCTRMask) == kMFCTRInstruction) ) err = err_cannot_override; #elif defined(__i386__) || defined(__x86_64__) int eatenCount = 0; char originalInstructions[kOriginalInstructionsSize]; uint64_t jumpRelativeInstruction = 0; // JMP Boolean overridePossible = eatKnownInstructions ((unsigned char *)originalFunctionPtr, &jumpRelativeInstruction, &eatenCount, originalInstructions); if (eatenCount > kOriginalInstructionsSize) { //printf ("Too many instructions eaten\n"); overridePossible = false; } if (!overridePossible) err = err_cannot_override; if (err) printf("err = %x %d\n", err, __LINE__); #endif // Make the original function implementation writable. if( !err ) { err = vm_protect( mach_task_self(), (vm_address_t) originalFunctionPtr, sizeof(long), false, (VM_PROT_ALL | VM_PROT_COPY) ); if( err ) err = vm_protect( mach_task_self(), (vm_address_t) originalFunctionPtr, sizeof(long), false, (VM_PROT_DEFAULT | VM_PROT_COPY) ); } if (err) printf("err = %x %d\n", err, __LINE__); // Allocate and target the escape island to the overriding function. BranchIsland *escapeIsland = NULL; if( !err ) err = allocateBranchIsland( &escapeIsland, kAllocateHigh, originalFunctionAddress ); if (err) printf("err = %x %d\n", err, __LINE__); #if defined(__ppc__) || defined(__POWERPC__) if( !err ) err = setBranchIslandTarget( escapeIsland, overrideFunctionAddress, 0 ); // Build the branch absolute instruction to the escape island. long branchAbsoluteInstruction = 0; // Set to 0 just to silence warning. if( !err ) { long escapeIslandAddress = ((long) escapeIsland) & 0x3FFFFFF; branchAbsoluteInstruction = 0x48000002 | escapeIslandAddress; } #elif defined(__i386__) || defined(__x86_64__) if (err) printf("err = %x %d\n", err, __LINE__); if( !err ) err = setBranchIslandTarget_i386( escapeIsland, overrideFunctionAddress, 0 ); if (err) printf("err = %x %d\n", err, __LINE__); // Build the jump relative instruction to the escape island #endif #if defined(__i386__) || defined(__x86_64__) if (!err) { uint32_t addressOffset = ((void*)escapeIsland - (void*)originalFunctionPtr - 5); addressOffset = OSSwapInt32(addressOffset); jumpRelativeInstruction |= 0xE900000000000000LL; jumpRelativeInstruction |= ((uint64_t)addressOffset & 0xffffffff) << 24; jumpRelativeInstruction = OSSwapInt64(jumpRelativeInstruction); } #endif // Optionally allocate & return the reentry island. BranchIsland *reentryIsland = NULL; if( !err && originalFunctionReentryIsland ) { err = allocateBranchIsland( &reentryIsland, kAllocateNormal, NULL); if( !err ) *originalFunctionReentryIsland = reentryIsland; } #if defined(__ppc__) || defined(__POWERPC__) // Atomically: // o If the reentry island was allocated: // o Insert the original instruction into the reentry island. // o Target the reentry island at the 2nd instruction of the // original function. // o Replace the original instruction with the branch absolute. if( !err ) { int escapeIslandEngaged = false; do { if( reentryIsland ) err = setBranchIslandTarget( reentryIsland, (void*) (originalFunctionPtr+1), originalInstruction ); if( !err ) { escapeIslandEngaged = CompareAndSwap( originalInstruction, branchAbsoluteInstruction, (UInt32*)originalFunctionPtr ); if( !escapeIslandEngaged ) { // Someone replaced the instruction out from under us, // re-read the instruction, make sure it's still not // 'mfctr' and try again. originalInstruction = *originalFunctionPtr; if( (originalInstruction & kMFCTRMask) == kMFCTRInstruction) err = err_cannot_override; } } } while( !err && !escapeIslandEngaged ); } #elif defined(__i386__) || defined(__x86_64__) // Atomically: // o If the reentry island was allocated: // o Insert the original instructions into the reentry island. // o Target the reentry island at the first non-replaced // instruction of the original function. // o Replace the original first instructions with the jump relative. // // Note that on i386, we do not support someone else changing the code under our feet if ( !err ) { if( reentryIsland ) err = setBranchIslandTarget_i386( reentryIsland, (void*) ((char *)originalFunctionPtr+eatenCount), originalInstructions ); if ( !err ) atomic_mov64((uint64_t *)originalFunctionPtr, jumpRelativeInstruction); } #endif // Clean up on error. if( err ) { if( reentryIsland ) freeBranchIsland( reentryIsland ); if( escapeIsland ) freeBranchIsland( escapeIsland ); } #if defined(__x86_64__) err = makeIslandExecutable(escapeIsland); err = makeIslandExecutable(reentryIsland); #endif return err; }
uint64_t AJ_ByteSwap64(uint64_t x) { return OSSwapInt64(x); }
void swap_x86_thread_state64( x86_thread_state64_t *cpu, enum NXByteOrder target_byte_sex) { cpu->rax = OSSwapInt64(cpu->rax); cpu->rbx = OSSwapInt64(cpu->rbx); cpu->rcx = OSSwapInt64(cpu->rcx); cpu->rdx = OSSwapInt64(cpu->rdx); cpu->rdi = OSSwapInt64(cpu->rdi); cpu->rsi = OSSwapInt64(cpu->rsi); cpu->rbp = OSSwapInt64(cpu->rbp); cpu->rsp = OSSwapInt64(cpu->rsp); cpu->rflags = OSSwapInt64(cpu->rflags); cpu->rip = OSSwapInt64(cpu->rip); cpu->r8 = OSSwapInt64(cpu->r8); cpu->r9 = OSSwapInt64(cpu->r9); cpu->r10 = OSSwapInt64(cpu->r10); cpu->r11 = OSSwapInt64(cpu->r11); cpu->r12 = OSSwapInt64(cpu->r12); cpu->r13 = OSSwapInt64(cpu->r13); cpu->r14 = OSSwapInt64(cpu->r14); cpu->r15 = OSSwapInt64(cpu->r15); cpu->cs = OSSwapInt64(cpu->cs); cpu->fs = OSSwapInt64(cpu->fs); cpu->gs = OSSwapInt64(cpu->gs); }
mach_error_t __asan_mach_override_ptr_custom( void *originalFunctionAddress, const void *overrideFunctionAddress, void **originalFunctionReentryIsland, island_malloc *alloc, island_free *dealloc) { assert( originalFunctionAddress ); assert( overrideFunctionAddress ); // this addresses overriding such functions as AudioOutputUnitStart() // test with modified DefaultOutputUnit project #if defined(__x86_64__) 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__) for(;;){ if(*(uint16_t*)originalFunctionAddress==0x25FF) // jmp *0x???????? originalFunctionAddress=**(void***)((uint16_t*)originalFunctionAddress+1); else break; } #endif #ifdef DEBUG_DISASM { fprintf(stderr, "Replacing function at %p\n", originalFunctionAddress); fprintf(stderr, "First 16 bytes of the function: "); unsigned char *orig = (unsigned char *)originalFunctionAddress; int i; for (i = 0; i < 16; i++) { fprintf(stderr, "%x ", (unsigned int) orig[i]); } fprintf(stderr, "\n"); fprintf(stderr, "To disassemble, save the following function as disas.c" " and run:\n gcc -c disas.c && gobjdump -d disas.o\n" "The first 16 bytes of the original function will start" " after four nop instructions.\n"); fprintf(stderr, "\nvoid foo() {\n asm volatile(\"nop;nop;nop;nop;\");\n"); int j = 0; for (j = 0; j < 2; j++) { fprintf(stderr, " asm volatile(\".byte "); for (i = 8 * j; i < 8 * (j+1) - 1; i++) { fprintf(stderr, "0x%x, ", (unsigned int) orig[i]); } fprintf(stderr, "0x%x;\");\n", (unsigned int) orig[8 * (j+1) - 1]); } fprintf(stderr, "}\n\n"); } #endif long *originalFunctionPtr = (long*) originalFunctionAddress; mach_error_t err = err_none; #if defined(__ppc__) || defined(__POWERPC__) // Ensure first instruction isn't 'mfctr'. #define kMFCTRMask 0xfc1fffff #define kMFCTRInstruction 0x7c0903a6 long originalInstruction = *originalFunctionPtr; if( !err && ((originalInstruction & kMFCTRMask) == kMFCTRInstruction) ) 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, &originalInstructionCount, originalInstructionSizes ); #ifdef DEBUG_DISASM if (!overridePossible) fprintf(stderr, "overridePossible = false @%d\n", __LINE__); #endif if (eatenCount > kOriginalInstructionsSize) { #ifdef DEBUG_DISASM fprintf(stderr, "Too many instructions eaten\n"); #endif overridePossible = false; } if (!overridePossible) err = err_cannot_override; if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__); #endif // Make the original function implementation writable. if( !err ) { err = vm_protect( mach_task_self(), (vm_address_t) originalFunctionPtr, 8, false, (VM_PROT_ALL | VM_PROT_COPY) ); if( err ) err = vm_protect( mach_task_self(), (vm_address_t) originalFunctionPtr, 8, false, (VM_PROT_DEFAULT | VM_PROT_COPY) ); } if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__); // Allocate and target the escape island to the overriding function. BranchIsland *escapeIsland = NULL; if( !err ) err = alloc( (void**)&escapeIsland, sizeof(BranchIsland), originalFunctionAddress ); if ( err ) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__); #if defined(__ppc__) || defined(__POWERPC__) if( !err ) err = setBranchIslandTarget( escapeIsland, overrideFunctionAddress, 0 ); // Build the branch absolute instruction to the escape island. long branchAbsoluteInstruction = 0; // Set to 0 just to silence warning. if( !err ) { long escapeIslandAddress = ((long) escapeIsland) & 0x3FFFFFF; branchAbsoluteInstruction = 0x48000002 | escapeIslandAddress; } #elif defined(__i386__) || defined(__x86_64__) if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__); if( !err ) err = setBranchIslandTarget_i386( escapeIsland, overrideFunctionAddress, 0 ); if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__); // Build the jump relative instruction to the escape island #endif #if defined(__i386__) || defined(__x86_64__) if (!err) { uint32_t addressOffset = ((char*)escapeIsland - (char*)originalFunctionPtr - 5); addressOffset = OSSwapInt32(addressOffset); jumpRelativeInstruction |= 0xE900000000000000LL; jumpRelativeInstruction |= ((uint64_t)addressOffset & 0xffffffff) << 24; jumpRelativeInstruction = OSSwapInt64(jumpRelativeInstruction); } #endif // 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 = alloc( (void**)&reentryIsland, sizeof(BranchIsland), escapeIsland); if( !err ) *originalFunctionReentryIsland = reentryIsland; } #if defined(__ppc__) || defined(__POWERPC__) // Atomically: // o If the reentry island was allocated: // o Insert the original instruction into the reentry island. // o Target the reentry island at the 2nd instruction of the // original function. // o Replace the original instruction with the branch absolute. if( !err ) { int escapeIslandEngaged = false; do { if( reentryIsland ) err = setBranchIslandTarget( reentryIsland, (void*) (originalFunctionPtr+1), originalInstruction ); if( !err ) { escapeIslandEngaged = CompareAndSwap( originalInstruction, branchAbsoluteInstruction, (UInt32*)originalFunctionPtr ); if( !escapeIslandEngaged ) { // Someone replaced the instruction out from under us, // re-read the instruction, make sure it's still not // 'mfctr' and try again. originalInstruction = *originalFunctionPtr; if( (originalInstruction & kMFCTRMask) == kMFCTRInstruction) err = err_cannot_override; } } } while( !err && !escapeIslandEngaged ); } #elif defined(__i386__) || defined(__x86_64__) // Atomically: // o If the reentry island was allocated: // o Insert the original instructions into the reentry island. // o Target the reentry island at the first non-replaced // instruction of the original function. // o Replace the original first instructions with the jump relative. // // 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 ); // try making islands executable before planting the jmp #if defined(__x86_64__) || defined(__i386__) if( !err ) err = makeIslandExecutable(escapeIsland); if( !err && reentryIsland ) err = makeIslandExecutable(reentryIsland); #endif if ( !err ) atomic_mov64((uint64_t *)originalFunctionPtr, jumpRelativeInstruction); } #endif // Clean up on error. if( err ) { if( reentryIsland ) dealloc( reentryIsland ); if( escapeIsland ) dealloc( escapeIsland ); } #ifdef DEBUG_DISASM { fprintf(stderr, "First 16 bytes of the function after slicing: "); unsigned char *orig = (unsigned char *)originalFunctionAddress; int i; for (i = 0; i < 16; i++) { fprintf(stderr, "%x ", (unsigned int) orig[i]); } fprintf(stderr, "\n"); } #endif return err; }
IOReturn AppleUHCIIsochTransferDescriptor::UpdateFrameList(AbsoluteTime timeStamp) { UInt32 statFlags; IOUSBIsocFrame *pFrames; IOUSBLowLatencyIsocFrame *pLLFrames; IOReturn frStatus = kIOReturnSuccess; UInt16 frActualCount = 0; UInt16 frReqCount; statFlags = USBToHostLong(GetSharedLogical()->ctrlStatus); frActualCount = UHCI_TD_GET_ACTLEN(statFlags); // warning - this method can run at primary interrupt time, which can cause a panic if it logs too much // USBLog(7, "AppleUHCIIsochTransferDescriptor[%p]::UpdateFrameList statFlags (%x)", this, statFlags); pFrames = _pFrames; if (!pFrames) // this will be the case for the dummy TD return kIOReturnSuccess; pLLFrames = (IOUSBLowLatencyIsocFrame*)_pFrames; if (_lowLatency) { frReqCount = pLLFrames[_frameIndex].frReqCount; } else { frReqCount = pFrames[_frameIndex].frReqCount; } if (statFlags & kUHCI_TD_ACTIVE) { frStatus = kIOUSBNotSent2Err; } else if (statFlags & kUHCI_TD_CRCTO) { frStatus = kIOReturnNotResponding; } else if (statFlags & kUHCI_TD_DBUF) // data buffer (PCI error) { if (_pEndpoint->direction == kUSBOut) frStatus = kIOUSBBufferUnderrunErr; else frStatus = kIOUSBBufferOverrunErr; } else if (statFlags & kUHCI_TD_BABBLE) { if (_pEndpoint->direction == kUSBOut) frStatus = kIOReturnNotResponding; // babble on OUT. this should never happen else frStatus = kIOReturnOverrun; } else if (statFlags & kUHCI_TD_STALLED) // if STALL happens on Isoch, it is most likely covered by one of the other bits above { frStatus = kIOUSBWrongPIDErr; } else { if (frActualCount != frReqCount) { if (_pEndpoint->direction == kUSBOut) { // warning - this method can run at primary interrupt time, which can cause a panic if it logs too much // USBLog(7, "AppleUHCIIsochTransferDescriptor[%p]::UpdateFrameList - (OUT) reqCount (%d) actCount (%d)", this, frReqCount, frActualCount); frStatus = kIOUSBBufferUnderrunErr; // this better have generated a DBUF or other error } else if (_pEndpoint->direction == kUSBIn) { // warning - this method can run at primary interrupt time, which can cause a panic if it logs too much // USBLog(7, "AppleUHCIIsochTransferDescriptor[%p]::UpdateFrameList - (IN) reqCount (%d) actCount (%d)", this, frReqCount, frActualCount); frStatus = kIOReturnUnderrun; // benign error } } } if (alignBuffer && alignBuffer->userBuffer && alignBuffer->vaddr && (_pEndpoint->direction == kUSBIn)) { // i can't log in here because this is called at interrupt time // i know that this is OK for Low Latency because the buffer will be allocated in low memory and wont' be bounced alignBuffer->userBuffer->writeBytes(alignBuffer->userOffset, (void*)alignBuffer->vaddr, frActualCount); alignBuffer->actCount = frActualCount; } if (_lowLatency) { if ( _requestFromRosettaClient ) { pLLFrames[_frameIndex].frActCount = OSSwapInt16(frActualCount); pLLFrames[_frameIndex].frReqCount = OSSwapInt16(pLLFrames[_frameIndex].frReqCount); AbsoluteTime_to_scalar(&pLLFrames[_frameIndex].frTimeStamp) = OSSwapInt64(AbsoluteTime_to_scalar(&timeStamp)); pLLFrames[_frameIndex].frStatus = OSSwapInt32(frStatus); } else { pLLFrames[_frameIndex].frActCount = frActualCount; pLLFrames[_frameIndex].frTimeStamp = timeStamp; pLLFrames[_frameIndex].frStatus = frStatus; #ifdef __LP64__ USBTrace( kUSBTUHCIInterrupts, kTPUHCIUpdateFrameList , (uintptr_t)((_pEndpoint->direction << 24) | ( _pEndpoint->functionAddress << 8) | _pEndpoint->endpointNumber), (uintptr_t)&pLLFrames[_frameIndex], (uintptr_t)frActualCount, (uintptr_t)timeStamp ); #else USBTrace( kUSBTUHCIInterrupts, kTPUHCIUpdateFrameList , (uintptr_t)((_pEndpoint->direction << 24) | ( _pEndpoint->functionAddress << 8) | _pEndpoint->endpointNumber), (uintptr_t)&pLLFrames[_frameIndex], (uintptr_t)(timeStamp.hi), (uintptr_t)timeStamp.lo ); #endif } } else { if ( _requestFromRosettaClient ) { pFrames[_frameIndex].frActCount = OSSwapInt16(frActualCount); pFrames[_frameIndex].frReqCount = OSSwapInt16(pFrames[_frameIndex].frReqCount); pFrames[_frameIndex].frStatus = OSSwapInt32(frStatus); } else { pFrames[_frameIndex].frActCount = frActualCount; pFrames[_frameIndex].frStatus = frStatus; } } if (frStatus != kIOReturnSuccess) { if (frStatus != kIOReturnUnderrun) { _pEndpoint->accumulatedStatus = frStatus; } else if (_pEndpoint->accumulatedStatus == kIOReturnSuccess) { _pEndpoint->accumulatedStatus = kIOReturnUnderrun; } } return frStatus; }
mach_error_t mach_override_ptr( void *originalFunctionAddress, const void *overrideFunctionAddress, void **originalFunctionReentryIsland ) { assert( originalFunctionAddress ); assert( overrideFunctionAddress ); // this addresses overriding such functions as AudioOutputUnitStart() // test with modified DefaultOutputUnit project #if defined(__x86_64__) 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__) for(;;){ if(*(uint16_t*)originalFunctionAddress==0x25FF) // jmp *0x???????? originalFunctionAddress=**(void***)((uint16_t*)originalFunctionAddress+1); else break; } #endif long *originalFunctionPtr = (long*) originalFunctionAddress; mach_error_t err = err_none; #if defined(__ppc__) || defined(__POWERPC__) // Ensure first instruction isn't 'mfctr'. #define kMFCTRMask 0xfc1fffff #define kMFCTRInstruction 0x7c0903a6 long originalInstruction = *originalFunctionPtr; if( !err && ((originalInstruction & kMFCTRMask) == kMFCTRInstruction) ) 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, &originalInstructionCount, originalInstructionSizes ); if (eatenCount + kMaxFixupSizeIncrease > kOriginalInstructionsSize) { //printf ("Too many instructions eaten\n"); overridePossible = false; } if (!overridePossible) err = err_cannot_override; if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__); #endif // Make the original function implementation writable. if( !err ) { err = vm_protect( mach_task_self(), (vm_address_t) originalFunctionPtr, 8, false, (VM_PROT_ALL | VM_PROT_COPY) ); if( err ) err = vm_protect( mach_task_self(), (vm_address_t) originalFunctionPtr, 8, false, (VM_PROT_DEFAULT | VM_PROT_COPY) ); } if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__); // Allocate and target the escape island to the overriding function. BranchIsland *escapeIsland = NULL; if( !err ) err = allocateBranchIsland( &escapeIsland, originalFunctionAddress ); if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__); #if defined(__ppc__) || defined(__POWERPC__) if( !err ) err = setBranchIslandTarget( escapeIsland, overrideFunctionAddress, 0 ); // Build the branch absolute instruction to the escape island. long branchAbsoluteInstruction = 0; // Set to 0 just to silence warning. if( !err ) { long escapeIslandAddress = ((long) escapeIsland) & 0x3FFFFFF; branchAbsoluteInstruction = 0x48000002 | escapeIslandAddress; } #elif defined(__i386__) || defined(__x86_64__) if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__); if( !err ) err = setBranchIslandTarget_i386( escapeIsland, overrideFunctionAddress, 0 ); if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__); // Build the jump relative instruction to the escape island #endif #if defined(__i386__) || defined(__x86_64__) if (!err) { uint32_t addressOffset = ((char*)escapeIsland - (char*)originalFunctionPtr - 5); addressOffset = OSSwapInt32(addressOffset); jumpRelativeInstruction |= 0xE900000000000000LL; jumpRelativeInstruction |= ((uint64_t)addressOffset & 0xffffffff) << 24; jumpRelativeInstruction = OSSwapInt64(jumpRelativeInstruction); } #endif // 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, escapeIsland); if( !err ) *originalFunctionReentryIsland = reentryIsland; } #if defined(__ppc__) || defined(__POWERPC__) // Atomically: // o If the reentry island was allocated: // o Insert the original instruction into the reentry island. // o Target the reentry island at the 2nd instruction of the // original function. // o Replace the original instruction with the branch absolute. if( !err ) { int escapeIslandEngaged = false; do { if( reentryIsland ) err = setBranchIslandTarget( reentryIsland, (void*) (originalFunctionPtr+1), originalInstruction ); if( !err ) { escapeIslandEngaged = CompareAndSwap( originalInstruction, branchAbsoluteInstruction, (UInt32*)originalFunctionPtr ); if( !escapeIslandEngaged ) { // Someone replaced the instruction out from under us, // re-read the instruction, make sure it's still not // 'mfctr' and try again. originalInstruction = *originalFunctionPtr; if( (originalInstruction & kMFCTRMask) == kMFCTRInstruction) err = err_cannot_override; } } } while( !err && !escapeIslandEngaged ); } #elif defined(__i386__) || defined(__x86_64__) // Atomically: // o If the reentry island was allocated: // o Insert the original instructions into the reentry island. // o Target the reentry island at the first non-replaced // instruction of the original function. // o Replace the original first instructions with the jump relative. // // Note that on i386, we do not support someone else changing the code under our feet if ( !err ) { uint32_t offset = (uintptr_t)originalFunctionPtr - (uintptr_t)reentryIsland; fixupInstructions(offset, originalInstructions, originalInstructionCount, originalInstructionSizes ); if( reentryIsland ) err = setBranchIslandTarget_i386( reentryIsland, (void*) ((char *)originalFunctionPtr+eatenCount), originalInstructions ); // try making islands executable before planting the jmp #if defined(__x86_64__) || defined(__i386__) if( !err ) err = makeIslandExecutable(escapeIsland); if( !err && reentryIsland ) err = makeIslandExecutable(reentryIsland); #endif if ( !err ) atomic_mov64((uint64_t *)originalFunctionPtr, jumpRelativeInstruction); } #endif // Clean up on error. if( err ) { if( reentryIsland ) freeBranchIsland( reentryIsland ); if( escapeIsland ) freeBranchIsland( escapeIsland ); } return err; }
size_t decompress_lzvn(void * _dest, size_t _dest_size, void * _src, size_t _src_size) { size_t rax = 0; const uint64_t rdi = (const uint64_t)_dest; uint64_t rsi = _dest_size; uint64_t rcx = _src_size; uint64_t rdx = (uint64_t)_src; uint64_t r8 = 0; uint64_t r9 = 0; uint64_t r10 = 0; uint64_t r11 = 0; uint64_t r12 = 0; uint64_t addr = 0; unsigned char byte_data = 0; short jmp = 0; // lea Llzvn_tableref(%rip),%rbx // // this will load the address of the tableref label into the %rbx // register. in our code, this is the 'Llzvn_tableref' array // // for clearness, it will be used directly. rax = 0; // xor %rax,%rax r12 = 0; // xor %r12,%r12 // sub $0x8,%rsi // jb Llzvn_exit jmp = rsi < 0x8 ? 1 : 0; rsi -= 0x8; if (jmp) { return 0; } // lea -0x8(%rdx,%rcx,1),%rcx // cmp %rcx,%rdx // ja Llzvn_exit rcx = rdx + rcx - 0x8; if (rdx > rcx) { return 0; } LABEL_JUMP; Llzvn_table0: r9 >>= 0x6; // shr $0x6,%r9 rdx = rdx + r9 + 0x1; // lea 0x1(%rdx,%r9,1),%rdx // cmp %rcx,%rdx // ja Llzvn_exit if (rdx > rcx) { return 0; } r10 = 0x38; // mov $0x38,%r10 r10 &= r8; // and %r8,%r10 r8 >>= 0x8; // shr $0x8,%r8 r10 >>= 0x3; // shr $0x3,%r10 r10 += 0x3; // add $0x3,%r10 goto Llzvn_l10; // jmp Llzvn_l10 Llzvn_table1: r9 >>= 0x6; // shr $0x6,%r9 rdx = rdx + r9 + 0x2; // lea 0x2(%rdx,%r9,1),%rdx // cmp %rcx,%rdx // ja Llzvn_exit if (rdx > rcx) { return 0; } r12 = r8; // mov %r8,%r12 r12 = OSSwapInt64(r12); // bswap %r12 r10 = r12; // mov %r12,%r10 r12 <<= 0x5; // shl $0x5,%r12 r12 >>= 0x35; // shr $0x35,%r12 r10 <<= 0x2; // shl $0x2,%r10 r10 >>= 0x3d; // shr $0x3d,%r10 r10 += 0x3; // add $0x3,%r10 r8 >>= 0x10; // shr $0x10,%r8 goto Llzvn_l10; Llzvn_table3: r9 >>= 0x6; // shr $0x6,%r9 rdx = rdx + r9 + 0x3; // lea 0x3(%rdx,%r9,1),%rdx // cmp %rcx,%rdx // ja Llzvn_exit if (rdx > rcx) { return 0; } r10 = 0x38; // mov $0x38,%r10 r12 = 0xFFFF; // mov $0xffff,%r12 r10 &= r8; // and %r8,%r10 r8 >>= 0x8; // shr $0x8,%r8 r10 >>= 0x3; // shr $0x3,%r10 r12 &= r8; // and %r8,%r12 r8 >>= 0x10; // shr $0x10,%r8 r10 += 0x3; // add $0x3,%r10 goto Llzvn_l10; // jmp Llzvn_l10 Llzvn_table4: // add $0x1,%rdx // cmp %rcx,%rdx // ja Llzvn_exit rdx += 1; if (rdx > rcx) { return 0; } LABEL_JUMP; Llzvn_table6: r9 >>= 0x3; // shr $0x3,%r9 r9 &= 0x3; // and $0x3,%r9 rdx = rdx + r9 + 0x3; // lea 0x3(%rdx,%r9,1),%rdx // cmp %rcx,%rdx // ja Llzvn_exit if (rdx > rcx) { return 0; } r10 = r8; // mov %r8,%r10 r10 &= 0x307; // and $0x307,%r10 r8 >>= 0xa; // shr $0xa,%r8 // movzbq %r10b,%r12 r12 = r10 & 0xFF; r10 >>= 0x8; // shr $0x8,%r10 r12 <<= 0x2; // shl $0x2,%r12 r10 |= r12; // or %r12,%r10 r12 = 0x3FFF; // mov $0x3fff,%r12 r10 += 0x3; // add $0x3,%r10 r12 &= r8; // and %r8,%r12 r8 >>= 0xE; // shr $0xe,%r8 goto Llzvn_l10; // jmp Llzvn_l10 Llzvn_table7: r8 >>= 0x8; // shr $0x8,%r8 r8 &= 0xFF; // and $0xff,%r8 r8 += 0x10; // add $0x10,%r8 rdx = rdx + r8 + 0x2; // lea 0x2(%rdx,%r8,1),%rdx goto Llzvn_l0; Llzvn_table8: r8 &= 0xF; // and $0xf,%r8 rdx = rdx + r8 + 0x1; // lea 0x1(%rdx,%r8,1),%rdx goto Llzvn_l0; // jmp Llzvn_l0 Llzvn_table9: rdx += 0x2; // add $0x2,%rdx // cmp %rcx,%rdx // ja Llzvn_exit if (rdx > rcx) { return 0; } r10 = r8; // mov %r8,%r10 r10 >>= 0x8; // shr $0x8,%r10 r10 &= 0xFF; // and $0xff,%r10 r10 += 0x10; // add $0x10,%r10 goto Llzvn_l11; Llzvn_table10: rdx += 1; // add $0x1,%rdx //cmp %rcx,%rdx //ja Llzvn_exit if (rdx > rcx) { return 0; } r10 = r8; // mov %r8,%r10 r10 &= 0xF; // and $0xf,%r10 goto Llzvn_l11; // jmp Llzvn_l11 Llzvn_l10: r11 = rax + r9; // lea (%rax,%r9,1),%r11 r11 += r10; // add %r10,%r11 // cmp %rsi,%r11 // jae Llzvn_l8 if (r11 >= rsi) { goto Llzvn_l8; } // mov %r8,(%rdi,%rax,1) addr = rdi + rax; *((uint64_t *)addr) = r8; rax += r9; // add %r9,%rax r8 = rax; // mov %rax,%r8 // sub %r12,%r8 // jb Llzvn_exit jmp = r8 < r12 ? 1 : 0; r8 -= r12; if (jmp) { return 0; } // cmp $0x8,%r12 // jb Llzvn_l4 if (r12 < 0x8) { goto Llzvn_l4; } Llzvn_l5: do { // mov (%rdi,%r8,1),%r9 addr = rdi + r8; r9 = *((uint64_t *)addr); r8 += 0x8; // add $0x8,%r8 // mov %r9,(%rdi,%rax,1) addr = rdi + rax; *((uint64_t *)addr) = r9; rax += 0x8; // add $0x8,%rax // sub $0x8,%r10 // ja Llzvn_l5 jmp = r10 > 0x8 ? 1 : 0; r10 -= 0x8; } while (jmp); rax += r10; // add %r10,%rax LABEL_JUMP; Llzvn_l8: // test %r9,%r9 // je Llzvn_l7 if (r9 != 0) { r11 = rsi + 0x8; // lea 0x8(%rsi),%r11 do { // mov %r8b,(%rdi,%rax,1) addr = rdi + rax; byte_data = (unsigned char)(r8 & 0xFF); *((unsigned char *)addr) = byte_data; rax += 0x1; // add $0x1,%rax // cmp %rax,%r11 // je Llzvn_exit2 if (rax == r11) { return rax; } r8 >>= 0x8; // shr $0x8,%r8 // sub $0x1,%r9 // jne Llzvn_l6 jmp = r9 != 0x1 ? 1 : 0; r9 -= 1; } while (jmp); }