/* * Original idea of patching kernel by Evan Lojewsky, 2009 * * Copyright (c) 2011-2012 Frank Peng. All rights reserved. * * 2012 - 2020 Correction and improvements by Clover team */ //#include #include #include // Only use angled for Platform, else, xcode project won't compile //#include "LoaderUefi.h" #include "Nvram.h" #include "FixBiosDsdt.h" #include "cpu.h" #include "kext_inject.h" #include "kernel_patcher.h" //#include "sse3_patcher.h" //#include "sse3_5_patcher.h" #ifndef DEBUG_ALL #define KERNEL_DEBUG 1 #else #define KERNEL_DEBUG DEBUG_ALL #endif #if KERNEL_DEBUG == 2 #define DBG(...) printf(__VA_ARGS__); #elif KERNEL_DEBUG == 1 #define DBG(...) DebugLog(KERNEL_DEBUG, __VA_ARGS__) #else #define DBG(...) #endif // runtime debug //make it a member of LOADER_ENTRY class entry.DBG_RT(...) //#define DBG_RT( ...) if ((KernelAndKextPatches != NULL) && KernelAndKextPatches.KPDebug) { printf(__VA_ARGS__); } //EFI_PHYSICAL_ADDRESS KernelRelocBase = 0; //BootArgs1 *bootArgs1 = NULL; //BootArgs2 *bootArgs2 = NULL; //CHAR8 *dtRoot = NULL; //UINT32 *dtLength; //UINT8 *KernelData = NULL; //UINT32 KernelSlide = 0; //BOOLEAN isKernelcache = FALSE; //BOOLEAN is64BitKernel = FALSE; //BOOLEAN SSSE3; //BOOLEAN PatcherInited = FALSE; //BOOLEAN gSNBEAICPUFixRequire = FALSE; // SandyBridge-E AppleIntelCpuPowerManagement patch require or not //BOOLEAN gBDWEIOPCIFixRequire = FALSE; // Broadwell-E IOPCIFamily fix require or not extern EFI_GUID gEfiAppleBootGuid; /* * the driver OsxAptioFixDrv is old and mostly not used in favour of its successors. * anyway we will keep it for new investigations. */ VOID LOADER_ENTRY::SetKernelRelocBase() { // EFI_STATUS Status; UINTN DataSize = sizeof(KernelRelocBase); KernelRelocBase = 0; // OsxAptioFixDrv will set this /*Status = */gRT->GetVariable(L"OsxAptioFixDrv-RelocBase", &gEfiAppleBootGuid, NULL, &DataSize, &KernelRelocBase); DeleteNvramVariable(L"OsxAptioFixDrv-RelocBase", &gEfiAppleBootGuid); // clean up the temporary variable // KernelRelocBase is now either read or 0 return; } //Slice // the purpose of the procedure is to find a table of symbols in the shifted kernel EFI_STATUS LOADER_ENTRY::getVTable() { DBG("kernel at 0x%llx\n", (UINTN)KernelData); // INT32 LinkAdr = FindBin(KernelData, 0x3000, (const UINT8 *)kLinkEditSegment, (UINT32)strlen(kLinkEditSegment)); // if (LinkAdr == -1) { // DBG("no LinkEdit\n"); // return EFI_NOT_FOUND; // } // const UINT8 vtable[] = {0x04, 00,00,00, 0x0F, 0x08, 00, 00}; // const UINT8 vtableSur[] = {0x25, 00,00,00, 0x0F, 0x06, 00, 00}; //25000000 0F060000 940BFF00 80FFFFFF //00FFFFFF FF0FFFFF 00000000 FFFFFFFF // INT32 Tabble = FindBin(KernelData, 0x5000000, vtableSur, 8); INT32 NTabble = FindBin(KernelData, KERNEL_MAX_SIZE, (const UINT8 *)ctor_used, (UINT32)strlen(ctor_used)); DBG("ctor_used found at 0x%x\n", NTabble); if (NTabble < 0) { return EFI_NOT_FOUND; } while (KernelData[NTabble] || KernelData[NTabble-1]) --NTabble; NTabble &= ~0x03; //align, may be 0x07? // NTabble -=4; DBG(" NTabble=%x\n", NTabble); // DBG("LinkAdr=%x NTabble=%x Tabble=%x\n",LinkAdr, NTabble, Tabble); // SEGMENT *LinkSeg = (SEGMENT*)&KernelData[LinkAdr]; // AddrVtable = LinkSeg->AddrVtable; // SizeVtable = LinkSeg->SizeVtable; // NamesTable = LinkSeg->AddrNames; //TODO find an origin of the shift shift = NamesTable - NTabble; // DBG_RT("AddrVtable=%x Size=%x AddrNames=%x shift=%x\n", AddrVtable, SizeVtable, NamesTable, shift); NamesTable = NTabble; AddrVtable -= shift; // AddrVtable = Tabble; DBG("AddrVtable=%x Size=%x AddrNames=%x shift=%x\n", AddrVtable, SizeVtable, NamesTable, shift); SegVAddr = FindBin(KernelData+KernelOffset, 0x600, (const UINT8 *)kTextSegment, (UINT32)strlen(kTextSegment)); SegVAddr += KernelOffset; DBG("SegVAddr=0x%x\n", SegVAddr); return EFI_SUCCESS; } UINT32 LOADER_ENTRY::searchSectionByNum(UINT8 * binary, UINT32 Num) { UINT32 ncmds, cmdsize; UINT32 binaryIndex; UINT32 currsect = 0; UINT32 nsect; UINT32 textAddr = 0; // Init to avoid warning struct segment_command_64 *loadCommand; // struct symtab_command *symCmd; if (!Num) { return 0; } ncmds = MACH_GET_NCMDS(binary); binaryIndex = sizeof(struct mach_header_64); //20 DBG("segSize=0x%lx secsize=0x%lx\n", sizeof(struct segment_command_64), sizeof(struct section_64)); //48, 50 for (UINTN cnt = 0; cnt < ncmds; cnt++) { loadCommand = (struct segment_command_64 *)(binary + binaryIndex); //20, 158 cmdsize = loadCommand->cmdsize; //138, 278 switch (loadCommand->cmd) { case LC_SEGMENT_64: nsect = loadCommand->nsects; //3, 7, if (currsect == 0) { textAddr = binaryIndex + sizeof(struct segment_command_64); //20+48=68 } if (currsect + nsect >= Num - 1) { //3+7 >= 9 UINT32 sectAddr = binaryIndex + sizeof(struct segment_command_64) + sizeof(struct section_64) * (Num - currsect - 1); //158+48+50* if (*(UINT32*)(binary + sectAddr) == 0x73625F5F) { //special case for __bss DBG("__bss will be used as __text\n"); return textAddr; } return sectAddr; } currsect += nsect; //3 break; default: break; } binaryIndex += cmdsize; //20+138=158, } return 0; } UINTN LOADER_ENTRY::searchProcInDriver(UINT8 * driver, UINT32 driverLen, const XString8& procedure) { if (procedure.isEmpty()) { return 0; } /* INT32 LinkAdr = FindBin(driver, driverLen, (const UINT8 *)kLinkEditSegment, (UINT32)strlen(kLinkEditSegment)); if (LinkAdr == -1) { return 0; } SEGMENT *LinkSeg = (SEGMENT*)&driver[LinkAdr]; // INT32 lAddrVtable = LinkSeg->AddrVtable; INT32 lSizeVtable = LinkSeg->SizeVtable; // INT32 lNamesTable = LinkSeg->AddrNames; const char* Names = (const char*)(&driver[LinkSeg->AddrNames]); VTABLE * vArray = (VTABLE*)(&driver[LinkSeg->AddrVtable]); struct nlist_64 { union { uint32_t n_strx; // index into the string table //str_adr=stroff+n_strx } n_un; uint8_t n_type; // type flag, see below uint8_t n_sect; // section number or NO_SECT uint16_t n_desc; // see uint64_t n_value; // value of this symbol (or stab offset) }; */ DBG("search procedure %s\n", procedure.c_str()); struct nlist_64 * vArray = NULL; INT32 lSizeVtable = 0; const char* Names = NULL; struct symtab_command *symCmd = NULL; UINT32 symCmdOffset = Get_Symtab(driver); DBG("symCmdOffset=0x%X\n", symCmdOffset); //0x418 if (symCmdOffset != 0) { if ((((struct mach_header_64*)KernelData)->filetype) == MH_KERNEL_COLLECTION) { symCmd = (struct symtab_command *)&driver[symCmdOffset]; vArray = (struct nlist_64*)(&KernelData[symCmd->symoff - shift]); lSizeVtable = symCmd->nsyms; Names = (const char*)(&KernelData[symCmd->stroff - shift]); DBG("driverKC: AddrVtable=0x%x SizeVtable=0x%x NamesTable=0x%x\n", symCmd->symoff - shift, lSizeVtable, symCmd->stroff - shift); } else { symCmd = (struct symtab_command *)&driver[symCmdOffset]; vArray = (struct nlist_64*)(&driver[symCmd->symoff]); lSizeVtable = symCmd->nsyms; Names = (const char*)(&driver[symCmd->stroff]); DBG("driver: AddrVtable=0x%x SizeVtable=0x%x NamesTable=0x%x\n", symCmd->symoff, lSizeVtable, symCmd->stroff); } } if (!vArray || !lSizeVtable || !Names) { return 0; } INT32 i; UINT32 Offset = 0; // Init to avoid warning bool found = false; for (i = 0; i < lSizeVtable; ++i) { Offset = vArray[i].n_un.n_strx; if (strstr(&Names[Offset], procedure.c_str())) { found = true; break; } } if (!found) { DBG("%s not found\n", procedure.c_str()); return 0; } DBG("found section %d at pos=%d\n", vArray[i].n_sect, i); DBG("name offset=0x%x vtable_off=0x%lx\n", symCmd->stroff + Offset, symCmd->symoff + i * sizeof(struct nlist_64)); // INT32 textAddr = searchSectionByNum(driver, 1); INT32 lSegVAddr = searchSectionByNum(driver, vArray[i].n_sect); // DBG("section begin:\n"); // for (int j=0; j<20; ++j) { // DBG("%02X", driver[lSegVAddr+j]); // } // DBG("\n"); /* switch (vArray[i].Seg) { case ID_SEG_DATA: lSegVAddr = FindBin(driver, 0x1600, (const UINT8 *)kDataSegment, (UINT32)strlen(kDataSegment)); break; case ID_SEG_DATA_CONST: case ID_SEC_CONST: lSegVAddr = FindSection(driver, 0x1600, (const UINT8 *)kDataSegment, (const UINT8 *)kConstSection); break; case ID_SEG_TEXT_CONST: lSegVAddr = FindSection(driver, 0x1600, (const UINT8 *)kTextSegment, (const UINT8 *)kConstSection); break; case ID_SEG_DATA_COMMON: lSegVAddr = FindSection(driver, 0x1600, (const UINT8 *)kDataSegment, (const UINT8 *)kCommonSection); break; case ID_SEG_DATA_DATA2: case ID_SEG_DATA_DATA: lSegVAddr = FindSection(driver, 0x1600, (const UINT8 *)kDataSegment, (const UINT8 *)kDataSection); break; case ID_SEG_KLD: case ID_SEG_KLD2: case ID_SEG_KLD3: lSegVAddr = FindBin(driver, 0x2000, (const UINT8 *)kKldSegment, (UINT32)strlen(kKldSegment)); break; // case ID_SEC_BSS: // lSegVAddr = FindSection(driver, 0x1600, (const UINT8 *)kDataSegment, (const UINT8 *)kBssSection); // break; case ID_SEC_BSS: //it works this way case ID_SEG_TEXT: case ID_SEG_TEXT2: lSegVAddr = FindSection(driver, 0x600, (const UINT8 *)kTextSegment, (const UINT8 *)kPrelinkTextSection); break; case ID_SEG_HIB: lSegVAddr = FindBin(driver, 0x2000, (const UINT8 *)kHibSegment, (UINT32)strlen(kHibSegment)); break; // lSegVAddr = FindBin(driver, 0x600, (const UINT8 *)kTextSegment, (UINT32)strlen(kTextSegment)); // break; default: return vArray[i].ProcAddr; } if (lSegVAddr == 0) { lSegVAddr = 0x38; } SEGMENT *TextSeg = (SEGMENT*)&driver[lSegVAddr]; */ struct section_64 *TextSeg = (struct section_64*)&driver[lSegVAddr]; UINT64 Absolut = TextSeg->addr; UINT64 FileOff = TextSeg->offset; DBG("Absolut=0x%llx Fileoff=0x%llx\n", Absolut, FileOff); UINTN procAddr = vArray[i].n_value - Absolut + FileOff; // UINT32 procAddr32 = (UINT32)(vArray[i].n_value); //it is not work if ((((struct mach_header_64*)KernelData)->filetype) == MH_KERNEL_COLLECTION) { procAddr -= shift; } DBG("procAddr=0x%llx\n", procAddr); #if KERNEL_DEBUG if (Absolut != 0) { UINT8 *procVM; if ((((struct mach_header_64*)KernelData)->filetype) == MH_KERNEL_COLLECTION) { procVM = (UINT8*)&KernelData[procAddr]; } else { procVM = (UINT8*)&driver[procAddr]; } DBG("procedure begin:\n"); for (int j=0; j<30; ++j) { DBG("%02X", procVM[j]); } DBG("\n"); } #endif return procAddr; } //static int N = 0; //search a procedure by Name and return its offset in the kernel UINTN LOADER_ENTRY::searchProc(const XString8& procedure) { if (procedure.isEmpty()) { return 0; } DBG("search name in kernel: %s\n", procedure.c_str()); const char* Names = (const char*)(&KernelData[NamesTable]); VTABLE * vArray = (VTABLE*)(&KernelData[AddrVtable]); //search for the name // gBS->Stall(9000000); size_t i; bool found = false; for (i=0; iSegAddress; //KLD=C70000 UINT64 FileOff = TextSeg->fileoff; //950000 UINT64 procAddr = vArray[i].ProcAddr - Absolut + FileOff; /* UINT64 prevAddr; if (i == 0) { prevAddr = Absolut; } else { prevAddr = vArray[i-1].ProcAddr; } *procLen = vArray[i].ProcAddr - prevAddr; //never worked */ DBG("kernel: procAddr=0x%llx\n", procAddr); return procAddr; } #if 0 //TimeWalker - extended and corrected for systems up to Yosemite //TODO - Slice: no more needed VOID LOADER_ENTRY::KernelPatcher_64() { UINT8 *bytes = KernelData; UINT32 patchLocation=0, patchLocation1=0; UINT32 i; UINT32 switchaddr=0; UINT32 mask_family=0, mask_model=0; UINT32 cpuid_family_addr=0, cpuid_model_addr=0; UINT64 os_version; // DBG_RT( "Looking for _cpuid_set_info _panic ...\n"); // Determine location of _cpuid_set_info _panic call for reference // basically looking for info_p->cpuid_model = bitfield32(reg[eax], 7, 4); for (i=0; i<0x1000000; i++) { if (bytes[i+ 0] == 0xC7 && bytes[i+ 1] == 0x05 && bytes[i+ 5] == 0x00 && bytes[i+ 6] == 0x07 && bytes[i+ 7] == 0x00 && bytes[i+ 8] == 0x00 && bytes[i+ 9] == 0x00 && bytes[i-5] == 0xE8) { // matching 0xE8 for _panic call start patchLocation = i-5; break; } } if (!patchLocation) { // DBG_RT( "_cpuid_set_info Unsupported CPU _panic not found \n"); return; } os_version = AsciiOSVersionToUint64(OSVersion); // make sure only kernels for OSX 10.6.0 to 10.7.3 are being patched by this approach if (os_version >= AsciiOSVersionToUint64("10.6") && os_version <= AsciiOSVersionToUint64("10.7.3")) { // DBG_RT( "will patch kernel for macOS 10.6.0 to 10.7.3\n"); // remove tsc_init: unknown CPU family panic for kernels prior to 10.6.2 which still had Atom support if (os_version < AsciiOSVersionToUint64("10.6.2")) { for (i=0; i<0x1000000; i++) { // find _tsc_init panic address by byte sequence 488d3df4632a00 if (bytes[i] == 0x48 && bytes[i+1] == 0x8D && bytes[i+2] == 0x3D && bytes[i+3] == 0xF4 && bytes[i+4] == 0x63 && bytes[i+5] == 0x2A && bytes[i+6] == 0x00) { patchLocation1 = i+9; // DBG_RT( "Found _tsc_init _panic address at 0x%08x\n",patchLocation1); break; } } // NOP _panic call if (patchLocation1) { bytes[patchLocation1 + 0] = 0x90; bytes[patchLocation1 + 1] = 0x90; bytes[patchLocation1 + 2] = 0x90; bytes[patchLocation1 + 3] = 0x90; bytes[patchLocation1 + 4] = 0x90; } } else { // assume patching logic for OSX 10.6.2 to 10.7.3 /* Here is our case from CPUID switch statement, it sets CPUFAMILY_UNKNOWN C7051C2C5F0000000000 mov dword [ds:0xffffff80008a22c0], 0x0 (example from 10.7) */ switchaddr = patchLocation - 19; // DBG_RT( "switch statement patch location is 0x%08x\n", (switchaddr+6)); if (bytes[switchaddr + 0] == 0xC7 && bytes[switchaddr + 1] == 0x05 && bytes[switchaddr + 5] == 0x00 && bytes[switchaddr + 6] == 0x00 && bytes[switchaddr + 7] == 0x00 && bytes[switchaddr + 8] == 0x00) { // Determine cpuid_family address from above mov operation cpuid_family_addr = bytes[switchaddr + 2] << 0 | bytes[switchaddr + 3] << 8 | bytes[switchaddr + 4] << 16 | bytes[switchaddr + 5] << 24; cpuid_family_addr = cpuid_family_addr + (switchaddr + 10); if (cpuid_family_addr) { // Determine cpuid_model address // for 10.6.2 kernels it's offset by 299 bytes from cpuid_family address if (os_version == AsciiOSVersionToUint64("10.6.2")) { cpuid_model_addr = cpuid_family_addr - 0X12B; } // for 10.6.3 to 10.6.7 it's offset by 303 bytes else if (os_version <= AsciiOSVersionToUint64("10.6.7")) { cpuid_model_addr = cpuid_family_addr - 0X12F; } // for 10.6.8 to 10.7.3 kernels - by 339 bytes else { cpuid_model_addr = cpuid_family_addr - 0X153; } // DBG_RT( "cpuid_family address: 0x%08x\n", cpuid_family_addr); // DBG_RT( "cpuid_model address: 0x%08x\n", cpuid_model_addr); switchaddr += 6; // offset 6 bytes in mov operation to write a dword instead of zero // calculate mask for patching, cpuid_family mask not needed as we offset on a valid mask mask_model = cpuid_model_addr - (switchaddr+14); // DBG_RT( "model mask 0x%08x\n", mask_model); // DBG_RT( "overriding cpuid_family and cpuid_model as CPUID_INTEL_PENRYN\n"); bytes[switchaddr+0] = (CPUFAMILY_INTEL_PENRYN & 0x000000FF) >> 0; bytes[switchaddr+1] = (CPUFAMILY_INTEL_PENRYN & 0x0000FF00) >> 8; bytes[switchaddr+2] = (CPUFAMILY_INTEL_PENRYN & 0x00FF0000) >> 16; bytes[switchaddr+3] = (CPUFAMILY_INTEL_PENRYN & 0xFF000000) >> 24; // mov dword [ds:0xffffff80008a216d], 0x2000117 bytes[switchaddr+4] = 0xC7; bytes[switchaddr+5] = 0x05; bytes[switchaddr+6] = (UINT8)((mask_model & 0x000000FF) >> 0); bytes[switchaddr+7] = (UINT8)((mask_model & 0x0000FF00) >> 8); bytes[switchaddr+8] = (UINT8)((mask_model & 0x00FF0000) >> 16); bytes[switchaddr+9] = (UINT8)((mask_model & 0xFF000000) >> 24); bytes[switchaddr+10] = 0x17; // cpuid_model (Penryn) bytes[switchaddr+11] = 0x01; // cpuid_extmodel bytes[switchaddr+12] = 0x00; // cpuid_extfamily bytes[switchaddr+13] = 0x02; // cpuid_stepping // fill remainder with 4 NOPs for (i=14; i<18; i++) { bytes[switchaddr+i] = 0x90; } } } else { // DBG_RT( "Unable to determine cpuid_family address, patching aborted\n"); return; } } // patch ssse3 if (!SSSE3 && (AsciiStrnCmp(OSVersion,"10.6",4)==0)) { Patcher_SSE3_6((VOID*)bytes); } if (!SSSE3 && (AsciiStrnCmp(OSVersion,"10.7",4)==0)) { Patcher_SSE3_7(); } } // all 10.7.4+ kernels share common CPUID switch statement logic, // it needs to be exploited in diff manner due to the lack of space else if (os_version >= AsciiOSVersionToUint64("10.7.4")) { DBG_RT( "will patch kernel for macOS 10.7.4+\n"); /* Here is our switchaddress location ... it should be case 20 from CPUID switch statement 833D78945F0000 cmp dword [ds:0xffffff80008a21d0], 0x0; 7417 je 0xffffff80002a8d71 */ switchaddr = patchLocation-45; DBG_RT( "switch statement patch location is 0x%08x\n", switchaddr); if(bytes[switchaddr + 0] == 0x83 && bytes[switchaddr + 1] == 0x3D && bytes[switchaddr + 5] == 0x00 && bytes[switchaddr + 6] == 0x00 && bytes[switchaddr + 7] == 0x74) { // Determine cpuid_family address // 891D4F945F00 mov dword [ds:0xffffff80008a21a0], ebx cpuid_family_addr = bytes[switchaddr - 4] << 0 | bytes[switchaddr - 3] << 8 | bytes[switchaddr - 2] << 16 | bytes[switchaddr - 1] << 24; cpuid_family_addr = cpuid_family_addr + switchaddr; if (cpuid_family_addr) { // Determine cpuid_model address // for 10.6.8+ kernels it's 339 bytes apart from cpuid_family address cpuid_model_addr = cpuid_family_addr - 0X153; DBG_RT( "cpuid_family address: 0x%08x\n", cpuid_family_addr); DBG_RT( "cpuid_model address: 0x%08x\n", cpuid_model_addr); // Calculate masks for patching mask_family = cpuid_family_addr - (switchaddr +15); mask_model = cpuid_model_addr - (switchaddr +25); DBG_RT( "\nfamily mask: 0x%08x \nmodel mask: 0x%08x\n", mask_family, mask_model); // retain original // test ebx, ebx bytes[switchaddr+0] = bytes[patchLocation-13]; bytes[switchaddr+1] = bytes[patchLocation-12]; // retain original, but move jump offset by 20 bytes forward // jne for above test bytes[switchaddr+2] = bytes[patchLocation-11]; bytes[switchaddr+3] = bytes[patchLocation-10]+0x20; // mov ebx, 0x78ea4fbc bytes[switchaddr+4] = 0xBB; bytes[switchaddr+5] = (CPUFAMILY_INTEL_PENRYN & 0x000000FF) >> 0; bytes[switchaddr+6] = (CPUFAMILY_INTEL_PENRYN & 0x0000FF00) >> 8; bytes[switchaddr+7] = (CPUFAMILY_INTEL_PENRYN & 0x00FF0000) >> 16; bytes[switchaddr+8] = (CPUFAMILY_INTEL_PENRYN & 0xFF000000) >> 24; // mov dword, ebx bytes[switchaddr+9] = 0x89; bytes[switchaddr+10] = 0x1D; // cpuid_cpufamily address 0xffffff80008a21a0 bytes[switchaddr+11] = (UINT8)((mask_family & 0x000000FF) >> 0); bytes[switchaddr+12] = (UINT8)((mask_family & 0x0000FF00) >> 8); bytes[switchaddr+13] = (UINT8)((mask_family & 0x00FF0000) >> 16); bytes[switchaddr+14] = (UINT8)((mask_family & 0xFF000000) >> 24); // mov dword bytes[switchaddr+15] = 0xC7; bytes[switchaddr+16] = 0x05; // cpuid_model address 0xffffff80008b204d bytes[switchaddr+17] = (UINT8)((mask_model & 0x000000FF) >> 0); bytes[switchaddr+18] = (UINT8)((mask_model & 0x0000FF00) >> 8); bytes[switchaddr+19] = (UINT8)((mask_model & 0x00FF0000) >> 16); bytes[switchaddr+20] = (UINT8)((mask_model & 0xFF000000) >> 24); bytes[switchaddr+21] = 0x17; // cpuid_model bytes[switchaddr+22] = 0x01; // cpuid_extmodel bytes[switchaddr+23] = 0x00; // cpuid_extfamily bytes[switchaddr+24] = 0x02; // cpuid_stepping // fill remainder with 25 NOPs for (i=25; i<25+25; i++) { bytes[switchaddr+i] = 0x90; } } } else { DBG_RT( "Unable to determine cpuid_family address, patching aborted\n"); return; } } } VOID LOADER_ENTRY::KernelPatcher_32() { UINT8* bytes = KernelData; UINT32 patchLocation=0, patchLocation1=0; UINT32 i; UINT32 jumpaddr; DBG("Found _cpuid_set_info _panic Start\n"); // _cpuid_set_info _panic address for (i=0; i<0x1000000; i++) { if (bytes[i] == 0xC7 && bytes[i+1] == 0x05 && bytes[i+6] == 0x07 && bytes[i+7] == 0x00 && bytes[i+8] == 0x00 && bytes[i+9] == 0x00 && bytes[i+10] == 0xC7 && bytes[i+11] == 0x05 && bytes[i-5] == 0xE8) { patchLocation = i-5; DBG("Found _cpuid_set_info _panic address at 0x%08X\n",patchLocation); break; } } if (!patchLocation) { DBG("Can't find _cpuid_set_info _panic address, patch kernel abort.\n"/*,i*/); return; } // this for 10.6.0 and 10.6.1 kernel and remove tsc.c unknow cpufamily panic // c70424540e5900 // find _tsc_init panic address for (i=0; i<0x1000000; i++) { // _cpuid_set_info _panic address if (bytes[i] == 0xC7 && bytes[i+1] == 0x04 && bytes[i+2] == 0x24 && bytes[i+3] == 0x54 && bytes[i+4] == 0x0E && bytes[i+5] == 0x59 && bytes[i+6] == 0x00) { patchLocation1 = i+7; DBG("Found _tsc_init _panic address at 0x%08X\n",patchLocation1); break; } } // found _tsc_init panic addres and patch it if (patchLocation1) { bytes[patchLocation1 + 0] = 0x90; bytes[patchLocation1 + 1] = 0x90; bytes[patchLocation1 + 2] = 0x90; bytes[patchLocation1 + 3] = 0x90; bytes[patchLocation1 + 4] = 0x90; } // end tsc.c panic //first move panic code total 5 bytes, if patch cpuid fail still can boot with kernel bytes[patchLocation + 0] = 0x90; bytes[patchLocation + 1] = 0x90; bytes[patchLocation + 2] = 0x90; bytes[patchLocation + 3] = 0x90; bytes[patchLocation + 4] = 0x90; jumpaddr = patchLocation; for (i=0;i<500;i++) { if (bytes[jumpaddr-i-3] == 0x85 && bytes[jumpaddr-i-2] == 0xC0 && bytes[jumpaddr-i-1] == 0x75 ) { jumpaddr -= i; bytes[jumpaddr-1] = 0x77; if(bytes[patchLocation - 17] == 0xC7) bytes[jumpaddr] -=10; break; } } if (jumpaddr == patchLocation) { DBG("Can't Found jumpaddr address.\n"); return; //can't find jump location } // patch info_p->cpufamily to CPUFAMILY_INTEL_MEROM if (bytes[patchLocation - 17] == 0xC7) { bytes[patchLocation - 11] = (CPUFAMILY_INTEL_MEROM & 0x000000FF) >> 0; bytes[patchLocation - 10] = (CPUFAMILY_INTEL_MEROM & 0x0000FF00) >> 8; bytes[patchLocation - 9] = (CPUFAMILY_INTEL_MEROM & 0x00FF0000) >> 16; bytes[patchLocation - 8] = (CPUFAMILY_INTEL_MEROM & 0xFF000000) >> 24; } //patch info->cpuid_cpufamily bytes[patchLocation - 7] = 0xC7; bytes[patchLocation - 6] = 0x05; bytes[patchLocation - 5] = bytes[jumpaddr + 3]; bytes[patchLocation - 4] = bytes[jumpaddr + 4]; bytes[patchLocation - 3] = bytes[jumpaddr + 5]; bytes[patchLocation - 2] = bytes[jumpaddr + 6]; bytes[patchLocation - 1] = CPUIDFAMILY_DEFAULT; //cpuid_family need alway set 0x06 bytes[patchLocation + 0] = CPU_MODEL_MEROM; //cpuid_model set CPU_MODEL_MEROM bytes[patchLocation + 1] = 0x01; //cpuid_extmodel alway set 0x01 bytes[patchLocation + 2] = 0x00; //cpuid_extfamily alway set 0x00 bytes[patchLocation + 3] = 0x90; bytes[patchLocation + 4] = 0x90; if (OSVersion) { if (AsciiStrnCmp(OSVersion,"10.7",4)==0) return; if (!SSSE3 && (AsciiStrnCmp(OSVersion,"10.6",4)==0)) { Patcher_SSE3_6((VOID*)bytes); } if (!SSSE3 && (AsciiStrnCmp(OSVersion,"10.5",4)==0)) { Patcher_SSE3_5((VOID*)bytes); } } } #endif //Slice - FakeCPUID substitution, (c)2014 // _cpuid_set_info //TODO remake to patterns //procedure location const UINT8 StrCpuid1_tigLeo[] = {0xb9, 0x01, 0x00, 0x00, 0x00, 0x89, 0xc8, 0x0f, 0xa2}; const UINT8 StrCpuid1_snowLeo[] = {0xb8, 0x01, 0x00, 0x00, 0x00, 0x31, 0xdb, 0x89, 0xd9, 0x89, 0xda, 0x0f, 0xa2}; const UINT8 StrMsr8b[] = {0xb9, 0x8b, 0x00, 0x00, 0x00, 0x0f, 0x32}; // Tiger/Leopard/Snow Leopard /* This patch searches and eax, 0xf0 || and eax, 0x0f0000 shr eax, 0x04 || shr eax, 0x10 and replaces to mov eax, FakeModel | mov eax, FakeExt */ const UINT8 TigLeoSLSearchModel[] = {0x25, 0xf0, 0x00, 0x00, 0x00, 0xc1, 0xe8, 0x04}; const UINT8 TigLeoSLSearchExt[] = {0x25, 0x00, 0x00, 0x0f, 0x00, 0xc1, 0xe8, 0x10}; const UINT8 TigLeoSLReplaceModel[] = {0xb8, 0x07, 0x00, 0x00, 0x00, 0x90, 0x90, 0x90}; // Lion /* This patch searches mov ecx, eax shr ecx, 0x04 || shr ecx, 0x10 and replaces to mov ecx, FakeModel || mov ecx, FakeExt */ const UINT8 LionSearchModel[] = {0x89, 0xc1, 0xc1, 0xe9, 0x04}; const UINT8 LionSearchExt[] = {0x89, 0xc1, 0xc1, 0xe9, 0x10}; const UINT8 LionReplaceModel[] = {0xb9, 0x07, 0x00, 0x00, 0x00}; // Mountain Lion/Mavericks /* This patch searches mov bl, al || shr eax, 0x10 shr bl, 0x04 || and al,0x0f and replaces to mov ebx, FakeModel || mov eax, FakeExt */ const UINT8 MLMavSearchModel[] = {0x88, 0xc3, 0xc0, 0xeb, 0x04}; const UINT8 MLMavSearchExt[] = {0xc1, 0xe8, 0x10, 0x24, 0x0f}; const UINT8 MLMavReplaceModel[] = {0xbb, 0x0a, 0x00, 0x00, 0x00}; const UINT8 MLMavReplaceExt[] = {0xb8, 0x02, 0x00, 0x00, 0x00}; // Yosemite/El Capitan/Sierra /* This patch searches mov cl, al || mov ecx, eax shr cl, 0x04 || shr ecx, 0x10 and replaces to mov ecx, FakeModel || mov ecx, FakeExt */ const UINT8 YosECSieSearchModel[] = {0x88, 0xc1, 0xc0, 0xe9, 0x04}; const UINT8 YosECSieSearchExt[] = {0x89, 0xc1, 0xc1, 0xe9, 0x10}; // Need to use LionReplaceModel // High Sierra/Mojave @2c4baa {89 c1 c0 e9 04} /* This patch searches mov ecx, ecx || mov ecx, eax shr cl, 0x04 || shr ecx, 0x10 and replaces to mov ecx, FakeModel || mov ecx, FakeExt */ const UINT8 HSieMojSearchModel[] = {0x89, 0xc1, 0xc0, 0xe9, 0x04}; // Need to use YosECSieSearchExt, LionReplaceModel // Catalina /* This patch searches mov eax, r12 || mov eax, r12 shr al, 0x4 || shr eax, 0x10 and replaces to mov eax, FakeModel || mov eax, FakeExt nop || nop */ const UINT8 CataSearchModel[] = {0x44, 0x89, 0xE0, 0xC0, 0xE8, 0x04}; const UINT8 CataSearchExt[] = {0x44, 0x89, 0xE0, 0xC1, 0xE8, 0x10}; const UINT8 CataReplaceMovEax[] = {0xB8, 0x00, 0x00, 0x00, 0x00, 0x90}; // mov eax, val || nop BOOLEAN LOADER_ENTRY::PatchCPUID(const UINT8* Location, INT32 LenLoc, const UINT8* Search4, const UINT8* Search10, const UINT8* ReplaceModel, const UINT8* ReplaceExt, INT32 Len) { INT32 patchLocation=0, patchLocation1=0; INT32 Adr = 0, Num; BOOLEAN Patched = FALSE; UINT8 FakeModel = (KernelAndKextPatches.FakeCPUID >> 4) & 0x0f; UINT8 FakeExt = (KernelAndKextPatches.FakeCPUID >> 0x10) & 0x0f; for (Num = 0; Num < 2; Num++) { Adr = FindBin(&KernelData[Adr], 0x800000 - Adr, Location, (UINT32)LenLoc); if (Adr < 0) { break; } DBG_RT( "found location at %x\n", Adr); patchLocation = FindBin(&KernelData[Adr], 0x100, Search4, (UINT32)Len); if (patchLocation > 0 && patchLocation < 70) { //found DBG_RT( "found Model location at %x\n", Adr + patchLocation); CopyMem(&KernelData[Adr + patchLocation], ReplaceModel, Len); KernelData[Adr + patchLocation + 1] = FakeModel; patchLocation1 = FindBin(&KernelData[Adr], 0x100, Search10, (UINT32)Len); if (patchLocation1 > 0 && patchLocation1 < 100) { DBG_RT( "found ExtModel location at %x\n", Adr + patchLocation1); CopyMem(&KernelData[Adr + patchLocation1], ReplaceExt, Len); KernelData[Adr + patchLocation1 + 1] = FakeExt; } Patched = TRUE; } } return Patched; } VOID LOADER_ENTRY::KernelCPUIDPatch() { // Tiger/Leopard patterns DBG_RT( "CPUID: try Tiger/Leopard patch...\n"); if (PatchCPUID(&StrCpuid1_tigLeo[0], sizeof(StrCpuid1_tigLeo), &TigLeoSLSearchModel[0], &TigLeoSLSearchExt[0], &TigLeoSLReplaceModel[0], &TigLeoSLReplaceModel[0], sizeof(TigLeoSLSearchModel))) { DBG_RT( "...done!\n"); return; } // Snow Leopard patterns DBG_RT( "CPUID: try Snow Leopard patch...\n"); if (PatchCPUID(&StrCpuid1_snowLeo[0], sizeof(StrCpuid1_snowLeo), &TigLeoSLSearchModel[0], &TigLeoSLSearchExt[0], &TigLeoSLReplaceModel[0], &TigLeoSLReplaceModel[0], sizeof(TigLeoSLSearchModel))) { DBG_RT( "...done!\n"); return; } // Lion patterns DBG_RT( "CPUID: try Lion patch...\n"); if (PatchCPUID(&StrMsr8b[0], sizeof(StrMsr8b), &LionSearchModel[0], &LionSearchExt[0], &LionReplaceModel[0], &LionReplaceModel[0], sizeof(LionSearchModel))) { DBG_RT( "...done!\n"); return; } // Mountain Lion/Mavericks patterns DBG_RT( "CPUID: try Mountain Lion/Mavericks patch...\n"); if (PatchCPUID(&StrMsr8b[0], sizeof(StrMsr8b), &MLMavSearchModel[0], &MLMavSearchExt[0], &MLMavReplaceModel[0], &MLMavReplaceExt[0], sizeof(MLMavSearchModel))) { DBG_RT( "...done!\n"); return; } // Yosemite/El Capitan/Sierra patterns DBG_RT( "CPUID: try Yosemite/El Capitan/Sierra patch...\n"); if (PatchCPUID(&StrMsr8b[0], sizeof(StrMsr8b), &YosECSieSearchModel[0], &YosECSieSearchExt[0], &LionReplaceModel[0], &LionReplaceModel[0], sizeof(YosECSieSearchModel))) { DBG_RT( "...done!\n"); return; } // High Sierra/Mojave patterns // Sherlocks: 10.13/10.14 DBG_RT( "CPUID: try High Sierra/Mojave patch...\n"); if (PatchCPUID(&StrMsr8b[0], sizeof(StrMsr8b), &HSieMojSearchModel[0], &YosECSieSearchExt[0], &LionReplaceModel[0], &LionReplaceModel[0], sizeof(HSieMojSearchModel))) { DBG_RT( "...done!\n"); return; } // Catalina patterns // PMheart: 10.15.DP1 DBG_RT( "CPUID: try Catalina patch...\n"); if (PatchCPUID(&StrMsr8b[0], sizeof(StrMsr8b), &CataSearchModel[0], &CataSearchExt[0], &CataReplaceMovEax[0], &CataReplaceMovEax[0], sizeof(CataSearchModel))) { DBG_RT( "...done!\n"); return; } } #define NEW_PM 1 BOOLEAN LOADER_ENTRY::KernelPatchPm() { DBG_RT("Patching kernel power management...\n"); #if NEW_PM //Slice //1. procedure xcpm_idle // wrmsr 0xe2 twice // B9E2000000 0F30 replace to eb05 // UINTN procLen = 0; UINTN procLocation = searchProc("xcpm_idle"_XS8); const UINT8 findJmp[] = {0xB9, 0xE2, 0x00, 0x00, 0x00, 0x0F, 0x30}; const UINT8 patchJmp[] = {0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90}; DBG_RT("==> xcpm_idle at %llx\n", procLocation); INTN Num = SearchAndReplace(&KernelData[procLocation], 0x400, findJmp, sizeof(findJmp), patchJmp, 0); DBG_RT("==> found %lld patterns\n", Num); //2. procedure xcpm_init // indirect call to _xcpm_core_scope_msrs and to _xcpm_SMT_scope_msrs // 488D3DDA317600 lea rdi, qword [ds:_xcpm_core_scope_msrs] // BE0B000000 mov esi, 0xb => replace to eb0a // 31D2 xor edx, edx // E87EFCFFFF call sub_ffffff80004fa610 => check e8? // there are other occurence of _xcpm_core_scope_msrs so check 488D3D or E8 at .+7 // or restrict len = 0x200 procLocation = searchProc("xcpm_init"_XS8); UINTN symbol1 = searchProc("xcpm_core_scope_msrs"_XS8); UINTN patchLocation1 = FindRelative32(KernelData, procLocation, 0x200, symbol1); if (patchLocation1 != 0) { DBG_RT("=> xcpm_core_scope_msrs found at %llx\n", patchLocation1); if (KernelData[patchLocation1 + 7] == 0xE8) { DBG_RT("=> patch applied\n"); // for (int i=0; i < 0x10; ++i) { // DBG_RT("%02x", KernelData[patchLocation1 + i]); // } // DBG_RT("\n"); KernelData[patchLocation1] = 0xEB; KernelData[patchLocation1 + 1] = 0x0A; } else { DBG_RT("=> pattern not good\n"); // for (int i=0; i < 0x10; ++i) { // DBG_RT("%02x", KernelData[patchLocation1 + i]); // } // DBG_RT("\n"); } } UINTN symbol2 = searchProc("xcpm_SMT_scope_msrs"_XS8); patchLocation1 = FindRelative32(KernelData, procLocation, 0x200, symbol2); if (patchLocation1 != 0) { DBG_RT("=> xcpm_SMT_scope_msrs found at %llx\n", patchLocation1); if (KernelData[patchLocation1 + 7] == 0xE8) { DBG_RT("=> SMT patch applied\n"); KernelData[patchLocation1] = 0xEB; KernelData[patchLocation1 + 1] = 0x0A; } else { DBG_RT("=> pattern not good\n"); } } Stall(10000000); #else // Credits to RehabMan for the kernel patch information // new way by RehabMan 2017-08-13 // cleanup by Sherlocks 2020-03-23 #define CompareWithMask(x,m,c) (((x) & (m)) == (c)) //TODO - remake using CompareMemMask UINT64* Ptr = (UINT64*)KernelData; UINT64* End = Ptr + 0x1000000/sizeof(UINT64); if (Ptr == NULL) { return FALSE; } for (; Ptr < End; Ptr += 2) { // check for xcpm_scope_msr common 0xE2 prologue // E2000000 XX000000 00000000 00000000 00040000 00000000 // 10.8/10.9: 02,0C,10 // E2000000 XXXX0000 00000000 00000000 0F040000 00000000 // 10.10: 0200,4C00,9001, 10.11: 0200,4C00,9013, 10.12: 4C00,9033, 10.13-10.15.3: 4C00,9033,0040 // E2000000 XXXXXX00 00000000 00000000 0F040000 00000000 // 10.15.4+: 4C0000,903306,004000 // E2000000 XXXXXXXX 00000000 00000000 XX040000 00000000 // safe pattern for next macOS if (CompareWithMask(Ptr[0], 0x00000000FFFFFFFF, 0x00000000000000E2) && 0 == Ptr[1] && CompareWithMask(Ptr[2], 0xFFFFFFFFFFFFFF00, 0x0000000000000400)) { // 10.8 - 10.12 // 0700001E 00000000 00000000 00000000 00000000 00000000 // 0500001E 00000000 00000000 00000000 00000000 00000000 // 0800007E 00000000 00000000 00000000 00000000 00000000 // 10.13+ // 0500001E 00000000 00000000 00000000 00000000 00000000 // 0800007E 00000000 00000000 00000000 00000000 00000000 // 0300007E 00000000 00000000 00000000 00000000 00000000 // XX00001E 00000000 00000000 00000000 00000000 00000000 if (CompareWithMask(Ptr[3], 0xFFFFFFFFFFFFFF00, 0x000000001E000000) && 0 == Ptr[4] && 0 == Ptr[5]) { // zero out 0xE2 MSR and CPU mask Ptr[0] = 0; DBG_RT("Kernel power management: entry 1E found and patched\n"); // XX00007E 00000000 00000000 00000000 00000000 00000000 } else if (CompareWithMask(Ptr[3], 0xFFFFFFFFFFFFFF00, 0x000000007E000000) && 0 == Ptr[4] && 0 == Ptr[5]) { // zero out 0xE2 MSR and CPU mask Ptr[0] = 0; DBG_RT("Kernel power management: entry 7E found and patched\n"); } } } if (KernelAndKextPatches.KPDebug) { gBS->Stall(3000000); } #endif return TRUE; } const UINT8 PanicNoKextDumpFind[] = {0x00, 0x25, 0x2E, 0x2A, 0x73, 0x00}; //STATIC UINT8 PanicNoKextDumpReplace[6] = {0x00, 0x00, 0x2E, 0x2A, 0x73, 0x00}; BOOLEAN LOADER_ENTRY::KernelPanicNoKextDump() { INT32 patchLocation; patchLocation = FindBin(KernelData, 0xF00000, PanicNoKextDumpFind, 6); if (patchLocation > 0) { KernelData[patchLocation + 1] = 0; return TRUE; } return FALSE; } BOOLEAN LOADER_ENTRY::KernelLapicPatch_64() { // Credits to donovan6000 and Sherlocks for providing the lapic kernel patch source used to build this function UINT8 *bytes = KernelData; UINTN patchLocation1 = 0, patchLocation2 = 0; UINT32 i, y; DBG_RT( "Looking for Lapic panic call (64-bit) Start\n"); //Slice - symbolic method //start at lapic_interrupt ffffff80004e4950 => @2e4950 // found pattern: 1 // address: 002e4a2f // bytes:658b04251c0000003b058bb97b00 // call _panic -> change to nop {90,90,90,90,90} if (AsciiOSVersionToUint64(OSVersion) >= AsciiOSVersionToUint64("10.10"_XS8)) { UINTN procAddr = searchProc("lapic_interrupt"_XS8); patchLocation1 = searchProc("_panic"_XS8); patchLocation2 = FindRelative32(KernelData, procAddr, 0x140, patchLocation1); if (patchLocation2 != 0) { KernelData[patchLocation2 - 5] = 0xEB; KernelData[patchLocation2 - 4] = 0x03; DBG_RT( "Lapic panic patched\n"); return true; } } //else old method for (i = 0; i < 0x1000000; i++) { if (KernelData[i+0] == 0x65 && KernelData[i+1] == 0x8B && KernelData[i+2] == 0x04 && KernelData[i+3] == 0x25 && KernelData[i+4] == 0x3C && KernelData[i+5] == 0x00 && KernelData[i+6] == 0x00 && KernelData[i+7] == 0x00 && KernelData[i+45] == 0x65 && KernelData[i+46] == 0x8B && KernelData[i+47] == 0x04 && KernelData[i+48] == 0x25 && KernelData[i+49] == 0x3C && KernelData[i+50] == 0x00 && KernelData[i+51] == 0x00 && KernelData[i+52] == 0x00) { patchLocation1 = i+40; DBG_RT( "Found Lapic panic (10.6) at 0x%08llx\n", patchLocation1); break; } else if (KernelData[i+0] == 0x65 && KernelData[i+1] == 0x8B && KernelData[i+2] == 0x04 && KernelData[i+3] == 0x25 && KernelData[i+4] == 0x14 && KernelData[i+5] == 0x00 && KernelData[i+6] == 0x00 && KernelData[i+7] == 0x00 && KernelData[i+35] == 0x65 && KernelData[i+36] == 0x8B && KernelData[i+37] == 0x04 && KernelData[i+38] == 0x25 && KernelData[i+39] == 0x14 && KernelData[i+40] == 0x00 && KernelData[i+41] == 0x00 && KernelData[i+42] == 0x00) { patchLocation1 = i+30; DBG_RT( "Found Lapic panic (10.7 - 10.8) at 0x%08llx\n", patchLocation1); break; } else if (KernelData[i+0] == 0x65 && KernelData[i+1] == 0x8B && KernelData[i+2] == 0x04 && KernelData[i+3] == 0x25 && KernelData[i+4] == 0x1C && KernelData[i+5] == 0x00 && KernelData[i+6] == 0x00 && KernelData[i+7] == 0x00 && KernelData[i+36] == 0x65 && KernelData[i+37] == 0x8B && KernelData[i+38] == 0x04 && KernelData[i+39] == 0x25 && KernelData[i+40] == 0x1C && KernelData[i+41] == 0x00 && KernelData[i+42] == 0x00 && KernelData[i+43] == 0x00) { patchLocation1 = i+31; DBG_RT( "Found Lapic panic (10.9) at 0x%08llx\n", patchLocation1); break; // 00 29 C7 78 XX 31 DB 8D 47 FA 83 } else if (KernelData[i+0] == 0x00 && KernelData[i+1] == 0x29 && KernelData[i+2] == 0xC7 && KernelData[i+3] == 0x78 && //(bytes[i+4] == 0x3F || bytes[i+4] == 0x4F) && // 3F:10.10-10.12/4F:10.13+ bytes[i+5] == 0x31 && bytes[i+6] == 0xDB && bytes[i+7] == 0x8D && bytes[i+8] == 0x47 && bytes[i+9] == 0xFA && bytes[i+10] == 0x83) { DBG_RT( "Found Lapic panic Base (10.10 - recent macOS)\n"); for (y = i; y < 0x1000000; y++) { // Lapic panic patch, by vit9696 // mov eax, gs:XX // cmp eax, cs:_master_cpu // 65 8B 04 25 XX 00 00 00 3B 05 XX XX XX 00 if (bytes[y+0] == 0x65 && bytes[y+1] == 0x8B && bytes[y+2] == 0x04 && bytes[y+3] == 0x25 && //(bytes[y+4] == 0x1C || bytes[y+4] == 0x18) && // 1C:10.10-10.15.3/18:10.15.4+ bytes[y+5] == 0x00 && bytes[y+6] == 0x00 && bytes[y+7] == 0x00 && bytes[y+8] == 0x3B && bytes[y+9] == 0x05 && bytes[y+13] == 0x00) { patchLocation1 = y; DBG_RT( "Found Lapic panic (10.10 - recent macOS) at 0x%08llx\n", patchLocation1); break; } } break; } } if (!patchLocation1) { DBG_RT( "Can't find Lapic panic, kernel patch aborted.\n"); return FALSE; } // Already patched? May be running a non-vanilla kernel already? if (bytes[patchLocation1 + 0] == 0x90 && bytes[patchLocation1 + 1] == 0x90 && bytes[patchLocation1 + 2] == 0x90 && bytes[patchLocation1 + 3] == 0x90 && bytes[patchLocation1 + 4] == 0x90) { DBG_RT( "Lapic panic already patched, kernel file (10.6 - 10.9) manually patched?\n"); return FALSE; } else if (bytes[patchLocation1 + 0] == 0x31 && bytes[patchLocation1 + 1] == 0xC0 && bytes[patchLocation1 + 2] == 0x90 && bytes[patchLocation1 + 3] == 0x90) { DBG_RT( "Lapic panic already patched, kernel file (10.10 - recent macOS) manually patched?\n"); return FALSE; } else { if (bytes[patchLocation1 + 8] == 0x3B && bytes[patchLocation1 + 9] == 0x05 && bytes[patchLocation1 + 13] == 0x00) { // 65 8B 04 25 XX 00 00 00 3B 05 XX XX XX 00 // 31 C0 90 90 90 90 90 90 90 90 90 90 90 90 DBG_RT( "Patched Lapic panic (10.10 - recent macOS)\n"); bytes[patchLocation1 + 0] = 0x31; bytes[patchLocation1 + 1] = 0xC0; for (i = 2; i < 14; i++) { bytes[patchLocation1 + i] = 0x90; } for (i = 0; i < 0x1000000; i++) { // 00 29 C7 78 XX 31 DB 8D 47 FA 83 if (bytes[i+0] == 0x00 && bytes[i+1] == 0x29 && bytes[i+2] == 0xC7 && bytes[i+3] == 0x78 && //(bytes[i+4] == 0x3F || bytes[i+4] == 0x4F) && // 3F:10.10-10.12/4F:10.13+ bytes[i+5] == 0x31 && bytes[i+6] == 0xDB && bytes[i+7] == 0x8D && bytes[i+8] == 0x47 && bytes[i+9] == 0xFA && bytes[i+10] == 0x83) { DBG_RT( "Found Lapic panic master Base (10.10 - recent macOS)\n"); for (y = i; y < 0x1000000; y++) { // Lapic panic master patch, by vit9696 // cmp cs:_debug_boot_arg, 0 // E8 XX XX FF FF 83 XX XX XX XX 00 00 if (bytes[y+0] == 0xE8 && bytes[y+3] == 0xFF && bytes[y+4] == 0xFF && bytes[y+5] == 0x83 && bytes[y+10] == 0x00 && bytes[y+11] == 0x00) { patchLocation2 = y; DBG_RT( "Found Lapic panic master (10.10 - recent macOS) at 0x%08llx\n", patchLocation2); break; } } break; } } if (!patchLocation2) { DBG_RT( "Can't find Lapic panic master (10.10 - recent macOS), kernel patch aborted.\n"); return FALSE; } // Already patched? May be running a non-vanilla kernel already? if (bytes[patchLocation2 + 5] == 0x31 && bytes[patchLocation2 + 6] == 0xC0) { DBG_RT( "Lapic panic master already patched, kernel file (10.10 - recent macOS) manually patched?\n"); return FALSE; } else { DBG_RT( "Patched Lapic panic master (10.10 - recent macOS)\n"); // E8 XX XX FF FF 83 XX XX XX XX 00 00 // E8 XX XX FF FF 31 C0 90 90 90 90 90 xor eax,eax; nop; nop;.... bytes[patchLocation2 + 5] = 0x31; bytes[patchLocation2 + 6] = 0xC0; for (i = 7; i < 12; i++) { bytes[patchLocation2 + i] = 0x90; } } } else { DBG_RT( "Patched Lapic panic (10.6 - 10.9)\n"); for (i = 0; i < 5; i++) { bytes[patchLocation1 + i] = 0x90; } } } // if (KernelAndKextPatches.KPDebug) { Stall(3000000); // } return TRUE; } BOOLEAN LOADER_ENTRY::KernelLapicPatch_32() { // Credits to donovan6000 and Sherlocks for providing the lapic kernel patch source used to build this function UINT8 *bytes = KernelData; UINT32 patchLocation = 0; UINT32 i; DBG_RT( "Looking for Lapic panic call (32-bit) Start\n"); for (i = 0; i < 0x1000000; i++) { if (bytes[i+0] == 0x65 && bytes[i+1] == 0xA1 && bytes[i+2] == 0x0C && bytes[i+3] == 0x00 && bytes[i+4] == 0x00 && bytes[i+5] == 0x00 && bytes[i+30] == 0x65 && bytes[i+31] == 0xA1 && bytes[i+32] == 0x0C && bytes[i+33] == 0x00 && bytes[i+34] == 0x00 && bytes[i+35] == 0x00) { patchLocation = i+25; DBG_RT( "Found Lapic panic at 0x%08x\n", patchLocation); break; } } if (!patchLocation) { DBG_RT( "Can't find Lapic panic, kernel patch aborted.\n"); return FALSE; } // Already patched? May be running a non-vanilla kernel already? if (bytes[patchLocation + 0] == 0x90 && bytes[patchLocation + 1] == 0x90 && bytes[patchLocation + 2] == 0x90 && bytes[patchLocation + 3] == 0x90 && bytes[patchLocation + 4] == 0x90) { DBG_RT( "Lapic panic already patched, kernel file manually patched?\n"); return FALSE; } else { DBG_RT( "Patched Lapic panic (32-bit)\n"); for (i = 0; i < 5; i++) { bytes[patchLocation + i] = 0x90; } } // if (KernelAndKextPatches.KPDebug) { Stall(3000000); // } return TRUE; } // // syscl - EnableExtCpuXCPM(): enable extra(unsupport) Cpu XCPM function // PowerManagement that will be enabled on: // SandyBridge-E, Ivy Bridge, Ivy Bridge-E, Haswell Celeron/Pentium, Haswell-E, Broadwell-E, ... // credit Pike R.Alpha, stinga11, syscl // //BOOLEAN (*EnableExtCpuXCPM)(VOID *kernelData); // // syscl - applyKernPatch a wrapper for SearchAndReplace() to make the CpuPM patch tidy and clean // VOID LOADER_ENTRY::applyKernPatch(const UINT8 *find, UINTN size, const UINT8 *repl, const CHAR8 *comment) { DBG("Searching %s...\n", comment); if (SearchAndReplace(KernelData, KERNEL_MAX_SIZE, find, size, repl, 0)) { DBG("Found %s\nApplied patch\n", comment); } else { DBG("%s no found, patched already?\n", comment); } } // PMHeart // Global XCPM patches compatibility // Currently 10.8.5 - 10.15 // static inline BOOLEAN IsXCPMOSVersionCompat(UINT64 os_version) { return (os_version >= AsciiOSVersionToUint64("10.8.5"_XS8)) && (os_version < AsciiOSVersionToUint64("11.1.0"_XS8)); } // // Enable Unsupported CPU PowerManagement // // syscl - SandyBridgeEPM(): enable PowerManagement on SandyBridge-E // BOOLEAN LOADER_ENTRY::SandyBridgeEPM() { // note: a dummy function that made patches consistency return TRUE; } // // syscl - Enable Haswell-E XCPM // Hex data provided and polished (c) PMheart, idea (c) Pike R.Alpha // BOOLEAN LOADER_ENTRY::HaswellEXCPM() { DBG("HaswellEXCPM() ===>\n"); UINT8 *kern = KernelData; XString8 comment; // UINT32 i; UINTN patchLocation; UINT64 os_version = AsciiOSVersionToUint64(OSVersion); // check OS version suit for patches if (!IsXCPMOSVersionCompat(os_version)) { DBG("HaswellEXCPM(): Unsupported macOS.\n"); DBG("HaswellEXCPM() <===FALSE\n"); return FALSE; } // _cpuid_set_info comment = "_cpuid_set_info"_XS8; if (os_version <= AsciiOSVersionToUint64("10.8.5"_XS8)) { // 10.8.5 const UINT8 find[] = { 0x83, 0xF8, 0x3C, 0x74, 0x2D }; const UINT8 repl[] = { 0x83, 0xF8, 0x3F, 0x74, 0x2D }; applyKernPatch(find, sizeof(find), repl, comment.c_str()); } else if (os_version < AsciiOSVersionToUint64("10.10"_XS8)) { // 10.9.x const UINT8 find[] = { 0x83, 0xF8, 0x3C, 0x75, 0x07 }; const UINT8 repl[] = { 0x83, 0xF8, 0x3F, 0x75, 0x07 }; applyKernPatch(find, sizeof(find), repl, comment.c_str()); } else if (os_version <= AsciiOSVersionToUint64("10.10.1"_XS8)) { // 10.10 - 10.10.1 const UINT8 find[] = { 0x74, 0x11, 0x83, 0xF8, 0x3C }; const UINT8 repl[] = { 0x74, 0x11, 0x83, 0xF8, 0x3F }; applyKernPatch(find, sizeof(find), repl, comment.c_str()); } // 10.10.2+: native support reached, no need to patch // _xcpm_bootstrap comment = "_xcpm_bootstrap"_XS8; if (os_version <= AsciiOSVersionToUint64("10.8.5"_XS8)) { // 10.8.5 const UINT8 find[] = { 0x83, 0xFB, 0x3C, 0x75, 0x54 }; const UINT8 repl[] = { 0x83, 0xFB, 0x3F, 0x75, 0x54 }; applyKernPatch(find, sizeof(find), repl, comment.c_str()); } else if (os_version < AsciiOSVersionToUint64("10.10"_XS8)) { // 10.9.x const UINT8 find[] = { 0x83, 0xFB, 0x3C, 0x75, 0x68 }; const UINT8 repl[] = { 0x83, 0xFB, 0x3F, 0x75, 0x68 }; applyKernPatch(find, sizeof(find), repl, comment.c_str()); } else if (os_version <= AsciiOSVersionToUint64("10.10.2"_XS8)) { // 10.10 - 10.10.2 const UINT8 find[] = { 0x83, 0xFB, 0x3C, 0x75, 0x63 }; const UINT8 repl[] = { 0x83, 0xFB, 0x3F, 0x75, 0x63 }; applyKernPatch(find, sizeof(find), repl, comment.c_str()); } else if (os_version <= AsciiOSVersionToUint64("10.10.5"_XS8)) { // 10.10.3 - 10.10.5 const UINT8 find[] = { 0x83, 0xC3, 0xC6, 0x83, 0xFB, 0x0D }; const UINT8 repl[] = { 0x83, 0xC3, 0xC3, 0x83, 0xFB, 0x0D }; applyKernPatch(find, sizeof(find), repl, comment.c_str()); } else if (os_version <= AsciiOSVersionToUint64("10.11"_XS8)) { // 10.11 DB/PB - 10.11.0 const UINT8 find[] = { 0x83, 0xC3, 0xC6, 0x83, 0xFB, 0x0D }; const UINT8 repl[] = { 0x83, 0xC3, 0xC3, 0x83, 0xFB, 0x0D }; applyKernPatch(find, sizeof(find), repl, comment.c_str()); } else if (os_version <= AsciiOSVersionToUint64("10.11.6"_XS8)) { // 10.11.1 - 10.11.6 const UINT8 find[] = { 0x83, 0xC3, 0xBB, 0x83, 0xFB, 0x09 }; const UINT8 repl[] = { 0x83, 0xC3, 0xB8, 0x83, 0xFB, 0x09 }; applyKernPatch(find, sizeof(find), repl, comment.c_str()); } else { UINTN procLocation = searchProc(comment); UINTN featureCall = searchProc("_cpuid_features"_XS8); UINTN place = FindRelative32(KernelData, procLocation, 0x100, featureCall); for (UINTN i = 10; i < 20; ++i) { if (KernelData[place + i] == 0xC4) { KernelData[place + i] = 0xC1; if (KernelData[(place + i) - 5] == 0x3B) { KernelData[(place + i) - 5] = 0x00; } break; } } /*if (os_version <= AsciiOSVersionToUint64("10.12.5")) { // 10.12 - 10.12.5 const UINT8 find[] = { 0x83, 0xC3, 0xC4, 0x83, 0xFB, 0x22 }; const UINT8 repl[] = { 0x83, 0xC3, 0xC1, 0x83, 0xFB, 0x22 }; applyKernPatch(find, sizeof(find), repl, comment); } else if (os_version < AsciiOSVersionToUint64("10.13")) { // 10.12.6 const UINT8 find[] = { 0x8D, 0x43, 0xC4, 0x83, 0xF8, 0x22 }; const UINT8 repl[] = { 0x8D, 0x43, 0xC1, 0x83, 0xF8, 0x22 }; applyKernPatch(find, sizeof(find), repl, comment); // PMheart: attempt to add 10.14 compatibility } else if (os_version < AsciiOSVersionToUint64("10.15")) { // 10.13/10.14 const UINT8 find[] = { 0x89, 0xD8, 0x04, 0xC4, 0x3C, 0x22 }; const UINT8 repl[] = { 0x89, 0xD8, 0x04, 0xC1, 0x3C, 0x22 }; applyKernPatch(find, sizeof(find), repl, comment); // PMheart: attempt to add 10.15 compatibility } else if (os_version < AsciiOSVersionToUint64("10.15.4")) { const UINT8 find[] = { 0x8D, 0x43, 0xC4, 0x3C, 0x22 }; const UINT8 repl[] = { 0x8D, 0x43, 0xC1, 0x3C, 0x22 }; applyKernPatch(find, sizeof(find), repl, comment); } else if (os_version < AsciiOSVersionToUint64("10.16")) { // vector sigma: 10.15.5 Beta 2 build 19F62f and 10.15.4 build 19E287 const UINT8 find[] = { 0x3B, 0x7E, 0x2E, 0x80, 0xC3, 0xC4, 0x80, 0xFB, 0x42 }; const UINT8 repl[] = { 0x00, 0x7E, 0x2E, 0x80, 0xC3, 0xC1, 0x80, 0xFB, 0x42 }; applyKernPatch(find, sizeof(find), repl, comment); */ } DBG("Searching _xcpm_pkg_scope_msr ...\n"); comment = "_xcpm_pkg_scope_msrs"_XS8; if (os_version <= AsciiOSVersionToUint64("10.8.5"_XS8)) { // 10.8.5 const UINT8 find[] = { 0x48, 0x8D, 0x3D, 0x02, 0x71, 0x55, 0x00, 0xBE, 0x07, 0x00, 0x00, 0x00, 0xEB, 0x1F, 0x48, 0x8D, 0x3D, 0xF4, 0x70, 0x55, 0x00, 0xBE, 0x07, 0x00, 0x00, 0x00, 0x31, 0xD2, 0xE8, 0x28, 0x02, 0x00, 0x00 }; const UINT8 repl[] = { 0x48, 0x8D, 0x3D, 0x02, 0x71, 0x55, 0x00, 0xBE, 0x07, 0x00, 0x00, 0x00, 0x90, 0x90, 0x48, 0x8D, 0x3D, 0xF4, 0x70, 0x55, 0x00, 0xBE, 0x07, 0x00, 0x00, 0x00, 0x31, 0xD2, 0x90, 0x90, 0x90, 0x90, 0x90 }; applyKernPatch(find, sizeof(find), repl, comment.c_str()); } else if (os_version < AsciiOSVersionToUint64("10.10"_XS8)) { // 10.9.x const UINT8 find[] = { 0xBE, 0x07, 0x00, 0x00, 0x00, 0x74, 0x13, 0x31, 0xD2, 0xE8, 0x5F, 0x02, 0x00, 0x00 }; const UINT8 repl[] = { 0xBE, 0x07, 0x00, 0x00, 0x00, 0x90, 0x90, 0x31, 0xD2, 0x90, 0x90, 0x90, 0x90, 0x90 }; applyKernPatch(find, sizeof(find), repl, comment.c_str()); } else { // 10.10+ /* patchLocation = 0; // clean out the value just in case for (i = 0; i < 0x1000000; i++) { if (kern[i+0] == 0xBE && kern[i+1] == 0x07 && kern[i+2] == 0x00 && kern[i+3] == 0x00 && kern[i+4] == 0x00 && kern[i+5] == 0x31 && kern[i+6] == 0xD2 && kern[i+7] == 0xE8) { patchLocation = i+7; DBG("Found _xcpm_pkg_scope_msr\n"); break; } } */ UINTN procLocation = searchProc("xcpm_init"_XS8); UINTN symbol1 = searchProc("_xcpm_pkg_scope_msrs"_XS8); patchLocation = FindRelative32(KernelData, procLocation, 0x100, symbol1); if (patchLocation) { for (UINTN i = 7; i < 12; i++) { kern[patchLocation+i] = 0x90; } DBG("Applied _xcpm_pkg_scope_msr patch\n"); } else { DBG("_xcpm_pkg_scope_msr not found, patch aborted\n"); DBG("HaswellEXCPM() <===FALSE\n"); return FALSE; } } DBG("HaswellEXCPM() <===\n"); return TRUE; } // // Enable Broadwell-E/EP PowerManagement on 10.12+ by syscl // BOOLEAN LOADER_ENTRY::BroadwellEPM() { DBG("BroadwellEPM() ===>\n"); UINT32 i; UINTN patchLocation; UINT64 os_version = AsciiOSVersionToUint64(OSVersion); // check OS version suit for patches if (!IsXCPMOSVersionCompat(os_version)) { DBG("BroadwellEPM(): Unsupported macOS.\n"); DBG("BroadwellEPM() <===FALSE\n"); return FALSE; } KernelAndKextPatches.FakeCPUID = (UINT32)(os_version < AsciiOSVersionToUint64("10.10.3"_XS8) ? 0x0306C0 : 0x040674); KernelCPUIDPatch(); DBG("Searching _xcpm_pkg_scope_msr ...\n"); // proc: _xcpm_init @4687b0 // ffffff8000468825 488D3D54527F00 lea rdi, qword [ds:_xcpm_pkg_scope_msrs] // ffffff800046882c BE07000000 mov esi, 0x7 // ffffff8000468831 31D2 xor edx, edx // ffffff8000468833 E838FDFFFF call sub_ffffff8000468570 if (os_version >= AsciiOSVersionToUint64("10.12"_XS8)) { // 10.12+ // patchLocation = 0; // clean out the value just in case // for (i = 0; i < 0x1000000; i++) { // if (kern[i+0] == 0xBE && kern[i+1] == 0x07 && kern[i+2] == 0x00 && kern[i+3] == 0x00 && // kern[i+4] == 0x00 && kern[i+5] == 0x31 && kern[i+6] == 0xD2 && kern[i+7] == 0xE8) { // patchLocation = i+7; // DBG("Found _xcpm_pkg_scope_msr\n"); // break; // } UINTN procLocation = searchProc("xcpm_init"_XS8); UINTN symbol1 = searchProc("_xcpm_pkg_scope_msrs"_XS8); patchLocation = FindRelative32(KernelData, procLocation, 0x100, symbol1); if (patchLocation) { for (i = 7; i < 12; i++) { KernelData[patchLocation+i] = 0x90; } DBG("Applied _xcpm_pkg_scope_msr patch\n"); } else { DBG("_xcpm_pkg_scope_msr not found, patch aborted\n"); DBG("BroadwellEPM() <===FALSE\n"); return FALSE; } } DBG("BroadwellEPM() <===\n"); return TRUE; } // // syscl - this patch provides XCPM support for Haswell low-end(HSWLowEnd) and platforms later than Haswell // implemented by syscl // credit also Pike R.Alpha, stinga11, Sherlocks, vit9696 // BOOLEAN LOADER_ENTRY::HaswellLowEndXCPM() { DBG("HaswellLowEndXCPM() ===>\n"); UINT64 os_version = AsciiOSVersionToUint64(OSVersion); XString8 comment; // check OS version suit for patches if (!IsXCPMOSVersionCompat(os_version)) { DBG("HaswellLowEndXCPM(): Unsupported macOS.\n"); DBG("HaswellLowEndXCPM() <===FALSE\n"); return FALSE; } KernelAndKextPatches.FakeCPUID = (UINT32)(0x0306A0); // correct FakeCPUID KernelCPUIDPatch(); // 10.8.5 - 10.11.x no need the following kernel patches on Haswell Celeron/Pentium if (os_version >= AsciiOSVersionToUint64("10.8.5"_XS8) && os_version < AsciiOSVersionToUint64("10.12"_XS8)) { DBG("HaswellLowEndXCPM() <===\n"); return TRUE; } // _xcpm_idle //this is a part of KernelPM /* if (use_xcpm_idle) { DBG("HWPEnable - ON.\n"); comment = "_xcpm_idle"; const UINT8 find[] = { 0xB9, 0xE2, 0x00, 0x00, 0x00, 0x0F, 0x30 }; const UINT8 repl[] = { 0xB9, 0xE2, 0x00, 0x00, 0x00, 0x90, 0x90 }; applyKernPatch(find, sizeof(find), repl, comment); } */ comment = "_xcpm_bootstrap"_XS8; UINTN procLocation = searchProc(comment); UINTN featureCall = searchProc("_cpuid_features"_XS8); UINTN place = FindRelative32(KernelData, procLocation, 0x100, featureCall); for (UINTN i = 10; i < 20; ++i) { if (KernelData[place + i] == 0xC4) { KernelData[place + i] = 0xC6; if (KernelData[(place + i) - 5] == 0x3B) { KernelData[(place + i) - 5] = 0x00; } break; } } /* if (os_version <= AsciiOSVersionToUint64("10.12.5")) { // 10.12 - 10.12.5 const UINT8 find[] = { 0x83, 0xC3, 0xC4, 0x83, 0xFB, 0x22 }; const UINT8 repl[] = { 0x83, 0xC3, 0xC6, 0x83, 0xFB, 0x22 }; applyKernPatch(find, sizeof(find), repl, comment); } else if (os_version < AsciiOSVersionToUint64("10.13")) { // 10.12.6 const UINT8 find[] = { 0x8D, 0x43, 0xC4, 0x83, 0xF8, 0x22 }; const UINT8 repl[] = { 0x8D, 0x43, 0xC6, 0x83, 0xF8, 0x22 }; applyKernPatch(find, sizeof(find), repl, comment); } else if (os_version < AsciiOSVersionToUint64("10.15")) { // 10.13/10.14 // ; Basic Block Input Regs: rbx - Killed Regs: rax // ffffff80004fa0f7 89D8 mov eax, ebx // ffffff80004fa0f9 04C4 add al, 0xc4 // ffffff80004fa0fb 3C22 cmp al, 0x22 // ffffff80004fa0fd 7722 jnbe 0xffffff80004fa121 const UINT8 find[] = { 0x89, 0xD8, 0x04, 0xC4, 0x3C, 0x22 }; const UINT8 repl[] = { 0x89, 0xD8, 0x04, 0xC6, 0x3C, 0x22 }; applyKernPatch(find, sizeof(find), repl, comment); // PMheart: attempt to add 10.15 compatibility } else if (os_version < AsciiOSVersionToUint64("10.15.4")) { const UINT8 find[] = { 0x8D, 0x43, 0xC4, 0x3C, 0x22 }; const UINT8 repl[] = { 0x8D, 0x43, 0xC6, 0x3C, 0x22 }; applyKernPatch(find, sizeof(find), repl, comment); } else if (os_version < AsciiOSVersionToUint64("10.16")) { // vector sigma: 10.15.5 Beta 2 build 19F62f and 10.15.4 build 19E287 const UINT8 find[] = { 0x3B, 0x7E, 0x2E, 0x80, 0xC3, 0xC4, 0x80, 0xFB, 0x42 }; const UINT8 repl[] = { 0x00, 0x7E, 0x2E, 0x80, 0xC3, 0xC6, 0x80, 0xFB, 0x42 }; applyKernPatch(find, sizeof(find), repl, comment); } */ comment = "_cpuid_set_info_rdmsr"_XS8; // PMheart: bytes seem stable as of 10.12 if (os_version >= AsciiOSVersionToUint64("10.12"_XS8)) { // 10.12+ const UINT8 find[] = { 0xB9, 0xA0, 0x01, 0x00, 0x00, 0x0F, 0x32 }; const UINT8 repl[] = { 0xB9, 0xA0, 0x01, 0x00, 0x00, 0x31, 0xC0 }; applyKernPatch(find, sizeof(find), repl, comment.c_str()); } DBG("HaswellLowEndXCPM() <===\n"); return TRUE; } // // this patch provides XCPM support for Ivy Bridge. by PMheart // BOOLEAN LOADER_ENTRY::KernelIvyBridgeXCPM() { XString8 comment; // UINT32 i; UINTN patchLocation; UINT64 os_version = AsciiOSVersionToUint64(OSVersion); // check whether Ivy Bridge if (gCPUStructure.Model != CPU_MODEL_IVY_BRIDGE) { DBG("KernelIvyBridgeXCPM(): Unsupported platform.\nRequires Ivy Bridge, aborted\n"); DBG("KernelIvyBridgeXCPM() <===FALSE\n"); return FALSE; } // check OS version suit for patches // PMheart: attempt to add 10.14 compatibility if (!IsXCPMOSVersionCompat(os_version)) { DBG("KernelIvyBridgeXCPM():Unsupported macOS.\n"); DBG("KernelIvyBridgeXCPM() <===FALSE\n"); return FALSE; } else if (os_version >= AsciiOSVersionToUint64("10.8.5"_XS8) && os_version < AsciiOSVersionToUint64("10.12"_XS8)) { // 10.8.5 - 10.11.x no need the following kernel patches on Ivy Bridge - we just use -xcpm boot-args DBG("KernelIvyBridgeXCPM() <===\n"); return TRUE; } DBG("Searching _xcpm_pkg_scope_msr ...\n"); if (os_version >= AsciiOSVersionToUint64("10.12"_XS8)) { // 10.12+ /* patchLocation = 0; // clean out the value just in case for (i = 0; i < 0x1000000; i++) { if (kern[i+0] == 0xBE && kern[i+1] == 0x07 && kern[i+2] == 0x00 && kern[i+3] == 0x00 && kern[i+4] == 0x00 && kern[i+5] == 0x31 && kern[i+6] == 0xD2 && kern[i+7] == 0xE8) { patchLocation = i+7; DBG("Found _xcpm_pkg_scope_msr\n"); break; } } */ UINTN procLocation = searchProc("xcpm_init"_XS8); UINTN symbol1 = searchProc("_xcpm_pkg_scope_msrs"_XS8); patchLocation = FindRelative32(KernelData, procLocation, 0x100, symbol1); if (patchLocation) { for (int i = 7; i < 12; i++) { KernelData[patchLocation+i] = 0x90; } DBG("Applied _xcpm_pkg_scope_msr patch\n"); } else { DBG("_xcpm_pkg_scope_msr not found, patch aborted\n"); DBG("KernelIvyBridgeXCPM() <===FALSE\n"); return FALSE; } } comment = "_xcpm_bootstrap"_XS8; UINTN procLocation = searchProc(comment); UINTN featureCall = searchProc("_cpuid_features"_XS8); UINTN place = FindRelative32(KernelData, procLocation, 0x100, featureCall); for (UINTN i = 10; i < 20; ++i) { if (KernelData[place + i] == 0xC4) { KernelData[place + i] = 0xC6; if (KernelData[(place + i) - 5] == 0x3B) { KernelData[(place + i) - 5] = 0x00; } break; } } /* if (os_version <= AsciiOSVersionToUint64("10.12.5")) { // 10.12 - 10.12.5 const UINT8 find[] = { 0x83, 0xC3, 0xC4, 0x83, 0xFB, 0x22 }; const UINT8 repl[] = { 0x83, 0xC3, 0xC6, 0x83, 0xFB, 0x22 }; applyKernPatch(find, sizeof(find), repl, comment); } else if (os_version < AsciiOSVersionToUint64("10.13")) { // 10.12.6 const UINT8 find[] = { 0x8D, 0x43, 0xC4, 0x83, 0xF8, 0x22 }; const UINT8 repl[] = { 0x8D, 0x43, 0xC6, 0x83, 0xF8, 0x22 }; applyKernPatch(find, sizeof(find), repl, comment); // PMheart: attempt to add 10.14 compatibility } else if (os_version < AsciiOSVersionToUint64("10.15")) { // 10.13/10.14 const UINT8 find[] = { 0x89, 0xD8, 0x04, 0xC4, 0x3C, 0x22 }; const UINT8 repl[] = { 0x89, 0xD8, 0x04, 0xC6, 0x3C, 0x22 }; applyKernPatch(find, sizeof(find), repl, comment); // PMheart: attempt to add 10.15 compatibility } else if (os_version < AsciiOSVersionToUint64("10.15.4")) { const UINT8 find[] = { 0x8D, 0x43, 0xC4, 0x3C, 0x22 }; const UINT8 repl[] = { 0x8D, 0x43, 0xC6, 0x3C, 0x22 }; applyKernPatch(find, sizeof(find), repl, comment); } else if (os_version < AsciiOSVersionToUint64("10.16")) { // vector sigma: 10.15.5 Beta 2 build 19F62f and 10.15.4 build 19E287 const UINT8 find[] = { 0x3B, 0x7E, 0x2E, 0x80, 0xC3, 0xC4, 0x80, 0xFB, 0x42 }; const UINT8 repl[] = { 0x00, 0x7E, 0x2E, 0x80, 0xC3, 0xC6, 0x80, 0xFB, 0x42 }; applyKernPatch(find, sizeof(find), repl, comment); } */ DBG("KernelIvyBridgeXCPM() <===\n"); return TRUE; } // // this patch provides XCPM support for Ivy Bridge-E. by PMheart // attempt to enable XCPM for Ivy-E, still need to test further // BOOLEAN LOADER_ENTRY::KernelIvyE5XCPM() { UINT8 *kern = (UINT8*)KernelData; XString8 comment; // UINT32 i; UINTN patchLocation; UINT64 os_version = AsciiOSVersionToUint64(OSVersion); // check whether Ivy Bridge-E5 if (gCPUStructure.Model != CPU_MODEL_IVY_BRIDGE_E5) { DBG("KernelIvyE5XCPM(): Unsupported platform.\nRequires Ivy Bridge-E, aborted\n"); DBG("KernelIvyE5XCPM() <===FALSE\n"); return FALSE; } // check OS version suit for patches // PMheart: attempt to add 10.15 compatibility if (!IsXCPMOSVersionCompat(os_version)) { DBG("KernelIvyE5XCPM(): Unsupported macOS.\n"); DBG("KernelIvyE5XCPM() <===FALSE\n"); return FALSE; } // _cpuid_set_info // TODO: should we use FakeCPUID instead? comment = "_cpuid_set_info"_XS8; if (os_version <= AsciiOSVersionToUint64("10.8.5"_XS8)) { // 10.8.5 const UINT8 find[] = { 0x83, 0xF8, 0x3C, 0x74, 0x2D }; const UINT8 repl[] = { 0x83, 0xF8, 0x3E, 0x74, 0x2D }; applyKernPatch(find, sizeof(find), repl, comment.c_str()); } else if (os_version == AsciiOSVersionToUint64("10.9"_XS8) || os_version == AsciiOSVersionToUint64("10.9.1"_XS8)) { // 10.9.0 - 10.9.1 const UINT8 find[] = { 0x83, 0xF8, 0x3C, 0x75, 0x07 }; const UINT8 repl[] = { 0x83, 0xF8, 0x3E, 0x75, 0x07 }; applyKernPatch(find, sizeof(find), repl, comment.c_str()); } // 10.9.2+: native support reached, no need to patch // _xcpm_pkg_scope_msrs DBG("Searching _xcpm_pkg_scope_msrs ...\n"); comment = "_xcpm_pkg_scope_msrs"_XS8; if (os_version <= AsciiOSVersionToUint64("10.8.5"_XS8)) { // 10.8.5 const UINT8 find[] = { 0x48, 0x8D, 0x3D, 0x02, 0x71, 0x55, 0x00, 0xBE, 0x07, 0x00, 0x00, 0x00, 0xEB, 0x1F, 0x48, 0x8D, 0x3D, 0xF4, 0x70, 0x55, 0x00, 0xBE, 0x07, 0x00, 0x00, 0x00, 0x31, 0xD2, 0xE8, 0x28, 0x02, 0x00, 0x00 }; const UINT8 repl[] = { 0x48, 0x8D, 0x3D, 0x02, 0x71, 0x55, 0x00, 0xBE, 0x07, 0x00, 0x00, 0x00, 0x90, 0x90, 0x48, 0x8D, 0x3D, 0xF4, 0x70, 0x55, 0x00, 0xBE, 0x07, 0x00, 0x00, 0x00, 0x31, 0xD2, 0x90, 0x90, 0x90, 0x90, 0x90 }; applyKernPatch(find, sizeof(find), repl, comment.c_str()); } else if (os_version < AsciiOSVersionToUint64("10.10"_XS8)) { // 10.9.x const UINT8 find[] = { 0xBE, 0x07, 0x00, 0x00, 0x00, 0x74, 0x13, 0x31, 0xD2, 0xE8, 0x5F, 0x02, 0x00, 0x00 }; const UINT8 repl[] = { 0xBE, 0x07, 0x00, 0x00, 0x00, 0x90, 0x90, 0x31, 0xD2, 0x90, 0x90, 0x90, 0x90, 0x90 }; applyKernPatch(find, sizeof(find), repl, comment.c_str()); } else { // 10.10+ // patchLocation = 0; // clean out the value just in case UINTN procLocation = searchProc("xcpm_init"_XS8); UINTN symbol1 = searchProc(comment); patchLocation = FindRelative32(kern, procLocation, 0x100, symbol1); /* for (i = 0; i < 0x1000000; i++) { if (kern[i+0] == 0xBE && kern[i+1] == 0x07 && kern[i+2] == 0x00 && kern[i+3] == 0x00 && kern[i+4] == 0x00 && kern[i+5] == 0x31 && kern[i+6] == 0xD2 && kern[i+7] == 0xE8) { patchLocation = i+7; DBG("Found _xcpm_pkg_scope_msr\n"); break; } } */ if (patchLocation) { for (int i = 7; i < 12; i++) { kern[patchLocation+i] = 0x90; } DBG("Applied _xcpm_pkg_scope_msr patch\n"); } else { // DBG("_xcpm_pkg_scope_msr not found, patch aborted\n"); DBG("KernelIvyE5XCPM() <===FALSE\n"); return FALSE; } } // _xcpm_bootstrap comment = "_xcpm_bootstrap"_XS8; if (os_version <= AsciiOSVersionToUint64("10.8.5"_XS8)) { // 10.8.5 const UINT8 find[] = { 0x83, 0xFB, 0x3C, 0x75, 0x54 }; const UINT8 repl[] = { 0x83, 0xFB, 0x3E, 0x75, 0x54 }; applyKernPatch(find, sizeof(find), repl, comment.c_str()); } else if (os_version < AsciiOSVersionToUint64("10.10"_XS8)) { // 10.9.x const UINT8 find[] = { 0x83, 0xFB, 0x3C, 0x75, 0x68 }; const UINT8 repl[] = { 0x83, 0xFB, 0x3E, 0x75, 0x68 }; applyKernPatch(find, sizeof(find), repl, comment.c_str()); } else if (os_version <= AsciiOSVersionToUint64("10.10.2"_XS8)) { // 10.10 - 10.10.2 const UINT8 find[] = { 0x83, 0xFB, 0x3C, 0x75, 0x63 }; const UINT8 repl[] = { 0x83, 0xFB, 0x3E, 0x75, 0x63 }; applyKernPatch(find, sizeof(find), repl, comment.c_str()); } else if (os_version <= AsciiOSVersionToUint64("10.10.5"_XS8)) { // 10.10.3 - 10.10.5 const UINT8 find[] = { 0x83, 0xC3, 0xC6, 0x83, 0xFB, 0x0D }; const UINT8 repl[] = { 0x83, 0xC3, 0xC4, 0x83, 0xFB, 0x0D }; applyKernPatch(find, sizeof(find), repl, comment.c_str()); } else if (os_version <= AsciiOSVersionToUint64("10.11"_XS8)) { // 10.11 DB/PB - 10.11.0 const UINT8 find[] = { 0x83, 0xC3, 0xC6, 0x83, 0xFB, 0x0D }; const UINT8 repl[] = { 0x83, 0xC3, 0xC4, 0x83, 0xFB, 0x0D }; applyKernPatch(find, sizeof(find), repl, comment.c_str()); } else if (os_version <= AsciiOSVersionToUint64("10.11.6"_XS8)) { // 10.11.1 - 10.11.6 const UINT8 find[] = { 0x83, 0xC3, 0xBB, 0x83, 0xFB, 0x09 }; const UINT8 repl[] = { 0x83, 0xC3, 0xB9, 0x83, 0xFB, 0x09 }; applyKernPatch(find, sizeof(find), repl, comment.c_str()); } else { UINTN procLocation = searchProc(comment); UINTN featureCall = searchProc("_cpuid_features"_XS8); UINTN place = FindRelative32(KernelData, procLocation, 0x100, featureCall); for (UINTN i = 10; i < 20; ++i) { if (KernelData[place + i] == 0xC4) { KernelData[place + i] = 0xC1; if (KernelData[(place + i) - 5] == 0x3B) { KernelData[(place + i) - 5] = 0x00; } break; } } /* if (os_version <= AsciiOSVersionToUint64("10.12.5")) { // 10.12 - 10.12.5 const UINT8 find[] = { 0x83, 0xC3, 0xC4, 0x83, 0xFB, 0x22 }; const UINT8 repl[] = { 0x83, 0xC3, 0xC2, 0x83, 0xFB, 0x22 }; applyKernPatch(find, sizeof(find), repl, comment); } else if (os_version < AsciiOSVersionToUint64("10.13")) { // 10.12.6 const UINT8 find[] = { 0x8D, 0x43, 0xC4, 0x83, 0xF8, 0x22 }; const UINT8 repl[] = { 0x8D, 0x43, 0xC2, 0x83, 0xF8, 0x22 }; applyKernPatch(find, sizeof(find), repl, comment); // PMheart: attempt to add 10.14 compatibility } else if (os_version < AsciiOSVersionToUint64("10.15")) { // 10.13/10.14 const UINT8 find[] = { 0x89, 0xD8, 0x04, 0xC4, 0x3C, 0x22 }; const UINT8 repl[] = { 0x89, 0xD8, 0x04, 0xC1, 0x3C, 0x22 }; applyKernPatch(find, sizeof(find), repl, comment); // PMheart: attempt to add 10.15 compatibility } else if (os_version < AsciiOSVersionToUint64("10.15.4")) { const UINT8 find[] = { 0x8D, 0x43, 0xC4, 0x3C, 0x22 }; const UINT8 repl[] = { 0x8D, 0x43, 0xC1, 0x3C, 0x22 }; applyKernPatch(find, sizeof(find), repl, comment); } else if (os_version < AsciiOSVersionToUint64("10.16")) { // vector sigma: 10.15.5 Beta 2 build 19F62f and 10.15.4 build 19E287 const UINT8 find[] = { 0x3B, 0x7E, 0x2E, 0x80, 0xC3, 0xC4, 0x80, 0xFB, 0x42 }; const UINT8 repl[] = { 0x00, 0x7E, 0x2E, 0x80, 0xC3, 0xC1, 0x80, 0xFB, 0x42 }; applyKernPatch(find, sizeof(find), repl, comment); */ } DBG("KernelIvyE5XCPM() <===\n"); return TRUE; } #if 0 VOID Patcher_SSE3_6(VOID* kernelData) { UINT8* bytes = (UINT8*)kernelData; UINT32 patchLocation1 = 0; UINT32 patchLocation2 = 0; UINT32 patchlast = 0; UINT32 i; //UINT32 Length = sizeof(kernelData); // DBG("Start find SSE3 address\n"); i=0; //for (i=0;i 1000) ncmds = 0; for (cnt = 0; cnt < ncmds; cnt++) { loadCommand = (struct load_command *)(binary + binaryIndex); cmdsize = loadCommand->cmdsize; switch (loadCommand->cmd) { case LC_SYMTAB: // *symCmd = binaryIndex; // struct symtab_command { // uint32_t cmd; /* LC_SYMTAB == 2 */ // uint32_t cmdsize; /* sizeof(struct symtab_command) */ // uint32_t symoff; /* symbol table offset */ // uint32_t nsyms; /* number of symbol table entries */ // uint32_t stroff; /* string table offset */ // uint32_t strsize; /* string table size in bytes */ // }; //AddrVtable = symCmd->symoff; //SizeVtable = symCmd->nsyms; //NamesTable = symCmd->stroff; //DBG("SymTab: AddrVtable=0x%x SizeVtable=0x%x NamesTable=0x%x\n", AddrVtable, SizeVtable, NamesTable); return binaryIndex; //continue search for last command? or return here? default: break; } binaryIndex += cmdsize; } return 0; } void DumpSeg(struct segment_command_64 *segCmd64) { DBG("segCmd64->segname = %s\n",segCmd64->segname); DBG("segCmd64->vmaddr = 0x%08llX\n",segCmd64->vmaddr); DBG("segCmd64->vmsize = 0x%08llX\n",segCmd64->vmsize); DBG("fileoff = 0x%08llX\n",segCmd64->fileoff); DBG("filesize = 0x%08llX\n",segCmd64->filesize); //DBG("maxprot = 0x%08X\n",segCmd64->maxprot); //DBG("initprot = 0x%08X\n",segCmd64->initprot); //DBG("nsects = 0x%08X\n",segCmd64->nsects); DBG("flags = 0x%08X\n",segCmd64->flags); } UINT32 LOADER_ENTRY::GetTextExec() { UINT32 ncmds, cmdsize; UINT32 binaryIndex; struct segment_command_64 *segCmd64; ncmds = MACH_GET_NCMDS(KernelData); binaryIndex = sizeof(struct mach_header_64); for (UINTN cnt = 0; cnt < ncmds; cnt++) { segCmd64 = (struct segment_command_64 *)(KernelData + binaryIndex); cmdsize = segCmd64->cmdsize; switch (segCmd64->cmd) { case LC_SEGMENT_64: //19 if (strcmp(segCmd64->segname, kTextExecSegment) == 0) { return (UINT32)(segCmd64->fileoff); } break; default: break; } binaryIndex += cmdsize; } return 0; } void LOADER_ENTRY::Get_PreLink() { UINT32 ncmds, cmdsize; UINT32 binaryIndex; UINT8* binary = &KernelData[0]; struct load_command *loadCommand; // struct segment_command *segCmd; struct segment_command_64 *segCmd64; // struct symtab_command *symCmd; UINTN kernelvmAddr = 0; if (is64BitKernel) { binaryIndex = sizeof(struct mach_header_64); } else { binaryIndex = sizeof(struct mach_header); } ncmds = MACH_GET_NCMDS(binary); for (UINTN cnt = 0; cnt < ncmds; cnt++) { loadCommand = (struct load_command *)(binary + binaryIndex); cmdsize = loadCommand->cmdsize; switch (loadCommand->cmd) { case LC_SEGMENT_64: //19 segCmd64 = (struct segment_command_64 *)loadCommand; if (strcmp(segCmd64->segname, kTextSegment) == 0) { kernelvmAddr = segCmd64->vmaddr; } if (strcmp(segCmd64->segname, kPrelinkTextSegment) == 0) { // DBG("Found PRELINK_TEXT, 64bit\n"); if (segCmd64->vmsize > 0) { // 64bit segCmd64->vmaddr is 0xffffff80xxxxxxxx // PrelinkTextAddr = xxxxxxxx + KernelRelocBase //? PrelinkTextAddr = (UINT32)(segCmd64->vmaddr ? (segCmd64->vmaddr - kernelvmAddr) + KernelRelocBase : 0); PrelinkTextAddr = (UINT32)(segCmd64->vmaddr ? segCmd64->vmaddr + KernelRelocBase : 0); PrelinkTextSize = (UINT32)(segCmd64->filesize); PrelinkTextLoadCmdAddr = binaryIndex; //(UINT32)(UINTN)segCmd64; } #if KERNEL_DEBUG DumpSeg(segCmd64); DBG("PrelinkTextLoadCmdAddr = 0x%X, PrelinkTextAddr = 0x%X, PrelinkTextSize = 0x%X\n", PrelinkTextLoadCmdAddr, PrelinkTextAddr, PrelinkTextSize); UINT32 PrelinkTextAddr32 = (UINT32)(segCmd64->vmaddr - kernelvmAddr); for (int j=0; j<30; ++j) { DBG("%02x", binary[PrelinkTextAddr32+j]); } DBG("\n"); #endif } if (strcmp(segCmd64->segname, kPrelinkInfoSegment) == 0) { UINT32 sectionIndex; struct section_64 *sect; DumpSeg(segCmd64); sectionIndex = sizeof(struct segment_command_64); while(sectionIndex < segCmd64->cmdsize) { sect = (struct section_64 *)((UINT8*)segCmd64 + sectionIndex); if(strcmp(sect->sectname, kPrelinkInfoSection) == 0 && strcmp(sect->segname, kPrelinkInfoSegment) == 0) { if (sect->size > 0) { // 64bit sect->addr is 0xffffff80xxxxxxxx // PrelinkInfoAddr = xxxxxxxx + KernelRelocBase PrelinkInfoLoadCmdAddr = binaryIndex + sectionIndex; //(UINT32)(UINTN)sect; PrelinkInfoAddr = (UINT32)(sect->addr ? sect->addr + KernelRelocBase : 0); PrelinkInfoSize = (UINT32)sect->size; } DBG("__info found at 0x%llx: addr = 0x%x, size = 0x%llx\n", (UINTN)sect, sect->offset, sect->size); DBG("PrelinkInfoLoadCmdAddr = 0x%X, PrelinkInfoAddr = 0x%X, PrelinkInfoSize = 0x%X\n", PrelinkInfoLoadCmdAddr, PrelinkInfoAddr, PrelinkInfoSize); } sectionIndex += sizeof(struct section_64); } } break; #if 0 //exclude 32bit case LC_SEGMENT: segCmd = (struct segment_command *)loadCommand; //DBG("segCmd->segname = %s\n",segCmd->segname); //DBG("segCmd->vmaddr = 0x%08X\n",segCmd->vmaddr) //DBG("segCmd->vmsize = 0x%08X\n",segCmd->vmsize); if (strcmp(segCmd->segname, kPrelinkTextSegment) == 0) { //DBG("Found PRELINK_TEXT, 32bit\n"); if (segCmd->vmsize > 0) { // PrelinkTextAddr = vmaddr + KernelRelocBase PrelinkTextAddr = (UINT32)(segCmd->vmaddr ? segCmd->vmaddr + KernelRelocBase : 0); PrelinkTextSize = (UINT32)segCmd->vmsize; PrelinkTextLoadCmdAddr = (UINT32)(UINTN)segCmd; } //DBG("at 0x%llx: vmaddr = 0x%x, vmsize = 0x%x\n", (UINTN)segCmd, segCmd->vmaddr, segCmd->vmsize); //DBG("PrelinkTextLoadCmdAddr = 0x%X, PrelinkTextAddr = 0x%X, PrelinkTextSize = 0x%X\n", // PrelinkTextLoadCmdAddr, PrelinkTextAddr, PrelinkTextSize); //gBS->Stall(30*1000000); } if (strcmp(segCmd->segname, kPrelinkInfoSegment) == 0) { UINT32 sectionIndex; struct section *sect; //DBG("Found PRELINK_INFO, 32bit\n"); //DBG("cmd = 0x%08X\n",segCmd->cmd); //DBG("cmdsize = 0x%08X\n",segCmd->cmdsize); //DBG("vmaddr = 0x%08X\n",segCmd->vmaddr); //DBG("vmsize = 0x%08X\n",segCmd->vmsize); //DBG("fileoff = 0x%08X\n",segCmd->fileoff); //DBG("filesize = 0x%08X\n",segCmd->filesize); //DBG("maxprot = 0x%08X\n",segCmd->maxprot); //DBG("initprot = 0x%08X\n",segCmd->initprot); //DBG("nsects = 0x%08X\n",segCmd->nsects); //DBG("flags = 0x%08X\n",segCmd->flags); sectionIndex = sizeof(struct segment_command); while(sectionIndex < segCmd->cmdsize) { sect = (struct section *)((UINT8*)segCmd + sectionIndex); sectionIndex += sizeof(struct section); if(strcmp(sect->sectname, kPrelinkInfoSection) == 0 && strcmp(sect->segname, kPrelinkInfoSegment) == 0) { if (sect->size > 0) { // PrelinkInfoAddr = sect->addr + KernelRelocBase PrelinkInfoLoadCmdAddr = (UINT32)(UINTN)sect; PrelinkInfoAddr = (UINT32)(sect->addr ? sect->addr + KernelRelocBase : 0); PrelinkInfoSize = (UINT32)sect->size; } //DBG("__info found at 0x%llx: addr = 0x%x, size = 0x%x\n", (UINTN)sect, sect->addr, sect->size); //DBG("PrelinkInfoLoadCmdAddr = 0x%X, PrelinkInfoAddr = 0x%X, PrelinkInfoSize = 0x%X\n", // PrelinkInfoLoadCmdAddr, PrelinkInfoAddr, PrelinkInfoSize); //gBS->Stall(30*1000000); } } } break; #endif default: break; } binaryIndex += cmdsize; } //gBS->Stall(20*1000000); return; } VOID LOADER_ENTRY::FindBootArgs() { UINT8 *ptr; UINT8 archMode = sizeof(UINTN) * 8; // start searching from 0x200000. ptr = (UINT8*)0x200000ull; while(TRUE) { // check bootargs for 10.7 and up bootArgs2 = (BootArgs2*)ptr; if (bootArgs2->Version==2 && (bootArgs2->Revision==0 || bootArgs2->Revision==1) // plus additional checks - some values are not inited by boot.efi yet && bootArgs2->efiMode == archMode && bootArgs2->kaddr == 0 && bootArgs2->ksize == 0 && bootArgs2->efiSystemTable == 0 ) { // set vars dtRoot = (CHAR8*)(UINTN)bootArgs2->deviceTreeP; dtLength = &bootArgs2->deviceTreeLength; KernelSlide = bootArgs2->kslide; DBG_RT( "Found bootArgs2 at 0x%llX, DevTree at 0x%llX\n", (UINTN)ptr, (UINTN)bootArgs2->deviceTreeP); //DBG_RT("bootArgs2->kaddr = 0x%llX and bootArgs2->ksize = 0x%llX\n", bootArgs2->kaddr, bootArgs2->ksize); //DBG("bootArgs2->efiMode = 0x%02X\n", bootArgs2->efiMode); DBG_RT( "bootArgs2->CommandLine = %s\n", bootArgs2->CommandLine); DBG_RT( "bootArgs2->flags = 0x%hx\n", bootArgs2->flags); DBG_RT( "bootArgs2->kslide = 0x%x\n", bootArgs2->kslide); DBG_RT( "bootArgs2->bootMemStart = 0x%llx\n", bootArgs2->bootMemStart); // if (KernelAndKextPatches && KernelAndKextPatches.KPDebug) Stall(5000000); // disable other pointer bootArgs1 = NULL; break; } // check bootargs for 10.4 - 10.6.x /* bootArgs1 = (BootArgs1*)ptr; if (bootArgs1->Version==1 && (bootArgs1->Revision==6 || bootArgs1->Revision==5 || bootArgs1->Revision==4) // plus additional checks - some values are not inited by boot.efi yet && bootArgs1->efiMode == archMode && bootArgs1->kaddr == 0 && bootArgs1->ksize == 0 && bootArgs1->efiSystemTable == 0 ) { // set vars dtRoot = (CHAR8*)(UINTN)bootArgs1->deviceTreeP; dtLength = &bootArgs1->deviceTreeLength; DBG_RT( "Found bootArgs1 at 0x%8s, DevTree at %p\n", ptr, dtRoot); //DBG("bootArgs1->kaddr = 0x%08X and bootArgs1->ksize = 0x%08X\n", bootArgs1->kaddr, bootArgs1->ksize); //DBG("bootArgs1->efiMode = 0x%02X\n", bootArgs1->efiMode); // disable other pointer bootArgs2 = NULL; break; } */ ptr += 0x1000; if ((UINTN)ptr > 0x70000000ull) { DBG_RT("bootArgs not found\n"); bootArgs2 = 0; break; } } } BOOLEAN LOADER_ENTRY::KernelUserPatch() { INTN Num, y = 0; // old confuse // We are using KernelAndKextPatches as set by Custom Entries. // while config patches go to gSettings.KernelAndKextPatches // how to resolve it? for (size_t i = 0 ; i < KernelAndKextPatches.KernelPatches.size(); ++i) { DBG( "Patch[%zu]: %s\n", i, KernelAndKextPatches.KernelPatches[i].Label.c_str()); if (!KernelAndKextPatches.KernelPatches[i].MenuItem.BValue) { //DBG_RT( "Patch[%d]: %a :: is not allowed for booted OS %a\n", i, KernelAndKextPatches.KernelPatches[i].Label, OSVersion); DBG( "==> disabled\n"); continue; } // if we modify directly KernelAndKextPatches.KernelPatches[i].SearchLen, it will wrong for next driver UINTN SearchLen = KernelAndKextPatches.KernelPatches[i].SearchLen; bool once = false; UINTN procLen = 0; UINTN procAddr = searchProc(KernelAndKextPatches.KernelPatches[i].ProcedureName); DBG("procedure %s found at 0x%llx\n", KernelAndKextPatches.KernelPatches[i].ProcedureName.c_str(), procAddr); if (SearchLen == 0) { SearchLen = KERNEL_MAX_SIZE; procLen = KERNEL_MAX_SIZE - procAddr; once = true; } else { procLen = SearchLen; } UINT8 * curs = &KernelData[procAddr]; UINTN j = 0; while (j < KERNEL_MAX_SIZE) { if (KernelAndKextPatches.KernelPatches[i].StartPattern.isEmpty() || //old behavior CompareMemMask((const UINT8*)curs, KernelAndKextPatches.KernelPatches[i].StartPattern.data(), KernelAndKextPatches.KernelPatches[i].StartPattern.size(), KernelAndKextPatches.KernelPatches[i].StartMask.data(), KernelAndKextPatches.KernelPatches[i].StartPattern.size())) { DBG( " StartPattern found\n"); Num = SearchAndReplaceMask(curs, procLen, (const UINT8*)KernelAndKextPatches.KernelPatches[i].Data.data(), (const UINT8*)KernelAndKextPatches.KernelPatches[i].MaskFind.data(), KernelAndKextPatches.KernelPatches[i].Data.size(), (const UINT8*)KernelAndKextPatches.KernelPatches[i].Patch.data(), (const UINT8*)KernelAndKextPatches.KernelPatches[i].MaskReplace.data(), KernelAndKextPatches.KernelPatches[i].Count ); if (Num) { y++; curs += SearchLen - 1; j += SearchLen - 1; } DBG( "==> %s : %lld replaces done\n", Num ? "Success" : "Error", Num); if ( once || KernelAndKextPatches.KernelPatches[i].StartPattern.isEmpty() ) { break; } } j++; curs++; } } if (KernelAndKextPatches.KPDebug) { gBS->Stall(2000000); } return (y != 0); } BOOLEAN LOADER_ENTRY::BooterPatch(IN UINT8 *BooterData, IN UINT64 BooterSize) { INTN Num, y = 0; for (size_t i = 0 ; i < KernelAndKextPatches.BootPatches.size(); ++i) { // if we modify directly KernelAndKextPatches.BootPatches[i].SearchLen, it will wrong for next driver UINTN SearchLen = KernelAndKextPatches.BootPatches[i].SearchLen; if (!SearchLen) { SearchLen = BooterSize; } DBG( "Patch[%zu]: %s\n", i, KernelAndKextPatches.BootPatches[i].Label.c_str()); if (!KernelAndKextPatches.BootPatches[i].MenuItem.BValue) { DBG( "==> disabled\n"); continue; } UINT8 * curs = BooterData; UINTN j = 0; while (j < BooterSize) { if (KernelAndKextPatches.BootPatches[i].StartPattern.isEmpty() || //old behavior CompareMemMask((const UINT8*)curs, (const UINT8*)KernelAndKextPatches.BootPatches[i].StartPattern.data(), KernelAndKextPatches.BootPatches[i].StartPattern.size(), (const UINT8*)KernelAndKextPatches.BootPatches[i].StartMask.data(), KernelAndKextPatches.BootPatches[i].StartPattern.size())) { DBG( " StartPattern found\n"); Num = SearchAndReplaceMask(curs, SearchLen, (const UINT8*)KernelAndKextPatches.BootPatches[i].Data.data(), (const UINT8*)KernelAndKextPatches.BootPatches[i].MaskFind.data(), KernelAndKextPatches.BootPatches[i].Data.size(), (const UINT8*)KernelAndKextPatches.BootPatches[i].Patch.data(), (const UINT8*)KernelAndKextPatches.BootPatches[i].MaskReplace.data(), KernelAndKextPatches.BootPatches[i].Count ); if (Num) { y++; curs += SearchLen - 1; j += SearchLen - 1; } DBG( "==> %s : %lld replaces done\n", Num ? "Success" : "Error", Num); if ( KernelAndKextPatches.BootPatches[i].StartPattern.isEmpty() ) { break; } } j++; curs++; } } // if (KernelAndKextPatches.KPDebug) { // gBS->Stall(2000000); // } Stall(2000000); return (y != 0); } VOID LOADER_ENTRY::KernelAndKextPatcherInit() { if (PatcherInited) { DBG("patcher inited\n"); return; } PatcherInited = TRUE; // KernelRelocBase will normally be 0 // but if OsxAptioFixDrv is used, then it will be > 0 SetKernelRelocBase(); DBG("KernelRelocBase = %llx\n", KernelRelocBase); // Find bootArgs - we need then for proper detection // of kernel Mach-O header FindBootArgs(); if (bootArgs1 == NULL && bootArgs2 == NULL) { DBG_RT("BootArgs not found - skipping patches!\n"); return; } // Find kernel Mach-O header: // for 10.4 - 10.5: 0x00111000 // for 10.6 - 10.7: 0x00200000 // for ML: bootArgs2->kslide + 0x00200000 // for AptioFix booting - it's always at KernelRelocBase + 0x00200000 // UINT64 os_version = AsciiOSVersionToUint64(OSVersion); DBG("os_version=%s\n", OSVersion.c_str()); // if (os_version < AsciiOSVersionToUint64("10.6")) { // KernelData = (UINT8*)(UINTN)(KernelSlide + KernelRelocBase + 0x00111000); // } else { KernelData = (UINT8*)(UINTN)(KernelSlide + KernelRelocBase + 0x00200000); // } // check that it is Mach-O header and detect architecture if(MACH_GET_MAGIC(KernelData) == MH_MAGIC || MACH_GET_MAGIC(KernelData) == MH_CIGAM) { DBG("Found 32 bit kernel at 0x%llx\n", (UINTN)KernelData); is64BitKernel = FALSE; } else if (MACH_GET_MAGIC(KernelData) == MH_MAGIC_64 || MACH_GET_MAGIC(KernelData) == MH_CIGAM_64) { DBG( "Found 64 bit kernel at 0x%llx\n", (UINTN)KernelData); // DBG_RT("text section is: %s\n", (const char*)&KernelData[0x28]); /* KernelOffset = 0; while (KernelOffset < KERNEL_MAX_SIZE) { if ((MACH_GET_MAGIC(KernelData+KernelOffset) == MH_MAGIC_64 ) || (MACH_GET_MAGIC(KernelData+KernelOffset) == MH_CIGAM_64)) { DBG("dump at offset 0x%x\n", KernelOffset); for (int j = 0; j<20; ++j) { DBG("%02x ", KernelData[KernelOffset+j]); } DBG("\n"); if ((((struct mach_header_64*)(KernelData+KernelOffset))->filetype) == MH_EXECUTE) { DBG("execute found\n"); break; } } KernelOffset += 4; } */ if ((((struct mach_header_64*)KernelData)->filetype) == MH_KERNEL_COLLECTION) { // BigSur KernelOffset = GetTextExec(); // DBG("BigSur: KernelOffset =0x%X\n", KernelOffset); } is64BitKernel = TRUE; } else { // not valid Mach-O header - exiting DBG( "Kernel not found at 0x%llx - skipping patches!\n", (UINTN)KernelData); KernelData = NULL; return; } DBG( " kernel offset at 0x%x\n", KernelOffset); // find __PRELINK_TEXT and __PRELINK_INFO if ((((struct mach_header_64*)KernelData)->filetype) == MH_KERNEL_COLLECTION) { Get_PreLink(); // BigSur } else { Get_PreLink(); } //find symbol tables struct symtab_command *symCmd = NULL; UINT32 symCmdOffset = Get_Symtab(&KernelData[KernelOffset]); if (symCmdOffset != 0) { symCmd = (struct symtab_command *)&KernelData[KernelOffset + symCmdOffset]; AddrVtable = symCmd->symoff; //this offset relative to KernelData+0 SizeVtable = symCmd->nsyms; NamesTable = symCmd->stroff; DBG("Kernel: AddrVtable=0x%x SizeVtable=0x%x NamesTable=0x%x\n", AddrVtable, SizeVtable, NamesTable); } /* for (UINTN i=0x00200000; i<0x30000000; i+=4) { UINT32 *KD = (UINT32 *)i; if ((KD[0] == MH_MAGIC_64) && (KD[0x0a] == 0x45545F5F)){ DBG_RT( "Found MAGIC at %llx, text=%s\n", i, (const char*)&KD[0x0a]); DBG( "Found MAGIC at %llx, text=%s\n", i, (const char*)&KD[0x0a]); KernelData = (UINT8*)KD; DBG( "Found new kernel at 0x%llx\n", (UINTN)KernelData); break; } } */ if (EFI_ERROR(getVTable())) { DBG("error getting vtable: \n"); } isKernelcache = (PrelinkTextSize > 0) && (PrelinkInfoSize > 0); DBG( "isKernelcache: %ls\n", isKernelcache ? L"Yes" : L"No"); } VOID LOADER_ENTRY::KernelAndKextsPatcherStart() { BOOLEAN KextPatchesNeeded, patchedOk; /* * it was intended for custom entries but not work if no custom entries used * so set common until better solution invented */ //KernelAndKextPatches = (KERNEL_AND_KEXT_PATCHES *)(((UINTN)&gSettings) + OFFSET_OF(SETTINGS_DATA, KernelAndKextPatches)); // CopyKernelAndKextPatches(&KernelAndKextPatches, &gSettings.KernelAndKextPatches); KernelAndKextPatches = gSettings.KernelAndKextPatches; PatcherInited = false; KernelAndKextPatcherInit(); KextPatchesNeeded = ( KernelAndKextPatches.KPAppleIntelCPUPM || KernelAndKextPatches.KPAppleRTC || KernelAndKextPatches.EightApple || KernelAndKextPatches.KPDELLSMBIOS || KernelAndKextPatches.KPATIConnectorsPatch.notEmpty() || KernelAndKextPatches.KextPatches.size() > 0 ); // DBG_RT("\nKernelToPatch: "); // DBG_RT("Kernels patches: %d\n", KernelAndKextPatches.KernelPatches.size()); if (gSettings.KernelPatchesAllowed && KernelAndKextPatches.KernelPatches.notEmpty()) { // DBG_RT("Enabled: \n"); DBG("Kernels patches: enabled \n"); // KernelAndKextPatcherInit(); // if (KernelData == NULL) goto NoKernelData; if (EFI_ERROR(getVTable())) { // DBG_RT("error getting vtable: \n"); goto NoKernelData; } patchedOk = KernelUserPatch(); // DBG_RT(patchedOk ? " OK\n" : " FAILED!\n"); // gBS->Stall(5000000); } else { // DBG_RT("Disabled\n"); } /* DBG_RT( "\nKernelCpu patch: "); if (KernelAndKextPatches.KPKernelCpu) { // // Kernel patches // DBG_RT( "Enabled: \n"); KernelAndKextPatcherInit(); if (KernelData == NULL) goto NoKernelData; if(is64BitKernel) { DBG_RT( "64 bit patch ...\n"); KernelPatcher_64(); } else { DBG_RT( "32 bit patch ...\n"); KernelPatcher_32(); } DBG_RT( " OK\n"); } else { DBG_RT( "Disabled\n"); } */ //other method for KernelCPU patch is FakeCPUID DBG_RT( "\nFakeCPUID patch: "); if (KernelAndKextPatches.FakeCPUID) { DBG_RT( "Enabled: 0x%06x\n", KernelAndKextPatches.FakeCPUID); // KernelAndKextPatcherInit(); // if (KernelData == NULL) goto NoKernelData; KernelCPUIDPatch(); } else { DBG_RT( "Disabled\n"); } // CPU power management patch for CPU with locked msr DBG_RT( "\nKernelPm patch: "); if (KernelAndKextPatches.KPKernelPm || KernelAndKextPatches.KPKernelXCPM) { DBG_RT( "Enabled: \n"); DBG( "KernelPm patch: Enabled\n"); // KernelAndKextPatcherInit(); // if (KernelData == NULL) goto NoKernelData; patchedOk = FALSE; if (is64BitKernel) { patchedOk = KernelPatchPm(); } DBG_RT( patchedOk ? " OK\n" : " FAILED!\n"); } else { DBG_RT( "Disabled\n"); } // Patch to not dump kext at panic (c)vit9696 DBG_RT( "\nPanicNoKextDump patch: "); if (KernelAndKextPatches.KPPanicNoKextDump) { DBG_RT( "Enabled: \n"); // KernelAndKextPatcherInit(); // if (KernelData == NULL) goto NoKernelData; patchedOk = KernelPanicNoKextDump(); DBG_RT( patchedOk ? " OK\n" : " FAILED!\n"); } else { DBG_RT( "Disabled\n"); } // Lapic Panic Kernel Patch DBG_RT( "\nKernelLapic patch: "); if (KernelAndKextPatches.KPKernelLapic) { DBG_RT( "Enabled: \n"); // KernelAndKextPatcherInit(); // if (KernelData == NULL) goto NoKernelData; if(is64BitKernel) { DBG_RT( "64-bit patch ...\n"); patchedOk = KernelLapicPatch_64(); } else { DBG_RT( "32-bit patch ...\n"); patchedOk = KernelLapicPatch_32(); } DBG_RT( patchedOk ? " OK\n" : " FAILED!\n"); } else { DBG_RT( "Disabled\n"); } if (KernelAndKextPatches.KPKernelXCPM) { // // syscl - EnableExtCpuXCPM: Enable unsupported CPU's PowerManagement // // EnableExtCpuXCPM = NULL; patchedOk = FALSE; // BOOLEAN apply_idle_patch = (gCPUStructure.Model >= CPU_MODEL_SKYLAKE_U) && gSettings.HWP; // KernelAndKextPatcherInit(); // if (KernelData == NULL) goto NoKernelData; // syscl - now enable extra Cpu's PowerManagement // only Intel support this feature till now // move below code outside the if condition if AMD supports // XCPM later on if (gCPUStructure.Vendor == CPU_VENDOR_INTEL) { switch (gCPUStructure.Model) { case CPU_MODEL_JAKETOWN: // SandyBridge-E LGA2011 patchedOk = SandyBridgeEPM(); gSNBEAICPUFixRequire = TRUE; // turn on SandyBridge-E AppleIntelCPUPowerManagement Fix break; case CPU_MODEL_IVY_BRIDGE: // IvyBridge patchedOk = KernelIvyBridgeXCPM(); break; case CPU_MODEL_IVY_BRIDGE_E5: // IvyBridge-E patchedOk = KernelIvyE5XCPM(); break; case CPU_MODEL_HASWELL_E: // Haswell-E patchedOk = HaswellEXCPM(); break; case CPU_MODEL_BROADWELL_E5: case CPU_MODEL_BROADWELL_DE: // Broadwell-E/EP patchedOk = BroadwellEPM(); gBDWEIOPCIFixRequire = TRUE; break; default: if (gCPUStructure.Model >= CPU_MODEL_HASWELL && (AsciiStrStr(gCPUStructure.BrandString, "Celeron") || AsciiStrStr(gCPUStructure.BrandString, "Pentium"))) { // Haswell+ low-end CPU patchedOk = HaswellLowEndXCPM(); } break; } } DBG_RT( "EnableExtCpuXCPM - %s!\n", patchedOk? "OK" : "FAILED"); } Stall(2000000); // // Kext patches // // we need to scan kexts if "InjectKexts true and CheckFakeSMC" if (/*OSFLAG_ISSET(Flags, OSFLAG_WITHKEXTS) || */ OSFLAG_ISSET(Flags, OSFLAG_CHECKFAKESMC)) { DBG_RT( "\nAllowing kext patching to check if FakeSMC is present\n"); gSettings.KextPatchesAllowed = TRUE; KextPatchesNeeded = TRUE; } DBG_RT( "\nKextPatches Needed: %c, Allowed: %c ... ", (KextPatchesNeeded ? L'Y' : L'n'), (gSettings.KextPatchesAllowed ? L'Y' : L'n') ); if (KextPatchesNeeded && gSettings.KextPatchesAllowed) { // DBG_RT( "\nKext patching INIT\n"); // KernelAndKextPatcherInit(); // if (KernelData == NULL) goto NoKernelData; DBG_RT( "\nKext patching STARTED\n"); KextPatcherStart(); //is FakeSMC found in cache then inject will be disabled DBG_RT( "\nKext patching ENDED\n"); } else { DBG_RT( "Disabled\n"); } Stall(1000000); // // Kext add // // if (KernelAndKextPatches.KPDebug) { // if (OSFLAG_ISSET(Entry->Flags, OSFLAG_CHECKFAKESMC) && // OSFLAG_ISUNSET(Entry->Flags, OSFLAG_WITHKEXTS)) { // disabled kext injection if FakeSMC is already present // Entry->Flags = OSFLAG_UNSET(Entry->Flags, OSFLAG_WITHKEXTS); //Slice - we are already here // // DBG_RT( "\nInjectKexts: disabled because FakeSMC is already present and InjectKexts option set to Detect\n"); // gBS->Stall(500000); // } // } if (OSFLAG_ISSET(Flags, OSFLAG_WITHKEXTS)) { UINT32 deviceTreeP; UINT32 *deviceTreeLength; EFI_STATUS Status; UINTN DataSize; // check if FSInject already injected kexts DataSize = 0; Status = gRT->GetVariable (L"FSInject.KextsInjected", &gEfiGlobalVariableGuid, NULL, &DataSize, NULL); if (Status == EFI_BUFFER_TOO_SMALL) { // var exists - just exit DBG_RT( "\nInjectKexts: skipping, FSInject already injected them\n"); Stall(500000); return; } // KernelAndKextPatcherInit(); // if (KernelData == NULL) goto NoKernelData; if (bootArgs1 != NULL) { deviceTreeP = bootArgs1->deviceTreeP; deviceTreeLength = &bootArgs1->deviceTreeLength; } else if (bootArgs2 != NULL) { deviceTreeP = bootArgs2->deviceTreeP; deviceTreeLength = &bootArgs2->deviceTreeLength; } else return; Status = InjectKexts(deviceTreeP, deviceTreeLength); DBG_RT("Inject kexts done at 0x%llx\n", (UINTN)deviceTreeP); if (!EFI_ERROR(Status)) KernelBooterExtensionsPatch(); } return; NoKernelData: Stall(5000000); }