mirror of
https://github.com/acidanthera/OpenCorePkg.git
synced 2026-02-01 15:59:39 +00:00
Implement test kext reading from command line
Also remove legacy OcMachoPrelinkLib.
This commit is contained in:
parent
fc6fbed67c
commit
f9d5c1c4fd
1
.gitignore
vendored
1
.gitignore
vendored
@ -11,5 +11,6 @@ DICT
|
||||
fuzz-*.log
|
||||
crash-*
|
||||
oom-*
|
||||
slow-unit-*
|
||||
out.bin
|
||||
prelinkedkernel.unpack
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,431 +0,0 @@
|
||||
#ifndef OC_MACHO_PRELINK_INTERNAL_H_
|
||||
#define OC_MACHO_PRELINK_INTERNAL_H_
|
||||
|
||||
#include <IndustryStandard/AppleMachoImage.h>
|
||||
|
||||
#include <Library/OcMachoLib.h>
|
||||
|
||||
#define KXLD_WEAK_TEST_SYMBOL "_gOSKextUnresolved"
|
||||
|
||||
#define OS_METACLASS_VTABLE_NAME "__ZTV11OSMetaClass"
|
||||
|
||||
#define X86_64_RIP_RELATIVE_LIMIT 0x80000000ULL
|
||||
|
||||
#define SYM_MAX_NAME_LEN 256U
|
||||
|
||||
#define VTABLE_ENTRY_SIZE_64 8U
|
||||
#define VTABLE_HEADER_LEN_64 2U
|
||||
#define VTABLE_HEADER_SIZE_64 (VTABLE_HEADER_LEN_64 * VTABLE_ENTRY_SIZE_64)
|
||||
|
||||
#define OS_BUNDLE_LIBRARIES_STR "OSBundleLibraries"
|
||||
#define OS_BUNDLE_IDENTIFIER_STR "CFBundleIdentifier"
|
||||
#define OS_BUNDLE_VERSION_STR "CFBundleVersion"
|
||||
#define OS_BUNDLE_COMPATIBLE_VERSION_STR "OSBundleCompatibleVersion"
|
||||
|
||||
typedef struct {
|
||||
UINT32 StringIndex; ///< index into the string table
|
||||
UINT64 Value; ///< value of this symbol (or stab offset)
|
||||
} OC_SYMBOL_64;
|
||||
|
||||
#define OC_SYMBOL_TABLE_64_SIGNATURE SIGNATURE_32 ('O', 'S', '6', '4')
|
||||
|
||||
/**
|
||||
Gets the next element in a linked list of OC_SYMBOL_TABLE_64.
|
||||
|
||||
@param[in] This The current ListEntry.
|
||||
|
||||
**/
|
||||
#define GET_OC_SYMBOL_TABLE_64_FROM_LINK(This) \
|
||||
CR ( \
|
||||
(This), \
|
||||
OC_SYMBOL_TABLE_64, \
|
||||
Link, \
|
||||
OC_SYMBOL_TABLE_64_SIGNATURE \
|
||||
)
|
||||
|
||||
#define STR_LEN(String) (ARRAY_SIZE (String) - 1)
|
||||
#define STR_N_HELPER(String) (String), STR_LEN (String)
|
||||
|
||||
typedef struct {
|
||||
///
|
||||
/// These data are used to construct linked lists of dependency information
|
||||
/// for each KEXT. It is declared hear for every dependency will
|
||||
/// eventually be part of a list and to save separate allocations per KEXT.
|
||||
///
|
||||
UINT32 Signature;
|
||||
LIST_ENTRY Link;
|
||||
BOOLEAN IsIndirect;
|
||||
///
|
||||
/// The String Table associated with this symbol table.
|
||||
///
|
||||
CONST CHAR8 *StringTable;
|
||||
///
|
||||
/// The number of symbols in the entire symbols buffer.
|
||||
///
|
||||
UINT32 NumSymbols;
|
||||
///
|
||||
/// The number of C++ symbols at the end of the symbols buffer.
|
||||
///
|
||||
UINT32 NumCxxSymbols;
|
||||
OC_SYMBOL_64 Symbols[]; ///< The symbol buffer.
|
||||
} OC_SYMBOL_TABLE_64;
|
||||
|
||||
typedef struct {
|
||||
CONST CHAR8 *Name; ///< The symbol's name.
|
||||
UINT64 Address; ///< The symbol's address.
|
||||
} OC_VTABLE_ENTRY;
|
||||
|
||||
#define GET_NEXT_OC_VTABLE(This) \
|
||||
((OC_VTABLE *)(&(This)->Entries[(This)->NumEntries]))
|
||||
|
||||
typedef struct {
|
||||
CONST CHAR8 *Name; ///< The VTable's name.
|
||||
UINT32 NumEntries; ///< The number of VTable entries.
|
||||
OC_VTABLE_ENTRY Entries[]; ///< The VTable entries.
|
||||
} OC_VTABLE;
|
||||
|
||||
#define OC_VTABLE_ARRAY_SIGNATURE SIGNATURE_32 ('O', 'V', 'T', 'A')
|
||||
|
||||
/**
|
||||
Gets the next element in a linked list of OC_VTABLE_ARRAY.
|
||||
|
||||
@param[in] This The current ListEntry.
|
||||
|
||||
**/
|
||||
#define GET_OC_VTABLE_ARRAY_FROM_LINK(This) \
|
||||
CR ( \
|
||||
(This), \
|
||||
OC_VTABLE_ARRAY, \
|
||||
Link, \
|
||||
OC_VTABLE_ARRAY_SIGNATURE \
|
||||
)
|
||||
|
||||
#define GET_FIRST_OC_VTABLE(This) \
|
||||
((OC_VTABLE *)((This) + 1))
|
||||
|
||||
typedef struct {
|
||||
///
|
||||
/// These data are used to construct linked lists of dependency information
|
||||
/// for each KEXT. It is declared hear for every dependency will
|
||||
/// eventually be part of a list and to save separate allocations per KEXT.
|
||||
///
|
||||
UINT32 Signature;
|
||||
LIST_ENTRY Link;
|
||||
///
|
||||
/// The number of VTables in the array.
|
||||
///
|
||||
UINT32 NumVtables;
|
||||
//
|
||||
// NOTE: This is an array that cannot be declared as such as OC_VTABLE
|
||||
// contains a flexible array itself. As the size is dynamic, do not
|
||||
// try to use pointer arithmetics.
|
||||
//
|
||||
///
|
||||
/// VTable array.
|
||||
///
|
||||
OC_VTABLE Vtables;
|
||||
} OC_VTABLE_ARRAY;
|
||||
|
||||
typedef union {
|
||||
struct {
|
||||
UINT32 Major : 14;
|
||||
UINT32 Minor : 7;
|
||||
UINT32 Revision : 7;
|
||||
UINT32 Stage : 4;
|
||||
UINT32 StageLevel : 8;
|
||||
} Bits;
|
||||
UINT64 Value;
|
||||
} OC_KEXT_VERSION;
|
||||
|
||||
typedef enum {
|
||||
OcKextVersionStageDevelopment = 1,
|
||||
OcKextVersionStageAlpha = 3,
|
||||
OcKextVersionStageBeta = 5,
|
||||
OcKextVersionStageCandidate = 7,
|
||||
OcKextVersionStageRelease = 9
|
||||
} OC_KEXT_VERSION_STAGE;
|
||||
|
||||
typedef struct {
|
||||
OC_SYMBOL_TABLE_64 *SymbolTable;
|
||||
OC_VTABLE_ARRAY *Vtables;
|
||||
} OC_DEPENDENCY_DATA;
|
||||
|
||||
#define OC_DEPENDENCY_INFO_ENTRY_SIGNATURE \
|
||||
SIGNATURE_32 ('O', 'D', 'I', 'E')
|
||||
|
||||
#define OC_DEP_INFO_FROM_LINK(This) \
|
||||
(CR ( \
|
||||
(This), \
|
||||
OC_DEPENDENCY_INFO_ENTRY, \
|
||||
Link, \
|
||||
OC_DEPENDENCY_INFO_ENTRY_SIGNATURE \
|
||||
))
|
||||
|
||||
typedef struct OC_DEPENDENCY_INFO_ENTRY_ OC_DEPENDENCY_INFO_ENTRY;
|
||||
|
||||
typedef struct {
|
||||
MACH_HEADER_64 *MachHeader;
|
||||
UINT32 MachoSize;
|
||||
CONST CHAR8 *Name;
|
||||
OC_KEXT_VERSION Version;
|
||||
OC_KEXT_VERSION CompatibleVersion;
|
||||
UINTN NumDependencies;
|
||||
OC_DEPENDENCY_INFO_ENTRY *Dependencies[];
|
||||
} OC_DEPENDENCY_INFO;
|
||||
|
||||
struct OC_DEPENDENCY_INFO_ENTRY_ {
|
||||
UINT32 Signature;
|
||||
LIST_ENTRY Link;
|
||||
BOOLEAN Prelinked;
|
||||
OC_DEPENDENCY_DATA Data;
|
||||
OC_DEPENDENCY_INFO Info;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
struct {
|
||||
MACH_HEADER_64 *MachHeader;
|
||||
UINT32 MachoSize;
|
||||
CONST CHAR8 *Plist;
|
||||
} Input;
|
||||
|
||||
struct {
|
||||
BOOLEAN Linked;
|
||||
} Output;
|
||||
//
|
||||
// Private data.
|
||||
//
|
||||
struct {
|
||||
OC_DEPENDENCY_INFO_ENTRY *Info;
|
||||
OC_MACHO_CONTEXT MachoContext;
|
||||
MACH_SEGMENT_COMMAND_64 *LinkEdit;
|
||||
BOOLEAN IsDependedOn;
|
||||
} Private;
|
||||
} OC_KEXT_REQUEST;
|
||||
|
||||
typedef struct {
|
||||
CONST MACH_NLIST_64 *Smcp;
|
||||
CONST MACH_NLIST_64 *Vtable;
|
||||
CONST MACH_NLIST_64 *MetaVtable;
|
||||
} OC_VTABLE_PATCH_ENTRY;
|
||||
|
||||
typedef struct {
|
||||
UINTN NumEntries;
|
||||
OC_VTABLE_PATCH_ENTRY Entries[];
|
||||
} OC_VTABLE_PATCH_ARRAY;
|
||||
|
||||
typedef struct {
|
||||
UINT32 NumSymbols;
|
||||
CONST MACH_NLIST_64 *Symbols[];
|
||||
} OC_VTABLE_EXPORT_ARRAY;
|
||||
|
||||
//
|
||||
// Dependencies
|
||||
//
|
||||
|
||||
OC_DEPENDENCY_INFO_ENTRY *
|
||||
InternalKextCollectInformation (
|
||||
IN CONST CHAR8 *Plist,
|
||||
IN OUT OC_MACHO_CONTEXT *MachoContext, OPTIONAL
|
||||
IN UINT64 KextsVirtual, OPTIONAL
|
||||
IN UINTN KextsPhysical, OPTIONAL
|
||||
IN UINT64 RequestedVersion OPTIONAL
|
||||
);
|
||||
|
||||
VOID
|
||||
InternalFreeDependencyEntry (
|
||||
IN OC_DEPENDENCY_INFO_ENTRY *Entry
|
||||
);
|
||||
|
||||
BOOLEAN
|
||||
InternalResolveDependencies (
|
||||
IN LIST_ENTRY *Dependencies,
|
||||
IN UINTN NumRequests, OPTIONAL
|
||||
IN OUT OC_KEXT_REQUEST *Requests, OPTIONAL
|
||||
IN CONST CHAR8 *PrelinkedPlist,
|
||||
IN OC_DEPENDENCY_INFO_ENTRY *KextInfo,
|
||||
IN UINT64 KextsVirtual,
|
||||
IN UINTN KextsPhysical
|
||||
);
|
||||
|
||||
LIST_ENTRY *
|
||||
InternalRemoveDependency (
|
||||
IN CONST LIST_ENTRY *Dependencies,
|
||||
IN UINTN NumRequests,
|
||||
IN OUT OC_KEXT_REQUEST *Requests,
|
||||
IN OC_DEPENDENCY_INFO_ENTRY *DepInfo
|
||||
);
|
||||
|
||||
VOID
|
||||
InternalInvalidateKextRequest (
|
||||
IN CONST LIST_ENTRY *Dependencies,
|
||||
IN UINTN NumRequests,
|
||||
IN OUT OC_KEXT_REQUEST *Requests,
|
||||
IN OC_KEXT_REQUEST *Request
|
||||
);
|
||||
|
||||
BOOLEAN
|
||||
InternalConstructDependencyArrays (
|
||||
IN UINTN NumDependencies,
|
||||
IN OC_DEPENDENCY_INFO_ENTRY **Dependencies,
|
||||
OUT OC_DEPENDENCY_DATA *DependencyData
|
||||
);
|
||||
|
||||
VOID
|
||||
InternalDestructDependencyArrays (
|
||||
OUT CONST OC_DEPENDENCY_DATA *DependencyData
|
||||
);
|
||||
|
||||
UINT64
|
||||
InternalGetNewPrelinkedKextLoadAddress (
|
||||
IN OUT OC_MACHO_CONTEXT *KernelContext,
|
||||
IN CONST MACH_SEGMENT_COMMAND_64 *PrelinkedKextsSegment,
|
||||
IN CONST CHAR8 *PrelinkedPlist
|
||||
);
|
||||
|
||||
/**
|
||||
Fills SymbolTable with the symbols provided in Symbols. For performance
|
||||
reasons, the C++ symbols are continuously added to the top of the buffer.
|
||||
Their order is not preserved. SymbolTable->SymbolTable is expected to be
|
||||
a valid buffer that can store at least NumSymbols symbols.
|
||||
|
||||
@param[in] MachoContext Context of the Mach-O.
|
||||
@param[in] NumSymbols The number of symbols to copy.
|
||||
@param[in] Symbols The source symbol array.
|
||||
@param[in,out] SymbolTable The desination Symbol List. Must be able to
|
||||
hold at least NumSymbols symbols.
|
||||
|
||||
**/
|
||||
VOID
|
||||
InternalFillSymbolTable64 (
|
||||
IN OUT OC_MACHO_CONTEXT *MachoContext,
|
||||
IN UINT32 NumSymbols,
|
||||
IN CONST MACH_NLIST_64 *Symbols,
|
||||
IN OUT OC_SYMBOL_TABLE_64 *SymbolTable
|
||||
);
|
||||
|
||||
//
|
||||
// PLIST
|
||||
//
|
||||
|
||||
CONST CHAR8 *
|
||||
InternalPlistStrStrSameLevelUp (
|
||||
IN CONST CHAR8 *AnchorString,
|
||||
IN CONST CHAR8 *FindString,
|
||||
IN UINTN FindStringLen
|
||||
);
|
||||
|
||||
CONST CHAR8 *
|
||||
InternalPlistStrStrSameLevelDown (
|
||||
IN CONST CHAR8 *AnchorString,
|
||||
IN CONST CHAR8 *FindString,
|
||||
IN UINTN FindStringLen
|
||||
);
|
||||
|
||||
CONST CHAR8 *
|
||||
InternalPlistStrStrSameLevel (
|
||||
IN CONST CHAR8 *AnchorString,
|
||||
IN CONST CHAR8 *FindString,
|
||||
IN UINTN FindStringLen,
|
||||
IN UINTN DownwardsOffset
|
||||
);
|
||||
|
||||
UINT64
|
||||
InternalPlistGetIntValue (
|
||||
IN CONST CHAR8 **Tag
|
||||
);
|
||||
|
||||
//
|
||||
// VTables
|
||||
//
|
||||
|
||||
UINT32
|
||||
InternalGetVtableSize64 (
|
||||
IN CONST UINT64 *VtableData
|
||||
);
|
||||
|
||||
BOOLEAN
|
||||
InternalGetVtableSizeWithRelocs64 (
|
||||
IN OUT OC_MACHO_CONTEXT *MachoContext,
|
||||
IN CONST UINT64 *VtableData,
|
||||
OUT UINT32 *VtableSize
|
||||
);
|
||||
|
||||
BOOLEAN
|
||||
InternalPrepareVtableCreationNonPrelinked64 (
|
||||
IN OUT OC_MACHO_CONTEXT *MachoContext,
|
||||
IN UINT32 NumSymbols,
|
||||
IN CONST MACH_NLIST_64 *SymbolTable,
|
||||
OUT OC_VTABLE_PATCH_ARRAY *PatchData
|
||||
);
|
||||
|
||||
BOOLEAN
|
||||
InternalCreateVtablesNonPrelinked64 (
|
||||
IN OUT OC_MACHO_CONTEXT *MachoContext,
|
||||
IN CONST OC_DEPENDENCY_DATA *DependencyData,
|
||||
IN OC_VTABLE_PATCH_ARRAY *PatchData,
|
||||
OUT OC_VTABLE_ARRAY *VtableArray
|
||||
);
|
||||
|
||||
BOOLEAN
|
||||
InternalPrepareCreateVtablesPrelinked64 (
|
||||
IN OC_MACHO_CONTEXT *MachoContext,
|
||||
OUT OC_VTABLE_EXPORT_ARRAY *VtableExport,
|
||||
IN UINT32 VtableExportSize
|
||||
);
|
||||
|
||||
BOOLEAN
|
||||
InternalCreateVtablesPrelinked64 (
|
||||
IN OC_MACHO_CONTEXT *MachoContext,
|
||||
IN CONST OC_SYMBOL_TABLE_64 *DefinedSymbols,
|
||||
IN OC_VTABLE_EXPORT_ARRAY *VtableExport,
|
||||
OUT OC_VTABLE *VtableBuffer
|
||||
);
|
||||
|
||||
//
|
||||
// Prelink
|
||||
//
|
||||
|
||||
// TODO: Move?
|
||||
CONST OC_SYMBOL_64 *
|
||||
InternalOcGetSymbolByName (
|
||||
IN CONST OC_SYMBOL_TABLE_64 *DefinedSymbols,
|
||||
IN CONST CHAR8 *Name,
|
||||
IN BOOLEAN CheckIndirect
|
||||
);
|
||||
|
||||
VOID
|
||||
InternalSolveSymbolValue64 (
|
||||
IN UINT64 Value,
|
||||
OUT MACH_NLIST_64 *Symbol
|
||||
);
|
||||
|
||||
/**
|
||||
Prelinks the specified KEXT against the specified LinkAddress and the data
|
||||
of its dependencies.
|
||||
|
||||
@param[in,out] MachoContext Mach-O context of the KEXT to prelink.
|
||||
@param[in] LinkEditSegment __LINKEDIT segment of the KEXT to prelink.
|
||||
@param[in] LinkAddress The address this KEXT shall be linked
|
||||
against.
|
||||
@param[in] DependencyData List of data of all dependencies.
|
||||
@param[in] ExposeSymbols Whether the symbol table shall be exposed.
|
||||
@param[out] OutputData Buffer to output data into.
|
||||
@param[out] ScratchMemory Scratch memory buffer that is at least as big
|
||||
as the KEXT's __LINKEDIT segment.
|
||||
|
||||
@retval Returned is whether the prelinking process has been successful.
|
||||
The state of the KEXT is undefined in case this routine fails.
|
||||
|
||||
**/
|
||||
BOOLEAN
|
||||
InternalPrelinkKext64 (
|
||||
IN OUT OC_MACHO_CONTEXT *MachoContext,
|
||||
IN MACH_SEGMENT_COMMAND_64 *LinkEditSegment,
|
||||
IN UINT64 LinkAddress,
|
||||
IN OC_DEPENDENCY_DATA *DependencyData,
|
||||
IN BOOLEAN ExposeSymbols,
|
||||
IN OUT OC_DEPENDENCY_DATA *OutputData,
|
||||
OUT VOID *ScratchMemory
|
||||
);
|
||||
|
||||
#endif // OC_MACHO_PRELINK_INTERNAL_H_
|
||||
@ -1,476 +0,0 @@
|
||||
/** @file
|
||||
Library handling KEXT prelinking.
|
||||
Currently limited to Intel 64 architectures.
|
||||
|
||||
Copyright (c) 2018, Download-Fritz. All rights reserved.<BR>
|
||||
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 <Base.h>
|
||||
|
||||
#include <IndustryStandard/AppleMachoImage.h>
|
||||
|
||||
#include <Library/BaseLib.h>
|
||||
#include <Library/DebugLib.h>
|
||||
#include <Library/MemoryAllocationLib.h>
|
||||
#include <Library/OcGuardLib.h>
|
||||
#include <Library/OcMachoLib.h>
|
||||
|
||||
#include "OcMachoPrelinkInternal.h"
|
||||
|
||||
STATIC
|
||||
BOOLEAN
|
||||
InternalPrelinkKextsWorker (
|
||||
IN OC_MACHO_CONTEXT *KernelContext,
|
||||
IN UINTN NumRequests,
|
||||
IN OUT OC_KEXT_REQUEST *Requests,
|
||||
IN LIST_ENTRY *Dependencies,
|
||||
IN CONST MACH_SEGMENT_COMMAND_64 *PrelinkTextSegment,
|
||||
IN CONST CHAR8 *PrelinkedPlist
|
||||
)
|
||||
{
|
||||
UINTN Index;
|
||||
OC_KEXT_REQUEST *Request;
|
||||
LIST_ENTRY *DependencyEntry;
|
||||
OC_DEPENDENCY_INFO_ENTRY *DependencyInfo;
|
||||
OC_DEPENDENCY_INFO *Info;
|
||||
OC_DEPENDENCY_DATA DependencyData;
|
||||
UINT64 LoadAddress;
|
||||
BOOLEAN Result;
|
||||
BOOLEAN OneLinked;
|
||||
BOOLEAN OneUnlinked;
|
||||
MACH_SEGMENT_COMMAND_64 *LinkEdit;
|
||||
UINTN ScratchSize;
|
||||
VOID *ScratchMemory;
|
||||
OC_DEPENDENCY_DATA *CurrentData;
|
||||
OC_MACHO_CONTEXT MachoContext;
|
||||
CONST MACH_HEADER_64 *MachHeader;
|
||||
CONST MACH_NLIST_64 *SymbolTable;
|
||||
UINT32 NumSymbols;
|
||||
OC_SYMBOL_TABLE_64 *OcSymbolTable;
|
||||
OC_VTABLE_ARRAY *Vtables;
|
||||
OC_VTABLE_EXPORT_ARRAY *VtableExport;
|
||||
|
||||
UINT32 VtableOffset;
|
||||
CONST UINT64 *VtableData;
|
||||
UINTN VtablesSize;
|
||||
|
||||
ASSERT (KernelContext != NULL);
|
||||
ASSERT (NumRequests > 0);
|
||||
ASSERT (Requests != NULL);
|
||||
ASSERT (Dependencies != NULL);
|
||||
ASSERT (PrelinkTextSegment != NULL);
|
||||
ASSERT (PrelinkedPlist != NULL);
|
||||
|
||||
ScratchSize = 0;
|
||||
|
||||
for (Index = 0; Index < NumRequests; ++Index) {
|
||||
Request = &Requests[Index];
|
||||
if (Request->Private.Info == NULL) {
|
||||
continue;
|
||||
}
|
||||
//
|
||||
// Retrieve the __LINKEDIT segment.
|
||||
//
|
||||
Result = MachoGetSegmentByName64 (
|
||||
&Request->Private.MachoContext,
|
||||
"__LINKEDIT",
|
||||
&LinkEdit
|
||||
);
|
||||
if (!Result || (LinkEdit == NULL)) {
|
||||
InternalInvalidateKextRequest (
|
||||
Dependencies,
|
||||
NumRequests,
|
||||
Requests,
|
||||
Request
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
Request->Private.LinkEdit = LinkEdit;
|
||||
|
||||
if (ScratchSize < LinkEdit->FileSize) {
|
||||
ScratchSize = LinkEdit->FileSize;
|
||||
}
|
||||
}
|
||||
|
||||
if (ScratchSize == 0) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ScratchMemory = AllocatePool (ScratchSize);
|
||||
if (ScratchMemory == NULL) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
VtableExport = (OC_VTABLE_EXPORT_ARRAY *)ScratchMemory;
|
||||
|
||||
for (
|
||||
DependencyEntry = GetFirstNode (Dependencies);
|
||||
!IsNull (DependencyEntry, Dependencies);
|
||||
DependencyEntry = GetNextNode (Dependencies, DependencyEntry),
|
||||
InternalDestructDependencyArrays (&DependencyData)
|
||||
) {
|
||||
DependencyInfo = OC_DEP_INFO_FROM_LINK (DependencyEntry);
|
||||
CurrentData = &DependencyInfo->Data;
|
||||
//
|
||||
// Try to construct the dependency tree first.
|
||||
//
|
||||
Info = &DependencyInfo->Info;
|
||||
Result = InternalConstructDependencyArrays (
|
||||
Info->NumDependencies,
|
||||
Info->Dependencies,
|
||||
&DependencyData
|
||||
);
|
||||
if (!Result) {
|
||||
//
|
||||
// Prelinked dependencies can only depend on other already prelinked
|
||||
// KEXTs.
|
||||
//
|
||||
DependencyEntry = InternalRemoveDependency (
|
||||
Dependencies,
|
||||
NumRequests,
|
||||
Requests,
|
||||
DependencyInfo
|
||||
);
|
||||
continue;
|
||||
}
|
||||
//
|
||||
// Create a Mach-O Context for this KEXT.
|
||||
//
|
||||
Result = MachoInitializeContext (
|
||||
&MachoContext,
|
||||
Info->MachHeader,
|
||||
Info->MachoSize
|
||||
);
|
||||
if (!Result) {
|
||||
DependencyEntry = InternalRemoveDependency (
|
||||
Dependencies,
|
||||
NumRequests,
|
||||
Requests,
|
||||
DependencyInfo
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
NumSymbols = MachoGetSymbolTable (
|
||||
&MachoContext,
|
||||
&SymbolTable,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
);
|
||||
if (NumSymbols == 0) {
|
||||
DependencyEntry = InternalRemoveDependency (
|
||||
Dependencies,
|
||||
NumRequests,
|
||||
Requests,
|
||||
DependencyInfo
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
OcSymbolTable = AllocatePool (
|
||||
sizeof (*OcSymbolTable)
|
||||
+ (NumSymbols * sizeof (*OcSymbolTable->Symbols))
|
||||
);
|
||||
if (OcSymbolTable == NULL) {
|
||||
FreePool (ScratchMemory);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
InternalFillSymbolTable64 (
|
||||
&MachoContext,
|
||||
NumSymbols,
|
||||
SymbolTable,
|
||||
OcSymbolTable
|
||||
);
|
||||
|
||||
Result = InternalPrepareCreateVtablesPrelinked64 (
|
||||
&MachoContext,
|
||||
VtableExport,
|
||||
ScratchSize
|
||||
);
|
||||
if (!Result) {
|
||||
DependencyEntry = InternalRemoveDependency (
|
||||
Dependencies,
|
||||
NumRequests,
|
||||
Requests,
|
||||
DependencyInfo
|
||||
);
|
||||
FreePool (OcSymbolTable);
|
||||
continue;
|
||||
}
|
||||
|
||||
MachHeader = MachoGetMachHeader64 (&MachoContext);
|
||||
ASSERT (MachHeader != NULL);
|
||||
|
||||
Result = TRUE;
|
||||
VtablesSize = 0;
|
||||
|
||||
for (Index = 0; Index < VtableExport->NumSymbols; ++Index) {
|
||||
Result = MachoSymbolGetFileOffset64 (
|
||||
&MachoContext,
|
||||
VtableExport->Symbols[Index],
|
||||
&VtableOffset
|
||||
);
|
||||
if (!Result) {
|
||||
break;
|
||||
}
|
||||
|
||||
VtableData = (UINT64 *)((UINTN)MachHeader + VtableOffset);
|
||||
if (!OC_ALIGNED (VtableData)) {
|
||||
Result = FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
VtablesSize += InternalGetVtableSize64 (VtableData);
|
||||
}
|
||||
|
||||
if (!Result) {
|
||||
DependencyEntry = InternalRemoveDependency (
|
||||
Dependencies,
|
||||
NumRequests,
|
||||
Requests,
|
||||
DependencyInfo
|
||||
);
|
||||
FreePool (OcSymbolTable);
|
||||
continue;
|
||||
}
|
||||
|
||||
Vtables = AllocatePool (sizeof (*Vtables) + VtablesSize);
|
||||
if (Vtables == NULL) {
|
||||
FreePool (OcSymbolTable);
|
||||
FreePool (ScratchMemory);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Result = InternalCreateVtablesPrelinked64 (
|
||||
&MachoContext,
|
||||
DependencyData.SymbolTable,
|
||||
VtableExport,
|
||||
GET_FIRST_OC_VTABLE (Vtables)
|
||||
);
|
||||
if (!Result) {
|
||||
DependencyEntry = InternalRemoveDependency (
|
||||
Dependencies,
|
||||
NumRequests,
|
||||
Requests,
|
||||
DependencyInfo
|
||||
);
|
||||
FreePool (Vtables);
|
||||
FreePool (OcSymbolTable);
|
||||
continue;
|
||||
}
|
||||
|
||||
CurrentData->SymbolTable = OcSymbolTable;
|
||||
CurrentData->Vtables = Vtables;
|
||||
}
|
||||
|
||||
do {
|
||||
OneLinked = FALSE;
|
||||
OneUnlinked = FALSE;
|
||||
|
||||
for (Index = 0; Index < NumRequests; ++Index) {
|
||||
Request = &Requests[Index];
|
||||
DependencyInfo = Request->Private.Info;
|
||||
if ((DependencyInfo == NULL) || DependencyInfo->Prelinked) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Info = &DependencyInfo->Info;
|
||||
Result = InternalConstructDependencyArrays (
|
||||
Info->NumDependencies,
|
||||
Info->Dependencies,
|
||||
&DependencyData
|
||||
);
|
||||
if (!Result) {
|
||||
//
|
||||
// The KEXT depends on another KEXT staged for prelinking which has not
|
||||
// been processed yet. Postpone to another iteration.
|
||||
//
|
||||
OneUnlinked = TRUE;
|
||||
continue;
|
||||
}
|
||||
//
|
||||
// Retrieve a loading address for the KEXT.
|
||||
//
|
||||
LoadAddress = InternalGetNewPrelinkedKextLoadAddress (
|
||||
KernelContext,
|
||||
PrelinkTextSegment,
|
||||
PrelinkedPlist
|
||||
);
|
||||
if (LoadAddress == 0) {
|
||||
FreePool (ScratchMemory);
|
||||
return FALSE;
|
||||
}
|
||||
//
|
||||
// Prelink the KEXT.
|
||||
//
|
||||
Result = InternalPrelinkKext64 (
|
||||
&Request->Private.MachoContext,
|
||||
Request->Private.LinkEdit,
|
||||
LoadAddress,
|
||||
&DependencyData,
|
||||
Request->Private.IsDependedOn,
|
||||
&DependencyInfo->Data,
|
||||
ScratchMemory
|
||||
);
|
||||
if (Result) {
|
||||
DependencyInfo->Prelinked = TRUE;
|
||||
Request->Output.Linked = TRUE;
|
||||
OneLinked = TRUE;
|
||||
} else {
|
||||
InternalInvalidateKextRequest (
|
||||
Dependencies,
|
||||
NumRequests,
|
||||
Requests,
|
||||
Request
|
||||
);
|
||||
}
|
||||
}
|
||||
//
|
||||
// Continue while the loop makes progress and there are still KEXTs to
|
||||
// link.
|
||||
//
|
||||
} while (OneLinked && OneUnlinked);
|
||||
|
||||
FreePool (ScratchMemory);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
OcPrelinkKexts64 (
|
||||
IN OC_MACHO_CONTEXT *KernelContext,
|
||||
IN UINTN NumRequests,
|
||||
IN OUT OC_KEXT_REQUEST *Requests
|
||||
)
|
||||
{
|
||||
CONST MACH_HEADER_64 *KernelHeader;
|
||||
UINTN Index;
|
||||
OC_KEXT_REQUEST *Request;
|
||||
OC_DEPENDENCY_INFO_ENTRY *DependencyInfo;
|
||||
BOOLEAN Result;
|
||||
MACH_SEGMENT_COMMAND_64 *PrelinkTextSegment;
|
||||
CONST CHAR8 *PrelinkedPlist;
|
||||
LIST_ENTRY Dependencies;
|
||||
LIST_ENTRY *DependencyEntry;
|
||||
UINT64 KextAddress;
|
||||
|
||||
ASSERT (KernelContext != NULL);
|
||||
ASSERT (NumRequests > 0);
|
||||
ASSERT (Requests != NULL);
|
||||
|
||||
KernelHeader = MachoGetMachHeader64 (KernelContext);
|
||||
ASSERT (KernelHeader != NULL);
|
||||
//
|
||||
// Collect the KEXT information for all KEXTs to be prelinked. Do not solve
|
||||
// dependencies yet so we can verify successful dependency against other
|
||||
// KEXTs to be prelinked in one go.
|
||||
//
|
||||
for (Index = 0; Index < NumRequests; ++Index) {
|
||||
Request = &Requests[Index];
|
||||
//
|
||||
// Create a Mach-O Context for this KEXT.
|
||||
//
|
||||
Result = MachoInitializeContext (
|
||||
&Request->Private.MachoContext,
|
||||
Request->Input.MachHeader,
|
||||
Request->Input.MachoSize
|
||||
);
|
||||
if (Result) {
|
||||
Request->Output.Linked = FALSE;
|
||||
Request->Private.IsDependedOn = FALSE;
|
||||
Request->Private.Info = InternalKextCollectInformation (
|
||||
Request->Input.Plist,
|
||||
&Request->Private.MachoContext,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
);
|
||||
} else {
|
||||
Request->Private.Info = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
PrelinkedPlist = (CHAR8 *)((UINTN)KernelHeader + PrelinkInfoSection->Offset);
|
||||
//
|
||||
// Resolve dependencies.
|
||||
//
|
||||
InitializeListHead (&Dependencies);
|
||||
|
||||
for (Index = 0; Index < NumRequests; ++Index) {
|
||||
Request = &Requests[Index];
|
||||
if (Request->Private.Info != NULL) {
|
||||
Result = FALSE;
|
||||
|
||||
KextAddress = (UINTN)Request->Input.MachHeader;
|
||||
KextAddress += PrelinkTextSegment->FileOffset;
|
||||
if (KextAddress == (UINTN)KextAddress) {
|
||||
Result = InternalResolveDependencies (
|
||||
&Dependencies,
|
||||
NumRequests,
|
||||
Requests,
|
||||
PrelinkedPlist,
|
||||
Request->Private.Info,
|
||||
PrelinkTextSegment->VirtualAddress,
|
||||
(UINTN)KextAddress
|
||||
);
|
||||
}
|
||||
|
||||
if (!Result) {
|
||||
//
|
||||
// Only pass the KEXT Requests that already had their dependencies
|
||||
// resolved.
|
||||
//
|
||||
InternalRemoveDependency (
|
||||
&Dependencies,
|
||||
Index,
|
||||
Requests,
|
||||
Request->Private.Info
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
//
|
||||
// Link the KEXTs.
|
||||
//
|
||||
Result = InternalPrelinkKextsWorker (
|
||||
KernelContext,
|
||||
NumRequests,
|
||||
Requests,
|
||||
&Dependencies,
|
||||
PrelinkTextSegment,
|
||||
PrelinkedPlist
|
||||
);
|
||||
//
|
||||
// Free all resources.
|
||||
//
|
||||
for (Index = 0; Index < NumRequests; ++Index) {
|
||||
Request = &Requests[Index];
|
||||
if (Request->Private.Info != NULL) {
|
||||
InternalFreeDependencyEntry (Request->Private.Info);
|
||||
}
|
||||
}
|
||||
|
||||
DependencyEntry = GetFirstNode (&Dependencies);
|
||||
|
||||
while (!IsNull (DependencyEntry, &Dependencies)) {
|
||||
DependencyInfo = OC_DEP_INFO_FROM_LINK (DependencyEntry);
|
||||
DependencyEntry = GetNextNode (&Dependencies, DependencyEntry);
|
||||
InternalFreeDependencyEntry (DependencyInfo);
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
@ -1,181 +0,0 @@
|
||||
/** @file
|
||||
PLIST helper functions.
|
||||
|
||||
Copyright (c) 2018, Download-Fritz. All rights reserved.<BR>
|
||||
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 <Base.h>
|
||||
|
||||
#include <Library/BaseLib.h>
|
||||
#include <Library/DebugLib.h>
|
||||
#include <Library/OcStringLib.h>
|
||||
|
||||
#include "OcMachoPrelinkInternal.h"
|
||||
|
||||
CONST CHAR8 *
|
||||
InternalPlistStrStrSameLevelUp (
|
||||
IN CONST CHAR8 *AnchorString,
|
||||
IN CONST CHAR8 *FindString,
|
||||
IN UINTN FindStringLen
|
||||
)
|
||||
{
|
||||
CONST CHAR8 *Walker;
|
||||
UINTN DictLevel;
|
||||
UINTN ShortestMatch;
|
||||
|
||||
ASSERT (AnchorString != NULL);
|
||||
ASSERT (FindString != NULL);
|
||||
ASSERT (AsciiStrLen (FindString) == FindStringLen);
|
||||
|
||||
ShortestMatch = MIN (FindStringLen, L_STR_LEN ("<dict>"));
|
||||
|
||||
for (
|
||||
Walker = (AnchorString - ShortestMatch);
|
||||
AsciiStrnCmp (Walker, FindString, FindStringLen) != 0;
|
||||
--Walker
|
||||
) {
|
||||
for (DictLevel = 1; TRUE; --Walker) {
|
||||
if (AsciiStrnCmp (Walker, STR_N_HELPER ("</dict>")) == 0) {
|
||||
++DictLevel;
|
||||
Walker -= (ShortestMatch - 1);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (AsciiStrnCmp (Walker, STR_N_HELPER ("<dict>")) == 0) {
|
||||
--DictLevel;
|
||||
if (DictLevel == 0) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (DictLevel == 1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Walker;
|
||||
}
|
||||
|
||||
CONST CHAR8 *
|
||||
InternalPlistStrStrSameLevelDown (
|
||||
IN CONST CHAR8 *AnchorString,
|
||||
IN CONST CHAR8 *FindString,
|
||||
IN UINTN FindStringLen
|
||||
)
|
||||
{
|
||||
CONST CHAR8 *Walker;
|
||||
UINTN DictLevel;
|
||||
|
||||
ASSERT (AnchorString != NULL);
|
||||
ASSERT (FindString != NULL);
|
||||
ASSERT (AsciiStrLen (FindString) == FindStringLen);
|
||||
|
||||
for (
|
||||
Walker = AnchorString;
|
||||
AsciiStrnCmp (Walker, FindString, FindStringLen) != 0;
|
||||
++Walker
|
||||
) {
|
||||
for (DictLevel = 1; TRUE; ++Walker) {
|
||||
if (AsciiStrnCmp (Walker, STR_N_HELPER ("<dict>")) == 0) {
|
||||
++DictLevel;
|
||||
Walker += (L_STR_LEN ("<dict>") - 1);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (AsciiStrnCmp (Walker, STR_N_HELPER ("</dict>")) == 0) {
|
||||
--DictLevel;
|
||||
if (DictLevel == 0) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (DictLevel == 1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Walker;
|
||||
}
|
||||
|
||||
CONST CHAR8 *
|
||||
InternalPlistStrStrSameLevel (
|
||||
IN CONST CHAR8 *AnchorString,
|
||||
IN CONST CHAR8 *FindString,
|
||||
IN UINTN FindStringLen,
|
||||
IN UINTN DownwardsOffset
|
||||
)
|
||||
{
|
||||
CONST CHAR8 *Result;
|
||||
|
||||
Result = InternalPlistStrStrSameLevelUp (
|
||||
AnchorString,
|
||||
FindString,
|
||||
FindStringLen
|
||||
);
|
||||
if (Result == NULL) {
|
||||
Result = InternalPlistStrStrSameLevelDown (
|
||||
(AnchorString + DownwardsOffset),
|
||||
FindString,
|
||||
FindStringLen
|
||||
);
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
UINT64
|
||||
InternalPlistGetIntValue (
|
||||
IN CONST CHAR8 **Tag
|
||||
)
|
||||
{
|
||||
UINT64 Value;
|
||||
|
||||
CONST CHAR8 *Walker;
|
||||
CHAR8 *Walker2;
|
||||
|
||||
ASSERT (Tag != NULL);
|
||||
ASSERT (*Tag != NULL);
|
||||
ASSERT (AsciiStrnCmp (*Tag, STR_N_HELPER ("<integer")) == 0);
|
||||
|
||||
Walker = (*Tag + L_STR_LEN ("<integer"));
|
||||
//
|
||||
// Skip "size" and any other attributes.
|
||||
//
|
||||
Walker = AsciiStrStr (Walker, ">");
|
||||
ASSERT (Walker != NULL);
|
||||
++Walker;
|
||||
//
|
||||
// Temporarily terminate after the integer definition.
|
||||
//
|
||||
Walker2 = AsciiStrStr (Walker, "<");
|
||||
ASSERT (Walker2 != NULL);
|
||||
*Walker2 = '\0';
|
||||
//
|
||||
// Assert that the prelinked PLIST always uses hexadecimal integers.
|
||||
//
|
||||
while ((*Walker == ' ') || (*Walker == '\t')) {
|
||||
++Walker;
|
||||
}
|
||||
ASSERT ((Walker[1] == 'x') || (Walker[1] == 'X'));
|
||||
Value = AsciiStrHexToUint64 (Walker);
|
||||
//
|
||||
// Restore the previously replaced opening brace.
|
||||
//
|
||||
*Walker2 = '<';
|
||||
//
|
||||
// Return the first character after the integer tag.
|
||||
//
|
||||
*Tag = (Walker2 + L_STR_LEN ("</integer>"));
|
||||
|
||||
return Value;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,859 +0,0 @@
|
||||
/** @file
|
||||
Library handling KEXT prelinking.
|
||||
Currently limited to Intel 64 architectures.
|
||||
|
||||
Copyright (c) 2018, Download-Fritz. All rights reserved.<BR>
|
||||
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 <Base.h>
|
||||
|
||||
#include <IndustryStandard/AppleMachoImage.h>
|
||||
|
||||
#include <Library/BaseLib.h>
|
||||
#include <Library/DebugLib.h>
|
||||
#include <Library/OcGuardLib.h>
|
||||
#include <Library/OcMachoLib.h>
|
||||
|
||||
#include "OcMachoPrelinkInternal.h"
|
||||
|
||||
STATIC
|
||||
CONST OC_VTABLE *
|
||||
InternalGetOcVtableByName (
|
||||
IN CONST OC_VTABLE_ARRAY *Vtables,
|
||||
IN CONST CHAR8 *Name
|
||||
)
|
||||
{
|
||||
CONST OC_VTABLE_ARRAY *VtableWalker;
|
||||
CONST OC_VTABLE *Vtable;
|
||||
UINT32 Index;
|
||||
INTN Result;
|
||||
|
||||
VtableWalker = Vtables;
|
||||
|
||||
do {
|
||||
Vtable = GET_FIRST_OC_VTABLE (VtableWalker);
|
||||
|
||||
for (Index = 0; Index < VtableWalker->NumVtables; ++Index) {
|
||||
Result = AsciiStrCmp (Vtable->Name, Name);
|
||||
if (Result == 0) {
|
||||
return Vtable;
|
||||
}
|
||||
|
||||
Vtable = GET_NEXT_OC_VTABLE (Vtable);
|
||||
}
|
||||
|
||||
VtableWalker = GET_OC_VTABLE_ARRAY_FROM_LINK (
|
||||
GetNextNode (&Vtables->Link, &VtableWalker->Link)
|
||||
);
|
||||
} while (!IsNull (&Vtables->Link, &VtableWalker->Link));
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
STATIC
|
||||
BOOLEAN
|
||||
InternalConstructVtablePrelinked64 (
|
||||
IN OUT OC_MACHO_CONTEXT *MachoContext,
|
||||
IN CONST OC_SYMBOL_TABLE_64 *DefinedSymbols,
|
||||
IN CONST MACH_NLIST_64 *VtableSymbol,
|
||||
OUT OC_VTABLE *Vtable
|
||||
)
|
||||
{
|
||||
BOOLEAN Result;
|
||||
CONST MACH_HEADER_64 *MachHeader;
|
||||
UINT32 VtableOffset;
|
||||
CONST UINT64 *VtableData;
|
||||
UINT64 Value;
|
||||
CONST OC_SYMBOL_TABLE_64 *SymbolsWalker;
|
||||
CONST CHAR8 *StringTable;
|
||||
UINT32 Index;
|
||||
UINT32 Index2;
|
||||
UINT32 CxxIndex;
|
||||
CONST OC_SYMBOL_64 *Symbol;
|
||||
|
||||
ASSERT (MachoContext != NULL);
|
||||
ASSERT (DefinedSymbols != NULL);
|
||||
ASSERT (VtableSymbol != NULL);
|
||||
ASSERT (Vtable != NULL);
|
||||
|
||||
MachHeader = MachoGetMachHeader64 (MachoContext);
|
||||
ASSERT (MachHeader != NULL);
|
||||
|
||||
Result = MachoSymbolGetFileOffset64 (
|
||||
MachoContext,
|
||||
VtableSymbol,
|
||||
&VtableOffset
|
||||
);
|
||||
if (!Result) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
VtableData = (UINT64 *)((UINTN)MachHeader + VtableOffset);
|
||||
if (!OC_ALIGNED (VtableData)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Vtable->Name = MachoGetSymbolName64 (MachoContext, VtableSymbol);
|
||||
//
|
||||
// Initialize the VTable by entries.
|
||||
//
|
||||
SymbolsWalker = DefinedSymbols;
|
||||
|
||||
do {
|
||||
StringTable = SymbolsWalker->StringTable;
|
||||
CxxIndex = (
|
||||
SymbolsWalker->NumSymbols
|
||||
- SymbolsWalker->NumCxxSymbols
|
||||
);
|
||||
//
|
||||
// Assumption: Not ARM (ARM requires an alignment to the function pointer
|
||||
// retrieved from VtableData.
|
||||
//
|
||||
for (
|
||||
Index = VTABLE_HEADER_LEN_64;
|
||||
(Value = VtableData[Index]) != 0;
|
||||
++Index
|
||||
) {
|
||||
for (
|
||||
Index2 = CxxIndex;
|
||||
Index2 < SymbolsWalker->NumSymbols;
|
||||
++Index2
|
||||
) {
|
||||
Symbol = &SymbolsWalker->Symbols[Index2];
|
||||
|
||||
if (Symbol->Value == Value) {
|
||||
Vtable->Entries[Index].Address = Value;
|
||||
Vtable->Entries[Index].Name = (StringTable + Symbol->StringIndex);
|
||||
break;
|
||||
}
|
||||
}
|
||||
//
|
||||
// If we can't find the symbol, it means that the virtual function was
|
||||
// defined inline. There's not much I can do about this; it just means
|
||||
// I can't patch this function.
|
||||
//
|
||||
if (Index == SymbolsWalker->NumCxxSymbols) {
|
||||
Vtable->Entries[Index].Address = 0;
|
||||
Vtable->Entries[Index].Name = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
SymbolsWalker = GET_OC_SYMBOL_TABLE_64_FROM_LINK (
|
||||
GetNextNode (
|
||||
&DefinedSymbols->Link,
|
||||
&SymbolsWalker->Link
|
||||
)
|
||||
);
|
||||
} while (!IsNull (&DefinedSymbols->Link, &SymbolsWalker->Link));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
UINT32
|
||||
InternalGetVtableSize64 (
|
||||
IN CONST UINT64 *VtableData
|
||||
)
|
||||
{
|
||||
UINT32 Index;
|
||||
|
||||
ASSERT (VtableData != NULL);
|
||||
//
|
||||
// Assumption: Not ARM (ARM requires an alignment to the function pointer
|
||||
// retrieved from VtableData.
|
||||
//
|
||||
for (Index = VTABLE_HEADER_LEN_64; VtableData[Index] != 0; ++Index) {
|
||||
;
|
||||
}
|
||||
|
||||
return (Index * VTABLE_ENTRY_SIZE_64);
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
InternalGetVtableSizeWithRelocs64 (
|
||||
IN OUT OC_MACHO_CONTEXT *MachoContext,
|
||||
IN CONST UINT64 *VtableData,
|
||||
OUT UINT32 *VtableSize
|
||||
)
|
||||
{
|
||||
UINT32 Size;
|
||||
MACH_NLIST_64 *Symbol;
|
||||
|
||||
Size = InternalGetVtableSize64 (VtableData);
|
||||
|
||||
Symbol = MachoGetSymbolByExternRelocationOffset64 (
|
||||
MachoContext,
|
||||
((UINTN)VtableData + Size)
|
||||
);
|
||||
if (Symbol == NULL) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
*VtableSize = Size;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
InternalPrepareCreateVtablesPrelinked64 (
|
||||
IN OC_MACHO_CONTEXT *MachoContext,
|
||||
OUT OC_VTABLE_EXPORT_ARRAY *VtableExport,
|
||||
IN UINT32 VtableExportSize
|
||||
)
|
||||
{
|
||||
UINT32 NumVtables;
|
||||
|
||||
CONST MACH_NLIST_64 *SymbolTable;
|
||||
CONST MACH_NLIST_64 *Symbol;
|
||||
CONST CHAR8 *Name;
|
||||
UINT32 NumSymbols;
|
||||
UINT32 Index;
|
||||
BOOLEAN Result;
|
||||
|
||||
ASSERT (MachoContext != NULL);
|
||||
|
||||
NumVtables = 0;
|
||||
|
||||
NumSymbols = MachoGetSymbolTable (
|
||||
MachoContext,
|
||||
&SymbolTable,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
);
|
||||
for (Index = 0; Index < NumSymbols; ++Index) {
|
||||
Symbol = &SymbolTable[Index];
|
||||
Name = MachoGetSymbolName64 (MachoContext, Symbol);
|
||||
if (MachoSymbolNameIsVtable64 (Name)) {
|
||||
Result = MachoIsSymbolValueInRange64 (
|
||||
MachoContext,
|
||||
VtableExport->Symbols[Index]
|
||||
);
|
||||
if (!Result) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
++NumVtables;
|
||||
|
||||
if (VtableExportSize < (NumVtables * sizeof (*VtableExport))) {
|
||||
ASSERT (FALSE);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
VtableExport->Symbols[NumVtables] = Symbol;
|
||||
}
|
||||
}
|
||||
|
||||
VtableExport->NumSymbols = NumVtables;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
InternalCreateVtablesPrelinked64 (
|
||||
IN OC_MACHO_CONTEXT *MachoContext,
|
||||
IN CONST OC_SYMBOL_TABLE_64 *DefinedSymbols,
|
||||
IN OC_VTABLE_EXPORT_ARRAY *VtableExport,
|
||||
OUT OC_VTABLE *VtableBuffer
|
||||
)
|
||||
{
|
||||
CONST MACH_NLIST_64 *Symbol;
|
||||
UINT32 Index;
|
||||
BOOLEAN Result;
|
||||
|
||||
ASSERT (MachoContext != NULL);
|
||||
ASSERT (DefinedSymbols != NULL);
|
||||
|
||||
for (Index = 0; Index < VtableExport->NumSymbols; ++Index) {
|
||||
Symbol = VtableExport->Symbols[Index];
|
||||
Result = InternalConstructVtablePrelinked64 (
|
||||
MachoContext,
|
||||
DefinedSymbols,
|
||||
Symbol,
|
||||
VtableBuffer
|
||||
);
|
||||
if (!Result) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
VtableBuffer = GET_NEXT_OC_VTABLE (VtableBuffer);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* kxld_vtable_patch
|
||||
*/
|
||||
STATIC
|
||||
BOOLEAN
|
||||
InternalPatchVtableSymbol (
|
||||
IN OUT OC_MACHO_CONTEXT *MachoContext,
|
||||
IN CONST OC_VTABLE_ENTRY *ParentEntry,
|
||||
IN CONST CHAR8 *VtableName,
|
||||
OUT MACH_NLIST_64 *Symbol
|
||||
)
|
||||
{
|
||||
CONST CHAR8 *Name;
|
||||
INTN Result;
|
||||
BOOLEAN Success;
|
||||
CONST CHAR8 *ClassName;
|
||||
CHAR8 FunctionPrefix[SYM_MAX_NAME_LEN];
|
||||
|
||||
ASSERT (Symbol != NULL);
|
||||
ASSERT (ParentEntry != NULL);
|
||||
//
|
||||
// The child entry can be NULL when a locally-defined, non-external
|
||||
// symbol is stripped. We wouldn't patch this entry anyway, so we
|
||||
// just skip it.
|
||||
//
|
||||
if (Symbol == NULL) {
|
||||
return TRUE;
|
||||
}
|
||||
//
|
||||
// It's possible for the patched parent entry not to have a symbol
|
||||
// (e.g. when the definition is inlined). We can't patch this entry no
|
||||
// matter what, so we'll just skip it and die later if it's a problem
|
||||
// (which is not likely).
|
||||
//
|
||||
if (ParentEntry->Name == NULL) {
|
||||
return MachoIsSymbolValueInRange64 (MachoContext, Symbol);
|
||||
}
|
||||
//
|
||||
// 1) If the symbol is defined locally, do not patch
|
||||
//
|
||||
if (MachoSymbolIsLocalDefined (MachoContext, Symbol)) {
|
||||
return MachoIsSymbolValueInRange64 (MachoContext, Symbol);
|
||||
}
|
||||
|
||||
Name = MachoGetSymbolName64 (MachoContext, Symbol);
|
||||
//
|
||||
// 2) If the child is a pure virtual function, do not patch.
|
||||
// In general, we want to proceed with patching when the symbol is
|
||||
// externally defined because pad slots fall into this category.
|
||||
// The pure virtual function symbol is special case, as the pure
|
||||
// virtual property itself overrides the parent's implementation.
|
||||
//
|
||||
if (MachoSymbolNameIsPureVirtual (Name)) {
|
||||
return MachoIsSymbolValueInRange64 (MachoContext, Symbol);
|
||||
}
|
||||
//
|
||||
// 3) If the symbols are the same, do not patch
|
||||
//
|
||||
Result = AsciiStrCmp (Name, ParentEntry->Name);
|
||||
if (Result == 0) {
|
||||
return MachoIsSymbolValueInRange64 (MachoContext, Symbol);
|
||||
}
|
||||
//
|
||||
// 4) If the parent vtable entry is a pad slot, and the child does not
|
||||
// match it, then the child was built against a newer version of the
|
||||
// libraries, so it is binary-incompatible.
|
||||
//
|
||||
if (MachoSymbolNameIsPadslot (ParentEntry->Name)) {
|
||||
return FALSE;
|
||||
}
|
||||
//
|
||||
// 5) If we are doing strict patching, we prevent kexts from declaring
|
||||
// virtual functions and not implementing them. We can tell if a
|
||||
// virtual function is declared but not implemented because we resolve
|
||||
// symbols before patching; an unimplemented function will still be
|
||||
// undefined at this point. We then look at whether the symbol has
|
||||
// the same class prefix as the vtable. If it does, the symbol was
|
||||
// declared as part of the class and not inherited, which means we
|
||||
// should not patch it.
|
||||
//
|
||||
if (!MachoSymbolIsDefined (MachoContext, Symbol)) {
|
||||
ClassName = MachoGetClassNameFromVtableName (VtableName);
|
||||
|
||||
Success = MachoGetFunctionPrefixFromClassName (
|
||||
ClassName,
|
||||
sizeof (FunctionPrefix),
|
||||
FunctionPrefix
|
||||
);
|
||||
if (!Success) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Result = AsciiStrCmp (Name, FunctionPrefix);
|
||||
if (Result == 0) {
|
||||
//
|
||||
// The VTable's class declares a method without providing an
|
||||
// implementation.
|
||||
//
|
||||
ASSERT (FALSE);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
//
|
||||
// 6) The child symbol is unresolved and different from its parent, so
|
||||
// we need to patch it up. We do this by modifying the relocation
|
||||
// entry of the vtable entry to point to the symbol of the parent
|
||||
// vtable entry. If that symbol does not exist (i.e. we got the data
|
||||
// from a link state object's vtable representation), then we create a
|
||||
// new symbol in the symbol table and point the relocation entry to
|
||||
// that.
|
||||
//
|
||||
// NOTE: The original logic has been altered significantly. Instead of
|
||||
// declaring a symbol as "replaced" and either changing the
|
||||
// associated relocation's index to the parent's or adding a new symbol
|
||||
// based on a match, the symbol is actually overwritten. This looks
|
||||
// fine for the rest of the control flow. The symbol name is not
|
||||
// changed for the symbol value is already resolved and nothing but a
|
||||
// VTable Relocation should reference it.
|
||||
//
|
||||
InternalSolveSymbolValue64 (ParentEntry->Address, Symbol);
|
||||
//
|
||||
// The C++ ABI requires that functions be aligned on a 2-byte boundary:
|
||||
// http://www.codesourcery.com/public/cxx-abi/abi.html#member-pointers
|
||||
// If the LSB of any virtual function's link address is 1, then the
|
||||
// compiler has violated that part of the ABI, and we're going to panic
|
||||
// in _ptmf2ptf() (in OSMetaClass.h). Better to panic here with some
|
||||
// context.
|
||||
//
|
||||
Name = ParentEntry->Name;
|
||||
ASSERT (MachoSymbolNameIsPureVirtual (Name) || ((Symbol->Value & 1U) == 0));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
STATIC
|
||||
BOOLEAN
|
||||
InternalInitializeVtableByEntriesAndRelocations64 (
|
||||
IN OUT OC_MACHO_CONTEXT *MachoContext,
|
||||
IN CONST OC_SYMBOL_TABLE_64 *DefinedSymbols,
|
||||
IN CONST OC_VTABLE *SuperVtable,
|
||||
IN CONST MACH_NLIST_64 *VtableSymbol,
|
||||
IN CONST UINT64 *VtableData,
|
||||
OUT OC_VTABLE *Vtable
|
||||
)
|
||||
{
|
||||
UINT32 NumEntries;
|
||||
UINT32 Index;
|
||||
UINT32 CxxIndex;
|
||||
UINT32 EntryOffset;
|
||||
UINT64 EntryValue;
|
||||
CONST OC_SYMBOL_TABLE_64 *SymbolsWalker;
|
||||
CONST OC_SYMBOL_64 *OcSymbol;
|
||||
CONST CHAR8 *StringTable;
|
||||
MACH_NLIST_64 *Symbol;
|
||||
BOOLEAN Result;
|
||||
CONST CHAR8 *Name;
|
||||
//
|
||||
// Assumption: Not ARM (ARM requires an alignment to the function pointer
|
||||
// retrieved from VtableData.
|
||||
//
|
||||
for (
|
||||
NumEntries = 0, EntryOffset = VTABLE_HEADER_LEN_64;
|
||||
TRUE;
|
||||
++NumEntries, ++EntryOffset
|
||||
) {
|
||||
EntryValue = VtableData[EntryOffset];
|
||||
//
|
||||
// If we can't find a symbol, it means it is a locally-defined,
|
||||
// non-external symbol that has been stripped. We don't patch over
|
||||
// locally-defined symbols, so we leave the symbol as NULL and just
|
||||
// skip it. We won't be able to patch subclasses with this symbol,
|
||||
// but there isn't much we can do about that.
|
||||
//
|
||||
if (EntryValue != 0) {
|
||||
SymbolsWalker = DefinedSymbols;
|
||||
CxxIndex = (
|
||||
SymbolsWalker->NumSymbols
|
||||
- SymbolsWalker->NumCxxSymbols
|
||||
);
|
||||
do {
|
||||
StringTable = SymbolsWalker->StringTable;
|
||||
//
|
||||
// Imported symbols are implicitely locally defined and hence do not
|
||||
// need to be patched.
|
||||
//
|
||||
for (
|
||||
Index = CxxIndex;
|
||||
Index < SymbolsWalker->NumSymbols;
|
||||
++Index
|
||||
) {
|
||||
OcSymbol = &SymbolsWalker->Symbols[Index];
|
||||
|
||||
if (OcSymbol->Value == EntryValue) {
|
||||
Name = (StringTable + OcSymbol->StringIndex);
|
||||
Vtable->Entries[NumEntries].Name = Name;
|
||||
Vtable->Entries[NumEntries].Address = OcSymbol->Value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (Index != SymbolsWalker->NumSymbols) {
|
||||
break;
|
||||
}
|
||||
|
||||
SymbolsWalker = GET_OC_SYMBOL_TABLE_64_FROM_LINK (
|
||||
GetNextNode (
|
||||
&DefinedSymbols->Link,
|
||||
&SymbolsWalker->Link
|
||||
)
|
||||
);
|
||||
if (IsNull (&DefinedSymbols->Link, &SymbolsWalker->Link)) {
|
||||
ASSERT (FALSE);
|
||||
return FALSE;
|
||||
}
|
||||
} while (TRUE);
|
||||
} else if (NumEntries < SuperVtable->NumEntries) {
|
||||
Symbol = MachoGetSymbolByExternRelocationOffset64 (
|
||||
MachoContext,
|
||||
(VtableSymbol->Value + EntryOffset)
|
||||
);
|
||||
|
||||
if (Symbol == NULL) {
|
||||
//
|
||||
// When the VTable entry is 0 and it is not referenced by a Relocation,
|
||||
// it is the end of the table.
|
||||
//
|
||||
break;
|
||||
}
|
||||
|
||||
Result = InternalPatchVtableSymbol (
|
||||
MachoContext,
|
||||
&SuperVtable->Entries[NumEntries],
|
||||
MachoGetSymbolName64 (MachoContext, VtableSymbol),
|
||||
Symbol
|
||||
);
|
||||
if (!Result) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Name = MachoGetSymbolName64 (MachoContext, Symbol);
|
||||
Vtable->Entries[NumEntries].Name = Name;
|
||||
Vtable->Entries[NumEntries].Address = Symbol->Value;
|
||||
}
|
||||
}
|
||||
|
||||
Vtable->NumEntries = NumEntries;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
InternalPrepareVtableCreationNonPrelinked64 (
|
||||
IN OUT OC_MACHO_CONTEXT *MachoContext,
|
||||
IN UINT32 NumSymbols,
|
||||
IN CONST MACH_NLIST_64 *SymbolTable,
|
||||
OUT OC_VTABLE_PATCH_ARRAY *PatchData
|
||||
)
|
||||
{
|
||||
CONST MACH_HEADER_64 *MachHeader;
|
||||
UINT32 Index;
|
||||
UINT32 NumTables;
|
||||
BOOLEAN Result;
|
||||
CONST MACH_NLIST_64 *Smcp;
|
||||
CONST CHAR8 *Name;
|
||||
CONST MACH_NLIST_64 *VtableSymbol;
|
||||
CONST MACH_NLIST_64 *MetaVtableSymbol;
|
||||
|
||||
MachHeader = MachoGetMachHeader64 (MachoContext);
|
||||
ASSERT (MachHeader != NULL);
|
||||
|
||||
NumTables = 0;
|
||||
|
||||
for (Index = 0; Index < NumSymbols; ++Index) {
|
||||
Smcp = &SymbolTable[Index];
|
||||
Name = MachoGetSymbolName64 (MachoContext, Smcp);
|
||||
if (MachoSymbolNameIsSmcp64 (MachoContext, Name)) {
|
||||
//
|
||||
// We walk over the super metaclass pointer symbols because classes
|
||||
// with them are the only ones that need patching. Then we double the
|
||||
// number of vtables we're expecting, because every pointer will have a
|
||||
// class vtable and a MetaClass vtable.
|
||||
//
|
||||
Result = MachoGetVtableSymbolsFromSmcp64 (
|
||||
MachoContext,
|
||||
Name,
|
||||
&VtableSymbol,
|
||||
&MetaVtableSymbol
|
||||
);
|
||||
if (!Result) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
PatchData[NumTables].Entries->Smcp = Smcp;
|
||||
PatchData[NumTables].Entries->Vtable = VtableSymbol;
|
||||
PatchData[NumTables].Entries->MetaVtable = MetaVtableSymbol;
|
||||
++NumTables;
|
||||
}
|
||||
}
|
||||
|
||||
PatchData->NumEntries = NumTables;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
InternalCreateVtablesNonPrelinked64 (
|
||||
IN OUT OC_MACHO_CONTEXT *MachoContext,
|
||||
IN CONST OC_DEPENDENCY_DATA *DependencyData,
|
||||
IN OC_VTABLE_PATCH_ARRAY *PatchData,
|
||||
OUT OC_VTABLE_ARRAY *VtableArray
|
||||
)
|
||||
{
|
||||
OC_VTABLE *VtableBuffer;
|
||||
CONST MACH_HEADER_64 *MachHeader;
|
||||
UINT32 Index;
|
||||
UINT32 NumPatched;
|
||||
BOOLEAN Result;
|
||||
CONST MACH_NLIST_64 *Smcp;
|
||||
CONST CHAR8 *Name;
|
||||
UINT32 VtableOffset;
|
||||
CONST MACH_NLIST_64 *VtableSymbol;
|
||||
CONST MACH_NLIST_64 *MetaVtableSymbol;
|
||||
CONST MACH_NLIST_64 *MetaClass;
|
||||
CONST UINT64 *VtableData;
|
||||
CONST OC_VTABLE *SuperVtable;
|
||||
CONST OC_VTABLE *MetaVtable;
|
||||
CONST OC_SYMBOL_64 *OcSymbolDummy;
|
||||
MACH_NLIST_64 *SymbolDummy;
|
||||
CHAR8 ClassName[SYM_MAX_NAME_LEN];
|
||||
CHAR8 SuperClassName[SYM_MAX_NAME_LEN];
|
||||
CHAR8 VtableName[SYM_MAX_NAME_LEN];
|
||||
CHAR8 SuperVtableName[SYM_MAX_NAME_LEN];
|
||||
CHAR8 FinalSymbolName[SYM_MAX_NAME_LEN];
|
||||
BOOLEAN SuccessfulIteration;
|
||||
|
||||
MachHeader = MachoGetMachHeader64 (MachoContext);
|
||||
ASSERT (MachHeader != NULL);
|
||||
|
||||
VtableBuffer = GET_FIRST_OC_VTABLE (VtableArray);
|
||||
NumPatched = 0;
|
||||
|
||||
while (NumPatched < PatchData->NumEntries) {
|
||||
SuccessfulIteration = FALSE;
|
||||
|
||||
for (Index = 0; Index < PatchData->NumEntries; ++Index) {
|
||||
Smcp = PatchData->Entries[Index].Smcp;
|
||||
Name = MachoGetSymbolName64 (MachoContext, Smcp);
|
||||
//
|
||||
// We walk over the super metaclass pointer symbols because classes
|
||||
// with them are the only ones that need patching. Then we double the
|
||||
// number of vtables we're expecting, because every pointer will have a
|
||||
// class vtable and a MetaClass vtable.
|
||||
//
|
||||
ASSERT (MachoSymbolNameIsSmcp64 (MachoContext, Name));
|
||||
VtableSymbol = PatchData->Entries[Index].Vtable;
|
||||
MetaVtableSymbol = PatchData->Entries[Index].MetaVtable;
|
||||
//
|
||||
// Get the class name from the smc pointer
|
||||
//
|
||||
Result = MachoGetClassNameFromSuperMetaClassPointer (
|
||||
MachoContext,
|
||||
Name,
|
||||
sizeof (ClassName),
|
||||
ClassName
|
||||
);
|
||||
if (!Result) {
|
||||
return FALSE;
|
||||
}
|
||||
//
|
||||
// Get the vtable name from the class name
|
||||
//
|
||||
Result = MachoGetVtableNameFromClassName (
|
||||
ClassName,
|
||||
sizeof (VtableName),
|
||||
VtableName
|
||||
);
|
||||
if (!Result) {
|
||||
return FALSE;
|
||||
}
|
||||
//
|
||||
// Find the SMCP's meta class symbol
|
||||
//
|
||||
MetaClass = MachoGetMetaclassSymbolFromSmcpSymbol64 (
|
||||
MachoContext,
|
||||
Smcp
|
||||
);
|
||||
if (MetaClass == NULL) {
|
||||
return FALSE;
|
||||
}
|
||||
//
|
||||
// Get the super class name from the super metaclass
|
||||
//
|
||||
Result = MachoGetClassNameFromMetaClassPointer (
|
||||
MachoContext,
|
||||
MachoGetSymbolName64 (MachoContext, MetaClass),
|
||||
sizeof (SuperClassName),
|
||||
SuperClassName
|
||||
);
|
||||
if (!Result) {
|
||||
return FALSE;
|
||||
}
|
||||
//
|
||||
// Get the super vtable if it's been patched
|
||||
//
|
||||
SuperVtable = InternalGetOcVtableByName (
|
||||
DependencyData->Vtables,
|
||||
SuperVtableName
|
||||
);
|
||||
if (SuperVtable == NULL) {
|
||||
continue;
|
||||
}
|
||||
//
|
||||
// Get the final symbol's name from the super vtable
|
||||
//
|
||||
Result = MachoGetFinalSymbolNameFromClassName (
|
||||
SuperClassName,
|
||||
sizeof (FinalSymbolName),
|
||||
FinalSymbolName
|
||||
);
|
||||
if (!Result) {
|
||||
return FALSE;
|
||||
}
|
||||
//
|
||||
// Verify that the final symbol does not exist. First check
|
||||
// all the externally defined symbols, then check locally.
|
||||
//
|
||||
OcSymbolDummy = InternalOcGetSymbolByName (
|
||||
DependencyData->SymbolTable,
|
||||
FinalSymbolName,
|
||||
TRUE
|
||||
);
|
||||
if (OcSymbolDummy != NULL) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Result = MachoGetLocalDefinedSymbolByName (
|
||||
MachoContext,
|
||||
FinalSymbolName,
|
||||
&SymbolDummy
|
||||
);
|
||||
if (!Result || (SymbolDummy != NULL)) {
|
||||
return FALSE;
|
||||
}
|
||||
//
|
||||
// Patch the class's vtable
|
||||
//
|
||||
Result = MachoSymbolGetFileOffset64 (
|
||||
MachoContext,
|
||||
VtableSymbol,
|
||||
&VtableOffset
|
||||
);
|
||||
if (!Result) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
VtableData = (UINT64 *)((UINTN)MachHeader + VtableOffset);
|
||||
if (!OC_ALIGNED (VtableData)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Result = InternalInitializeVtableByEntriesAndRelocations64 (
|
||||
MachoContext,
|
||||
DependencyData->SymbolTable,
|
||||
SuperVtable,
|
||||
VtableSymbol,
|
||||
VtableData,
|
||||
VtableBuffer
|
||||
);
|
||||
if (!Result) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
VtableBuffer->Name = MachoGetSymbolName64 (MachoContext, VtableSymbol);
|
||||
//
|
||||
// Add the class's vtable to the set of patched vtables
|
||||
// This is done implicitely as we're operating on an array.
|
||||
//
|
||||
VtableBuffer = GET_NEXT_OC_VTABLE (VtableBuffer);
|
||||
//
|
||||
// Get the meta vtable name from the class name
|
||||
//
|
||||
Result = MachoGetMetaVtableNameFromClassName (
|
||||
ClassName,
|
||||
sizeof (VtableName),
|
||||
VtableName
|
||||
);
|
||||
if (!Result) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
MetaVtable = InternalGetOcVtableByName (
|
||||
DependencyData->Vtables,
|
||||
VtableName
|
||||
);
|
||||
if (MetaVtable != NULL) {
|
||||
return FALSE;
|
||||
}
|
||||
//
|
||||
// There is no way to look up a metaclass vtable at runtime, but
|
||||
// we know that every class's metaclass inherits directly from
|
||||
// OSMetaClass, so we just hardcode that vtable name here.
|
||||
//
|
||||
SuperVtable = InternalGetOcVtableByName (
|
||||
DependencyData->Vtables,
|
||||
OS_METACLASS_VTABLE_NAME
|
||||
);
|
||||
if (SuperVtable == NULL) {
|
||||
return FALSE;
|
||||
}
|
||||
//
|
||||
// meta_vtable_sym will be null when we don't support strict
|
||||
// patching and can't find the metaclass vtable. If that's the
|
||||
// case, we just reduce the expect number of vtables by 1.
|
||||
// Only i386 does not support strict patchting.
|
||||
//
|
||||
Result = MachoSymbolGetFileOffset64 (
|
||||
MachoContext,
|
||||
MetaVtableSymbol,
|
||||
&VtableOffset
|
||||
);
|
||||
if (!Result) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
VtableData = (UINT64 *)((UINTN)MachHeader + VtableOffset);
|
||||
if (!OC_ALIGNED (VtableData)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Result = InternalInitializeVtableByEntriesAndRelocations64 (
|
||||
MachoContext,
|
||||
DependencyData->SymbolTable,
|
||||
SuperVtable,
|
||||
MetaVtableSymbol,
|
||||
VtableData,
|
||||
VtableBuffer
|
||||
);
|
||||
if (!Result) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
VtableBuffer->Name = MachoGetSymbolName64 (MachoContext, MetaVtableSymbol);
|
||||
//
|
||||
// Add the MetaClass's vtable to the set of patched vtables
|
||||
// This is done implicitely as we're operating on an array.
|
||||
//
|
||||
VtableBuffer = GET_NEXT_OC_VTABLE (VtableBuffer);
|
||||
|
||||
++NumPatched;
|
||||
SuccessfulIteration = TRUE;
|
||||
}
|
||||
//
|
||||
// Exit when there are unpatched VTables left, but there are none patched
|
||||
// in a full iteration.
|
||||
//
|
||||
if (!SuccessfulIteration) {
|
||||
ASSERT (FALSE);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
VtableArray->NumVtables = (NumPatched * 2);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@ -453,14 +453,25 @@ int main(int argc, char** argv) {
|
||||
|
||||
DEBUG ((DEBUG_WARN, "TestDriver.kext injected - %zx\n", Status));
|
||||
|
||||
UINT8 *TestData = LiluKextData;
|
||||
UINT32 TestDataSize = LiluKextDataSize;
|
||||
|
||||
if (argc > 2) {
|
||||
TestData = readFile(argv[2], &TestDataSize);
|
||||
if (TestData == NULL) {
|
||||
printf("Read fail\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
Status = PrelinkedInjectKext (
|
||||
&Context,
|
||||
"/Library/Extensions/Lilu.kext",
|
||||
LiluKextInfoPlistData,
|
||||
LiluKextInfoPlistDataSize,
|
||||
"Contents/MacOS/Lilu",
|
||||
LiluKextData,
|
||||
LiluKextDataSize
|
||||
TestData,
|
||||
TestDataSize
|
||||
);
|
||||
|
||||
DEBUG ((DEBUG_WARN, "Lilu.kext injected - %r\n", Status));
|
||||
|
||||
BIN
TestsUser/Prelinked/Prelinked_
Executable file
BIN
TestsUser/Prelinked/Prelinked_
Executable file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user