From ebdc3fa056f2a5c9f6dacd54b4410106b9b01cab Mon Sep 17 00:00:00 2001 From: vit9696 Date: Sat, 27 Jun 2020 20:55:09 +0300 Subject: [PATCH] OcAppleKernelLib: Start building new Mach-O functions --- .../Acidanthera/Library/OcAppleKernelLib.h | 12 +- Include/Acidanthera/Library/OcMachoLib.h | 15 ++ .../Apple/IndustryStandard/AppleMachoImage.h | 80 +++--- Library/OcAppleKernelLib/KernelCollection.c | 231 ++++++++++++++++++ Library/OcAppleKernelLib/OcAppleKernelLib.inf | 1 + Library/OcAppleKernelLib/PrelinkedContext.c | 11 + Library/OcAppleKernelLib/PrelinkedInternal.h | 23 +- Library/OcMachoLib/Header.c | 120 +++++++++ Platform/OpenCore/OpenCoreKernel.c | 2 +- 9 files changed, 461 insertions(+), 34 deletions(-) create mode 100644 Library/OcAppleKernelLib/KernelCollection.c diff --git a/Include/Acidanthera/Library/OcAppleKernelLib.h b/Include/Acidanthera/Library/OcAppleKernelLib.h index 81b0b679..f4352a6b 100644 --- a/Include/Acidanthera/Library/OcAppleKernelLib.h +++ b/Include/Acidanthera/Library/OcAppleKernelLib.h @@ -46,6 +46,10 @@ #define PRELINK_INFO_INTEGER_ATTRIBUTES "size=\"64\"" +#define KC_REGION_SEGMENT_PREFIX "__REGION" +#define KC_TEXT_SEGMENT "__TEXT" +#define KC_MOSCOW_SEGMENT "__MOSCOW101" + // // Failsafe default for plist reserve allocation. // @@ -125,9 +129,15 @@ typedef struct { VOID *LinkBuffer; UINT32 LinkBufferSize; // - // Used for caching prelinked kexts. + // Used for caching all prelinked kexts. + // I.e. this contains kernel, injected kexts, and kexts used as dependencies. // LIST_ENTRY PrelinkedKexts; + // + // Used for caching prelinked kexts, which we inject. + // This is a sublist of PrelinkedKexts. + // + LIST_ENTRY InjectedKexts; } PRELINKED_CONTEXT; // diff --git a/Include/Acidanthera/Library/OcMachoLib.h b/Include/Acidanthera/Library/OcMachoLib.h index 2f236c1f..0b6c0a82 100644 --- a/Include/Acidanthera/Library/OcMachoLib.h +++ b/Include/Acidanthera/Library/OcMachoLib.h @@ -231,6 +231,21 @@ MachoGetSectionByAddress64 ( IN UINT64 Address ); +/** + Merge Mach-O segments into one with lowest protection. + + @param[in,out] Context Context of the Mach-O. + @param[in] Prefix Segment prefix to merge. + + @retval TRUE on success + +**/ +BOOLEAN +MachoMergeSegments64 ( + IN OUT OC_MACHO_CONTEXT *Context, + IN CONST CHAR8 *Prefix + ); + /** Returns whether Symbol describes a section. diff --git a/Include/Apple/IndustryStandard/AppleMachoImage.h b/Include/Apple/IndustryStandard/AppleMachoImage.h index ec645a2e..263c0408 100644 --- a/Include/Apple/IndustryStandard/AppleMachoImage.h +++ b/Include/Apple/IndustryStandard/AppleMachoImage.h @@ -1779,6 +1779,21 @@ typedef struct { UINT32 HeaderAddress; ///< files virtual address } MACH_FIXED_VM_FILE_COMMAND; +/// +/// LC_FILESET_ENTRY commands describe constituent Mach-O files that are part +/// of a fileset. In one implementation, entries are dylibs with individual +/// mach headers and repositionable text and data segments. Each entry is +/// further described by its own mach header. +/// +typedef struct { + MACH_LOAD_COMMAND_HDR_ + UINT64 VirtualAddress; ///< memory address of the entry + UINT64 FileOffset; ///< file offset of the entry + MACH_LOAD_COMMAND_STRING EntryId; ///< contained entry id + UINT32 Reserved; ///< reserved + CHAR8 Payload[]; ///< file information starting at entry id +} MACH_FILESET_ENTRY_COMMAND; + /// /// The entry_point_command is a replacement for thread_command. /// It is used for main executables to specify the location (file offset) @@ -1813,37 +1828,40 @@ typedef struct { } MACH_SOURCE_VERSION_COMMAND; typedef union { - CONST MACH_LOAD_COMMAND *Hdr; - CONST MACH_SEGMENT_COMMAND *Segment; - CONST MACH_SEGMENT_COMMAND_64 *Segment64; - CONST MACH_FIXED_VM_LIB_COMMAND *VmLib; - CONST MACH_DYLIB_COMMAND *Dylib; - CONST MACH_SUB_FRAMEWORK_COMMAND *SubFramework; - CONST MACH_SUB_CLIENT_COMMAND *SubClient; - CONST MACH_SUB_UMBRELLA_COMMAND *SubUmbrella; - CONST MACH_SUB_LIBRARY_COMMAND *SubLibrary; - CONST MACH_PREBOUND_DYLIB_COMMAND *PreboundDyLib; - CONST MACH_DYLINKER_COMMAND *Dylinker; - CONST MACH_THREAD_COMMAND *Thread; - CONST MACH_ROUTINES_COMMAND *Routines; - CONST MACH_ROUTINES_COMMAND_64 *Routines64; - CONST MACH_SYMTAB_COMMAND *Symtab; - CONST MACH_DYSYMTAB_COMMAND *Dysymtab; - CONST MACH_TWO_LEVEL_HINTS_COMMAND *TwoLevelHints; - CONST MACH_PREBIND_CHECKSUM_COMMAND *PrebindChecksum; - CONST MACH_UUID_COMMAND *Uuid; - CONST MACH_RUN_PATH_COMMAND *RunPath; - CONST MACH_LINKEDIT_DATA_COMMAND *LinkeditData; - CONST MACH_ENCRYPTION_INFO_COMMAND *EncryptionInfo; - CONST MACH_ENCRYPTION_INFO_COMMAND_64 *EncryptionInfo64; - CONST MACH_VERSION_MIN_COMMAND *VersionMin; - CONST MACH_BUILD_VERSION_COMMAND *BuildVersion; - CONST MACH_DYLD_INFO_COMMAND *DyldInfo; - CONST MACH_LINKER_OPTION_COMMAND *LinkerOption; - CONST MACH_SYMBOL_SEGMENT_COMMAND *SymbolSegment; - CONST MACH_IDENTIFICATION_COMMAND *Identification; - CONST MACH_FIXED_VM_FILE_COMMAND *FixedVmFile; - CONST VOID *Pointer; + MACH_LOAD_COMMAND *Hdr; + MACH_SEGMENT_COMMAND *Segment; + MACH_SEGMENT_COMMAND_64 *Segment64; + MACH_FIXED_VM_LIB_COMMAND *VmLib; + MACH_DYLIB_COMMAND *Dylib; + MACH_SUB_FRAMEWORK_COMMAND *SubFramework; + MACH_SUB_CLIENT_COMMAND *SubClient; + MACH_SUB_UMBRELLA_COMMAND *SubUmbrella; + MACH_SUB_LIBRARY_COMMAND *SubLibrary; + MACH_PREBOUND_DYLIB_COMMAND *PreboundDyLib; + MACH_DYLINKER_COMMAND *Dylinker; + MACH_THREAD_COMMAND *Thread; + MACH_ROUTINES_COMMAND *Routines; + MACH_ROUTINES_COMMAND_64 *Routines64; + MACH_SYMTAB_COMMAND *Symtab; + MACH_DYSYMTAB_COMMAND *Dysymtab; + MACH_TWO_LEVEL_HINTS_COMMAND *TwoLevelHints; + MACH_PREBIND_CHECKSUM_COMMAND *PrebindChecksum; + MACH_UUID_COMMAND *Uuid; + MACH_RUN_PATH_COMMAND *RunPath; + MACH_LINKEDIT_DATA_COMMAND *LinkeditData; + MACH_ENCRYPTION_INFO_COMMAND *EncryptionInfo; + MACH_ENCRYPTION_INFO_COMMAND_64 *EncryptionInfo64; + MACH_VERSION_MIN_COMMAND *VersionMin; + MACH_BUILD_VERSION_COMMAND *BuildVersion; + MACH_DYLD_INFO_COMMAND *DyldInfo; + MACH_LINKER_OPTION_COMMAND *LinkerOption; + MACH_SYMBOL_SEGMENT_COMMAND *SymbolSegment; + MACH_IDENTIFICATION_COMMAND *Identification; + MACH_FIXED_VM_FILE_COMMAND *FixedVmFile; + MACH_LINKEDIT_DATA_COMMAND *DyldExportsTrie; + MACH_LINKEDIT_DATA_COMMAND *DyldChainedFixups; + MACH_FILESET_ENTRY_COMMAND *FilesetEntry; + VOID *Pointer; UINTN Address; } MACH_LOAD_COMMAND_PTR; diff --git a/Library/OcAppleKernelLib/KernelCollection.c b/Library/OcAppleKernelLib/KernelCollection.c new file mode 100644 index 00000000..31e6c04b --- /dev/null +++ b/Library/OcAppleKernelLib/KernelCollection.c @@ -0,0 +1,231 @@ +/** @file + Kernel collection support. + + Copyright (c) 2020, vit9696. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "PrelinkedInternal.h" + +STATIC +UINTN +InternalKcGetKextFilesetSize ( + IN OUT PRELINKED_CONTEXT *Context + ) +{ + PRELINKED_KEXT *PrelinkedKext; + LIST_ENTRY *Kext; + UINTN Size; + UINTN CommandSize; + + Size = 0; + + Kext = GetFirstNode (&Context->InjectedKexts); + while (!IsNull (&Context->InjectedKexts, Kext)) { + PrelinkedKext = GET_INJECTED_KEXT_FROM_LINK (Kext); + + // + // Each command must be NUL-terminated and 8-byte aligned. + // + CommandSize = sizeof (MACH_FILESET_ENTRY_COMMAND) + AsciiStrSize (PrelinkedKext->Identifier); + Size += ALIGN_VALUE (CommandSize, 8); + + Kext = GetNextNode (&Context->InjectedKexts, Kext); + } + + return Size; +} + +STATIC +VOID +InternalKcWriteCommandHeaders ( + IN OUT PRELINKED_CONTEXT *Context, + IN OUT MACH_HEADER_64 *MachHeader + ) +{ + PRELINKED_KEXT *PrelinkedKext; + PRELINKED_KEXT *LowestKext; + LIST_ENTRY *Kext; + MACH_LOAD_COMMAND_PTR Command; + MACH_SEGMENT_COMMAND_64 *Segment; + UINTN StringSize; + + Command.Address = (UINTN) MachHeader->Commands + MachHeader->CommandsSize; + + Kext = GetFirstNode (&Context->InjectedKexts); + LowestKext = GET_INJECTED_KEXT_FROM_LINK (Kext); + + while (!IsNull (&Context->InjectedKexts, Kext)) { + PrelinkedKext = GET_INJECTED_KEXT_FROM_LINK (Kext); + + StringSize = AsciiStrSize (PrelinkedKext->Identifier); + + // + // Write 8-byte aligned fileset command. + // + Command.FilesetEntry->CommandType = MACH_LOAD_COMMAND_FILESET_ENTRY; + Command.FilesetEntry->CommandSize = ALIGN_VALUE (sizeof (MACH_FILESET_ENTRY_COMMAND) + StringSize, 8); + Command.FilesetEntry->VirtualAddress = PrelinkedKext->Context.VirtualBase; + Segment = MachoGetNextSegment64 (&PrelinkedKext->Context.MachContext, NULL); + ASSERT (Segment != NULL); + Command.FilesetEntry->FileOffset = Segment->FileOffset; + Command.FilesetEntry->EntryId.Offset = OFFSET_OF (MACH_FILESET_ENTRY_COMMAND, Payload); + Command.FilesetEntry->Reserved = 0; + CopyMem (Command.FilesetEntry->Payload, PrelinkedKext->Identifier, StringSize); + ZeroMem ( + &Command.FilesetEntry->Payload[StringSize], + Command.FilesetEntry->CommandSize - Command.FilesetEntry->EntryId.Offset - StringSize + ); + Command.Address += Command.FilesetEntry->CommandSize; + + // + // Refresh Mach-O header constants to include the new command. + // + MachHeader->NumCommands++; + MachHeader->CommandsSize += Command.FilesetEntry->CommandSize; + + Kext = GetNextNode (&Context->InjectedKexts, Kext); + } + + // + // Get last kext. + // + Kext = GetPreviousNode (&Context->InjectedKexts, &Context->InjectedKexts); + PrelinkedKext = GET_INJECTED_KEXT_FROM_LINK (Kext); + + // + // Write a segment covering all the kexts. + // + Command.Segment64->CommandType = MACH_LOAD_COMMAND_SEGMENT_64; + Command.Segment64->CommandSize = sizeof (MACH_SEGMENT_COMMAND_64); + CopyMem (Command.Segment64->SegmentName, KC_MOSCOW_SEGMENT, sizeof (KC_MOSCOW_SEGMENT)); + ZeroMem ( + &Command.Segment64->SegmentName[sizeof (KC_MOSCOW_SEGMENT)], + sizeof (Command.Segment64->SegmentName) - sizeof (KC_MOSCOW_SEGMENT) + ); + Segment = MachoGetNextSegment64 (&LowestKext->Context.MachContext, NULL); + Command.Segment64->VirtualAddress = Segment->VirtualAddress; + Command.Segment64->FileOffset = Segment->FileOffset; + Segment = MachoGetNextSegment64 (&PrelinkedKext->Context.MachContext, NULL); + Command.Segment64->Size = Segment->VirtualAddress - Command.Segment64->VirtualAddress + + MachoGetVmSize64 (&PrelinkedKext->Context.MachContext); + Command.Segment64->FileSize = Segment->FileOffset - Command.Segment64->FileOffset + + MachoGetFileSize (&PrelinkedKext->Context.MachContext); + Command.Segment64->MaximumProtection = MACH_SEGMENT_VM_PROT_READ + | MACH_SEGMENT_VM_PROT_WRITE | MACH_SEGMENT_VM_PROT_EXECUTE; + Command.Segment64->InitialProtection = MACH_SEGMENT_VM_PROT_READ + | MACH_SEGMENT_VM_PROT_WRITE | MACH_SEGMENT_VM_PROT_EXECUTE; + Command.Segment64->NumSections = 0; + Command.Segment64->Flags = 0; + + // + // Refresh Mach-O header constants to include the new segment command. + // + MachHeader->NumCommands++; + MachHeader->CommandsSize += sizeof (MACH_SEGMENT_COMMAND_64); +} + +EFI_STATUS +InternalKcRebuildMachHeader ( + IN OUT PRELINKED_CONTEXT *Context + ) +{ + MACH_HEADER_64 *MachHeader; + MACH_SEGMENT_COMMAND_64 *TextSegment; + UINTN CurrentSize; + UINTN FilesetSize; + UINTN RequiredSize; + + MachHeader = MachoGetMachHeader64 ( + &Context->PrelinkedMachContext + ); + + CurrentSize = MachHeader->CommandsSize + sizeof (*MachHeader); + FilesetSize = InternalKcGetKextFilesetSize (Context); + RequiredSize = FilesetSize + sizeof (MACH_LOAD_COMMAND_SEGMENT_64); + + TextSegment = MachoGetSegmentByName64 ( + &Context->PrelinkedMachContext, + KC_TEXT_SEGMENT + ); + + DEBUG (( + DEBUG_INFO, + "OCAK: KC TEXT is %u bytes with %u Mach-O headers need %u\n", + (UINT32) (TextSegment != NULL ? TextSegment->FileSize : 0), + (UINT32) CurrentSize, + (UINT32) RequiredSize + )); + + if (TextSegment == NULL + || TextSegment->FileOffset != 0 + || TextSegment->FileSize != TextSegment->Size + || TextSegment->FileSize < CurrentSize) { + return EFI_INVALID_PARAMETER; + } + + if (FilesetSize == 0) { + return EFI_SUCCESS; ///< Just in case. + } + + if (CurrentSize + RequiredSize > TextSegment->FileSize) { + // + // We do not have enough memory in the header, free some memory by merging + // kext segments (__REGION###) into a single RWX segment. + // - This is not bad for security as it is actually how it is done before + // 11.0, where OSKext::setVMAttributes sets the proper memory permissions + // on every kext soon after the kernel loads. + // - This is not bad for compatibility as the only thing referencing these + // segments is dyld fixups command, and it does not matter whether it + // references the base segment or points to the middle of it. + // The actual reason this was added might actually be because of the ARM + // transition, where you can restrict the memory permissions till the next + // hardware reset (like on iOS) and they now really try to require W^X: + // https://developer.apple.com/videos/play/wwdc2020/10686/ + // + if (!MachoMergeSegments64 (&Context->PrelinkedMachContext, KC_REGION_SEGMENT_PREFIX)) { + DEBUG ((DEBUG_INFO, "OCAK: Segment expansion failure\n")); + return EFI_UNSUPPORTED; + } + + CurrentSize = MachHeader->CommandsSize + sizeof (*MachHeader); + } + + // + // If we do not fit even after the expansion, we are really doomed. + // This should never happen. + // + if (CurrentSize + RequiredSize > TextSegment->FileSize) { + DEBUG ((DEBUG_INFO, "OCAK: Used header %u is still too large\n", (UINT32) CurrentSize)); + return EFI_UNSUPPORTED; + } + + // + // At this step we have memory for all the new commands. + // Just write the here. + // + InternalKcWriteCommandHeaders (Context, MachHeader); + + return EFI_SUCCESS; +} diff --git a/Library/OcAppleKernelLib/OcAppleKernelLib.inf b/Library/OcAppleKernelLib/OcAppleKernelLib.inf index 8f3e7db5..25972065 100644 --- a/Library/OcAppleKernelLib/OcAppleKernelLib.inf +++ b/Library/OcAppleKernelLib/OcAppleKernelLib.inf @@ -33,6 +33,7 @@ KextPatcher.c Link.c CommonPatches.c + KernelCollection.c PrelinkedContext.c PrelinkedInternal.h PrelinkedKext.c diff --git a/Library/OcAppleKernelLib/PrelinkedContext.c b/Library/OcAppleKernelLib/PrelinkedContext.c index d0838097..dcb09bdc 100644 --- a/Library/OcAppleKernelLib/PrelinkedContext.c +++ b/Library/OcAppleKernelLib/PrelinkedContext.c @@ -173,6 +173,7 @@ PrelinkedContextInit ( // Initialize kext list with kernel pseudo kext. // InitializeListHead (&Context->PrelinkedKexts); + InitializeListHead (&Context->InjectedKexts); if (InternalCachedPrelinkedKernel (Context) == NULL) { return EFI_INVALID_PARAMETER; } @@ -320,6 +321,11 @@ PrelinkedContextFree ( } ZeroMem (&Context->PrelinkedKexts, sizeof (Context->PrelinkedKexts)); + + // + // We do not need to iterate InjectedKexts here, as its memory was freed above. + // + ZeroMem (&Context->InjectedKexts, sizeof (Context->InjectedKexts)); } EFI_STATUS @@ -707,6 +713,11 @@ PrelinkedInjectKext ( // if (PrelinkedKext != NULL) { InsertTailList (&Context->PrelinkedKexts, &PrelinkedKext->Link); + // + // Additionally register this kext in the injected list, as this is required + // for KernelCollection support. + // + InsertTailList (&Context->InjectedKexts, &PrelinkedKext->InjectedLink); } return EFI_SUCCESS; diff --git a/Library/OcAppleKernelLib/PrelinkedInternal.h b/Library/OcAppleKernelLib/PrelinkedInternal.h index 2ba79b09..c91c588f 100644 --- a/Library/OcAppleKernelLib/PrelinkedInternal.h +++ b/Library/OcAppleKernelLib/PrelinkedInternal.h @@ -61,8 +61,15 @@ struct PRELINKED_KEXT_ { // eventually be part of a list and to save separate allocations per KEXT. // UINT32 Signature; + // + // Link for global list (PRELINKED_CONTEXT -> PrelinkedKexts). + // LIST_ENTRY Link; // + // Link for local list (PRELINKED_CONTEXT -> InjectedKexts). + // + LIST_ENTRY InjectedLink; + // // Kext CFBundleIdentifier. // CONST CHAR8 *Identifier; @@ -129,7 +136,7 @@ struct PRELINKED_KEXT_ { #define PRELINKED_KEXT_SIGNATURE SIGNATURE_32 ('P', 'K', 'X', 'T') /** - Gets the next element in a linked list of PRELINKED_KEXT. + Gets the next element in PrelinkedKexts list of PRELINKED_KEXT. @param[in] This The current ListEntry. **/ @@ -141,6 +148,20 @@ struct PRELINKED_KEXT_ { PRELINKED_KEXT_SIGNATURE \ )) +/** + Gets the next element in InjectedKexts list of PRELINKED_KEXT. + + @param[in] This The current ListEntry. +**/ +#define GET_INJECTED_KEXT_FROM_LINK(This) \ + (CR ( \ + (This), \ + PRELINKED_KEXT, \ + InjectedLink, \ + PRELINKED_KEXT_SIGNATURE \ + )) + + /** Creates new PRELINKED_KEXT from OC_MACHO_CONTEXT. **/ diff --git a/Library/OcMachoLib/Header.c b/Library/OcMachoLib/Header.c index 70af2203..e2ba94e8 100644 --- a/Library/OcMachoLib/Header.c +++ b/Library/OcMachoLib/Header.c @@ -1485,3 +1485,123 @@ MachoRuntimeGetEntryAddress ( return Address; } + +BOOLEAN +MachoMergeSegments64 ( + IN OUT OC_MACHO_CONTEXT *Context, + IN CONST CHAR8 *Prefix + ) +{ + UINT32 LcIndex; + MACH_LOAD_COMMAND *LoadCommand; + MACH_SEGMENT_COMMAND_64 *Segment; + MACH_SEGMENT_COMMAND_64 *FirstSegment; + UINT64 MaxAddress; + UINT64 MaxOffset; + MACH_VM_PROTECTION MaxInitProt; + MACH_VM_PROTECTION MaxMaxProt; + MACH_HEADER_64 *Header; + UINTN PrefixLength; + UINTN SkipCount; + UINTN RemainingArea; + + ASSERT (Context != NULL); + ASSERT (Context->FileSize != 0); + ASSERT (Prefix != NULL); + + Header = MachoGetMachHeader64 (Context); + PrefixLength = AsciiStrLen (Prefix); + FirstSegment = NULL; + + MaxAddress = 0; + MaxOffset = 0; + MaxInitProt = 0; + MaxMaxProt = 0; + SkipCount = 0; + + LoadCommand = &Header->Commands[0]; + + for (LcIndex = 0; LcIndex < Header->NumCommands; ++LcIndex) { + // + // Either skip or stop at unrelated commands. + // + if (LoadCommand->CommandType != MACH_LOAD_COMMAND_SEGMENT_64 + || AsciiStrnCmp (Segment->SegmentName, Prefix, PrefixLength) != 0) { + if (FirstSegment != NULL) { + break; + } + + LoadCommand = NEXT_MACH_LOAD_COMMAND (LoadCommand); + continue; + } + + // + // We have a segment starting with the prefix. + // + Segment = (MACH_SEGMENT_COMMAND_64 *) (VOID *) LoadCommand; + + // + // Do not support this for now as it will require changes in the file. + // + if (Segment->Size != Segment->FileSize) { + return FALSE; + } + + // + // Remember the first segment or assume it is a skip. + // + if (FirstSegment == NULL) { + FirstSegment = Segment; + } else { + ++SkipCount; + + // + // Expand the first segment. + // TODO: Do we need to check these for overflow for our own purposes? + // + FirstSegment->Size = Segment->VirtualAddress - FirstSegment->VirtualAddress + Segment->Size; + FirstSegment->FileSize = Segment->FileOffset - FirstSegment->FileOffset + Segment->FileSize; + + // + // Add new segment protection to the first segment. + // + FirstSegment->InitialProtection |= Segment->InitialProtection; + FirstSegment->MaximumProtection |= Segment->MaximumProtection; + } + + LoadCommand = NEXT_MACH_LOAD_COMMAND (LoadCommand); + } + + // + // The segment does not exist. + // + if (FirstSegment == NULL) { + return FALSE; + } + + // + // The segment is only one. + // + if (SkipCount == 0) { + return FALSE; + } + + // + // Move back remaining commands ontop of the skipped ones and zero this area. + // + RemainingArea = Header->CommandsSize - ((UINTN) LoadCommand - (UINTN) &Header->Commands[0]); + CopyMem ( + (UINT8 *) FirstSegment + FirstSegment->CommandSize, + LoadCommand, + RemainingArea + ); + ZeroMem (LoadCommand, RemainingArea); + + // + // Account for dropped commands in the header. + // + Header->NumCommands -= SkipCount; + Header->CommandsSize -= sizeof (MACH_SEGMENT_COMMAND_64) * SkipCount; + + return TRUE; +} diff --git a/Platform/OpenCore/OpenCoreKernel.c b/Platform/OpenCore/OpenCoreKernel.c index d8b89c49..d5552548 100644 --- a/Platform/OpenCore/OpenCoreKernel.c +++ b/Platform/OpenCore/OpenCoreKernel.c @@ -722,7 +722,7 @@ OcKernelFileOpen ( // On 10.9 mach_kernel is loaded for manual linking aferwards, so we cannot skip it. // if (OpenMode == EFI_FILE_MODE_READ - && StrStr (FileName, L"kernel") != NULL + && OcStriStr (FileName, L"kernel") != NULL && StrCmp (FileName, L"System\\Library\\Kernels\\kernel") != 0) { DEBUG ((DEBUG_INFO, "OC: Trying XNU hook on %s\n", FileName));