right way to patch kexts

Signed-off-by: SergeySlice <sergey.slice@gmail.com>
This commit is contained in:
SergeySlice 2020-07-23 22:14:20 +03:00
parent f7c13f0b84
commit 0143e228ee
5 changed files with 374 additions and 32 deletions

View File

@ -558,17 +558,21 @@
</dict>
<dict>
<key>Comment</key>
<string>Patch 8 apples</string>
<string>Violet strips</string>
<key>Disabled</key>
<true/>
<key>Find</key>
<data>AQAAdSI=</data>
<key>MatchOS</key>
<string>10.13</string>
<false/>
<key>Name</key>
<string>IOGraphicsFamily</string>
<string>com.apple.kext.AMDSupport</string>
<key>Procedure</key>
<string>TestVRAM</string>
<key>Find</key>
<data>VUiJ</data>
<key>Replace</key>
<data>AQAA6yI=</data>
<data>sAHD</data>
<key>FindMask</key>
<data>AAAA</data>
<key>RangeFind</key>
<integer>10</integer>
</dict>
</array>
<key>KernelXCPM</key>

View File

@ -372,7 +372,7 @@ struct segment_command_64 { /* for 64-bit architectures */
vm_prot_t initprot; /* initial VM protection */ //3c
uint32_t nsects; /* number of sections in segment */ //40
uint32_t flags; /* flags */ //44
//struct section_64 sect[nsects]; //0x48 if nsect > 0
// struct section_64 sect[]; //0x48 if nsect > 0 len=nsects
};
/* Constants for the flags field of the segment_command */
@ -1565,14 +1565,285 @@ struct note_command {
//kexts cache
struct command_35 {
uint32_t cmd; //0x35 - LC_KEXT
uint32_t cmdsize; //0x38 - short name, 0x48 - long name
uint32_t cmdsize; //0x38 - short name, 0x48 - long name, ...
uint64_t offset; /* file offset of this data */
uint64_t size; /* length of data region */
uint32_t res1;
uint32_t res2;
char name[16]; //kext name [16] or [32]
uint32_t res1; //=0x20
uint32_t res2; //=0x00
char name[]; //kext name [16] or [32]
// align to 8 byte boundary
};
//from file nlist.h
//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 */
//};
/*
* This is the symbol table entry structure for 64-bit architectures.
*/
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 <mach-o/stab.h> */
uint64_t n_value; /* value of this symbol (or stab offset) */
};
//samples, str=0x39A9C48
//25000000 0F060000 940BFF00 80FFFFFF constructors_used, seg=__DATA:__lock_grp
//2D9D0000 0F170000 00601000 80FFFFFF _BootPDPT __HIB:__text
//EDCD0000 0F010000 F0729D00 80FFFFFF _IOFlushProcessorCache __TEXT:__text
//7DE90000 0F150000 B0A6C100 80FFFFFF _KHEAP_AUDIT __DATA_CONST:__mod_init_func
/*
* Symbols with a index into the string table of zero (n_un.n_strx == 0) are
* defined to have a null, "", name. Therefore all string indexes to non null
* names must not have a zero string index. This is bit historical information
* that has never been well documented.
*/
/*
* The n_type field really contains four fields:
* unsigned char N_STAB:3,
* N_PEXT:1,
* N_TYPE:3,
* N_EXT:1;
* which are used via the following masks.
*/
#define N_STAB 0xe0 /* if any of these bits set, a symbolic debugging entry */
#define N_PEXT 0x10 /* private external symbol bit */
#define N_TYPE 0x0e /* mask for the type bits */
#define N_EXT 0x01 /* external symbol bit, set for external symbols */
/*
* Only symbolic debugging entries have some of the N_STAB bits set and if any
* of these bits are set then it is a symbolic debugging entry (a stab). In
* which case then the values of the n_type field (the entire field) are given
* in <mach-o/stab.h>
*/
/*
* Symbolic debugger symbols. The comments give the conventional use for
*
* .stabs "n_name", n_type, n_sect, n_desc, n_value
*
* where n_type is the defined constant and not listed in the comment. Other
* fields not listed are zero. n_sect is the section ordinal the entry is
* refering to.
*/
#define N_GSYM 0x20 /* global symbol: name,,NO_SECT,type,0 */
#define N_FNAME 0x22 /* procedure name (f77 kludge): name,,NO_SECT,0,0 */
#define N_FUN 0x24 /* procedure: name,,n_sect,linenumber,address */
#define N_STSYM 0x26 /* static symbol: name,,n_sect,type,address */
#define N_LCSYM 0x28 /* .lcomm symbol: name,,n_sect,type,address */
#define N_BNSYM 0x2e /* begin nsect sym: 0,,n_sect,0,address */
#define N_AST 0x32 /* AST file path: name,,NO_SECT,0,0 */
#define N_OPT 0x3c /* emitted with gcc2_compiled and in gcc source */
#define N_RSYM 0x40 /* register sym: name,,NO_SECT,type,register */
#define N_SLINE 0x44 /* src line: 0,,n_sect,linenumber,address */
#define N_ENSYM 0x4e /* end nsect sym: 0,,n_sect,0,address */
#define N_SSYM 0x60 /* structure elt: name,,NO_SECT,type,struct_offset */
#define N_SO 0x64 /* source file name: name,,n_sect,0,address */
#define N_OSO 0x66 /* object file name: name,,0,0,st_mtime */
#define N_LSYM 0x80 /* local sym: name,,NO_SECT,type,offset */
#define N_BINCL 0x82 /* include file beginning: name,,NO_SECT,0,sum */
#define N_SOL 0x84 /* #included file name: name,,n_sect,0,address */
#define N_PARAMS 0x86 /* compiler parameters: name,,NO_SECT,0,0 */
#define N_VERSION 0x88 /* compiler version: name,,NO_SECT,0,0 */
#define N_OLEVEL 0x8A /* compiler -O level: name,,NO_SECT,0,0 */
#define N_PSYM 0xa0 /* parameter: name,,NO_SECT,type,offset */
#define N_EINCL 0xa2 /* include file end: name,,NO_SECT,0,0 */
#define N_ENTRY 0xa4 /* alternate entry: name,,n_sect,linenumber,address */
#define N_LBRAC 0xc0 /* left bracket: 0,,NO_SECT,nesting level,address */
#define N_EXCL 0xc2 /* deleted include file: name,,NO_SECT,0,sum */
#define N_RBRAC 0xe0 /* right bracket: 0,,NO_SECT,nesting level,address */
#define N_BCOMM 0xe2 /* begin common: name,,NO_SECT,0,0 */
#define N_ECOMM 0xe4 /* end common: name,,n_sect,0,0 */
#define N_ECOML 0xe8 /* end common (local name): 0,,n_sect,0,address */
#define N_LENG 0xfe /* second stab entry with length information */
/*
* Values for N_TYPE bits of the n_type field.
*/
#define N_UNDF 0x0 /* undefined, n_sect == NO_SECT */
#define N_ABS 0x2 /* absolute, n_sect == NO_SECT */
#define N_SECT 0xe /* defined in section number n_sect */
#define N_PBUD 0xc /* prebound undefined (defined in a dylib) */
#define N_INDR 0xa /* indirect */
/*
* If the type is N_INDR then the symbol is defined to be the same as another
* symbol. In this case the n_value field is an index into the string table
* of the other symbol's name. When the other symbol is defined then they both
* take on the defined type and value.
*/
/*
* If the type is N_SECT then the n_sect field contains an ordinal of the
* section the symbol is defined in. The sections are numbered from 1 and
* refer to sections in order they appear in the load commands for the file
* they are in. This means the same ordinal may very well refer to different
* sections in different files.
*
* The n_value field for all symbol table entries (including N_STAB's) gets
* updated by the link editor based on the value of it's n_sect field and where
* the section n_sect references gets relocated. If the value of the n_sect
* field is NO_SECT then it's n_value field is not changed by the link editor.
*/
#define NO_SECT 0 /* symbol is not in any section */
#define MAX_SECT 255 /* 1 thru 255 inclusive */
/*
* Common symbols are represented by undefined (N_UNDF) external (N_EXT) types
* who's values (n_value) are non-zero. In which case the value of the n_value
* field is the size (in bytes) of the common symbol. The n_sect field is set
* to NO_SECT. The alignment of a common symbol may be set as a power of 2
* between 2^1 and 2^15 as part of the n_desc field using the macros below. If
* the alignment is not set (a value of zero) then natural alignment based on
* the size is used.
*/
#define GET_COMM_ALIGN(n_desc) (((n_desc) >> 8) & 0x0f)
#define SET_COMM_ALIGN(n_desc,align) \
(n_desc) = (((n_desc) & 0xf0ff) | (((align) & 0x0f) << 8))
/*
* To support the lazy binding of undefined symbols in the dynamic link-editor,
* the undefined symbols in the symbol table (the nlist structures) are marked
* with the indication if the undefined reference is a lazy reference or
* non-lazy reference. If both a non-lazy reference and a lazy reference is
* made to the same symbol the non-lazy reference takes precedence. A reference
* is lazy only when all references to that symbol are made through a symbol
* pointer in a lazy symbol pointer section.
*
* The implementation of marking nlist structures in the symbol table for
* undefined symbols will be to use some of the bits of the n_desc field as a
* reference type. The mask REFERENCE_TYPE will be applied to the n_desc field
* of an nlist structure for an undefined symbol to determine the type of
* undefined reference (lazy or non-lazy).
*
* The constants for the REFERENCE FLAGS are propagated to the reference table
* in a shared library file. In that case the constant for a defined symbol,
* REFERENCE_FLAG_DEFINED, is also used.
*/
/* Reference type bits of the n_desc field of undefined symbols */
#define REFERENCE_TYPE 0x7
/* types of references */
#define REFERENCE_FLAG_UNDEFINED_NON_LAZY 0
#define REFERENCE_FLAG_UNDEFINED_LAZY 1
#define REFERENCE_FLAG_DEFINED 2
#define REFERENCE_FLAG_PRIVATE_DEFINED 3
#define REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY 4
#define REFERENCE_FLAG_PRIVATE_UNDEFINED_LAZY 5
/*
* To simplify stripping of objects that use are used with the dynamic link
* editor, the static link editor marks the symbols defined an object that are
* referenced by a dynamicly bound object (dynamic shared libraries, bundles).
* With this marking strip knows not to strip these symbols.
*/
#define REFERENCED_DYNAMICALLY 0x0010
/*
* For images created by the static link editor with the -twolevel_namespace
* option in effect the flags field of the mach header is marked with
* MH_TWOLEVEL. And the binding of the undefined references of the image are
* determined by the static link editor. Which library an undefined symbol is
* bound to is recorded by the static linker in the high 8 bits of the n_desc
* field using the SET_LIBRARY_ORDINAL macro below. The ordinal recorded
* references the libraries listed in the Mach-O's LC_LOAD_DYLIB,
* LC_LOAD_WEAK_DYLIB, LC_REEXPORT_DYLIB, LC_LOAD_UPWARD_DYLIB, and
* LC_LAZY_LOAD_DYLIB, etc. load commands in the order they appear in the
* headers. The library ordinals start from 1.
* For a dynamic library that is built as a two-level namespace image the
* undefined references from module defined in another use the same nlist struct
* an in that case SELF_LIBRARY_ORDINAL is used as the library ordinal. For
* defined symbols in all images they also must have the library ordinal set to
* SELF_LIBRARY_ORDINAL. The EXECUTABLE_ORDINAL refers to the executable
* image for references from plugins that refer to the executable that loads
* them.
*
* The DYNAMIC_LOOKUP_ORDINAL is for undefined symbols in a two-level namespace
* image that are looked up by the dynamic linker with flat namespace semantics.
* This ordinal was added as a feature in Mac OS X 10.3 by reducing the
* value of MAX_LIBRARY_ORDINAL by one. So it is legal for existing binaries
* or binaries built with older tools to have 0xfe (254) dynamic libraries. In
* this case the ordinal value 0xfe (254) must be treated as a library ordinal
* for compatibility.
*/
#define GET_LIBRARY_ORDINAL(n_desc) (((n_desc) >> 8) & 0xff)
#define SET_LIBRARY_ORDINAL(n_desc,ordinal) \
(n_desc) = (((n_desc) & 0x00ff) | (((ordinal) & 0xff) << 8))
#define SELF_LIBRARY_ORDINAL 0x0
#define MAX_LIBRARY_ORDINAL 0xfd
#define DYNAMIC_LOOKUP_ORDINAL 0xfe
#define EXECUTABLE_ORDINAL 0xff
/*
* The bit 0x0020 of the n_desc field is used for two non-overlapping purposes
* and has two different symbolic names, N_NO_DEAD_STRIP and N_DESC_DISCARDED.
*/
/*
* The N_NO_DEAD_STRIP bit of the n_desc field only ever appears in a
* relocatable .o file (MH_OBJECT filetype). And is used to indicate to the
* static link editor it is never to dead strip the symbol.
*/
#define N_NO_DEAD_STRIP 0x0020 /* symbol is not to be dead stripped */
/*
* The N_DESC_DISCARDED bit of the n_desc field never appears in linked image.
* But is used in very rare cases by the dynamic link editor to mark an in
* memory symbol as discared and longer used for linking.
*/
#define N_DESC_DISCARDED 0x0020 /* symbol is discarded */
/*
* The N_WEAK_REF bit of the n_desc field indicates to the dynamic linker that
* the undefined symbol is allowed to be missing and is to have the address of
* zero when missing.
*/
#define N_WEAK_REF 0x0040 /* symbol is weak referenced */
/*
* The N_WEAK_DEF bit of the n_desc field indicates to the static and dynamic
* linkers that the symbol definition is weak, allowing a non-weak symbol to
* also be used which causes the weak definition to be discared. Currently this
* is only supported for symbols in coalesed sections.
*/
#define N_WEAK_DEF 0x0080 /* coalesed symbol is a weak definition */
/*
* The N_REF_TO_WEAK bit of the n_desc field indicates to the dynamic linker
* that the undefined symbol should be resolved using flat namespace searching.
*/
#define N_REF_TO_WEAK 0x0080 /* reference to a weak symbol */
/*
* The N_ARM_THUMB_DEF bit of the n_desc field indicates that the symbol is
* a defintion of a Thumb function.
*/
#define N_ARM_THUMB_DEF 0x0008 /* symbol is a Thumb function (ARM) */
/*
* The N_SYMBOL_RESOLVER bit of the n_desc field indicates that the
* that the function is actually a resolver function and should
* be called to get the address of the real function to use.
* This bit is only available in .o files (MH_OBJECT filetype)
*/
#define N_SYMBOL_RESOLVER 0x0100
/*
* The N_ALT_ENTRY bit of the n_desc field indicates that the
* symbol is pinned to the previous content.
*/
#define N_ALT_ENTRY 0x0200
#endif /* _MACHO_LOADER_H_ */

View File

@ -73,7 +73,7 @@ VOID LOADER_ENTRY::SetKernelRelocBase()
}
//Slice
// the purpose of the procedure is to find a table of symbols in the kernel
// 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);
@ -115,6 +115,50 @@ EFI_STATUS LOADER_ENTRY::getVTable()
return EFI_SUCCESS;
}
UINT32 LOADER_ENTRY::searchSectionByNum(UINT8 * binary, UINT32 Num)
{
UINT32 ncmds, cmdsize;
UINT32 binaryIndex;
UINT32 currsect = 0;
UINT32 nsect;
UINT32 textAddr;
struct segment_command_64 *loadCommand;
// struct symtab_command *symCmd;
if (!Num) {
return 0;
}
ncmds = MACH_GET_NCMDS(binary);
binaryIndex = sizeof(struct mach_header_64);
for (UINTN cnt = 0; cnt < ncmds; cnt++) {
loadCommand = (struct segment_command_64 *)(binary + binaryIndex);
cmdsize = loadCommand->cmdsize;
switch (loadCommand->cmd) {
case LC_SEGMENT_64:
nsect = loadCommand->nsects;
if (currsect == 0) {
textAddr = binaryIndex + sizeof(struct segment_command_64);
}
if (currsect + nsect >= Num - 1) {
UINT32 sectAddr = binaryIndex + sizeof(struct segment_command_64) + sizeof(struct section_64) * (currsect - Num + 1);
if (*(UINT32*)(binary + sectAddr) == 0x73625F5F) { //special case for __bss
DBG("__bss will be used as __text\n");
return textAddr;
}
return sectAddr;
}
currsect += nsect;
break;
default:
break;
}
binaryIndex += cmdsize;
}
return 0;
}
UINTN LOADER_ENTRY::searchProcInDriver(UINT8 * driver, UINT32 driverLen, const char *procedure)
{
if (!procedure) {
@ -131,14 +175,27 @@ UINTN LOADER_ENTRY::searchProcInDriver(UINT8 * driver, UINT32 driverLen, const c
// 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 <mach-o/stab.h>
uint64_t n_value; // value of this symbol (or stab offset)
};
*/
VTABLE * vArray = NULL;
DBG("search procedure %s\n", procedure);
struct nlist_64 * vArray = NULL;
INT32 lSizeVtable = 0;
const char* Names = NULL;
struct symtab_command *symCmd = NULL;
Get_Symtab(driver, (void**)&symCmd);
if (symCmd != NULL) {
vArray = (VTABLE*)(&driver[symCmd->symoff]);
UINT32 symCmdOffset = 0;
Get_Symtab(driver, &symCmdOffset);
if (symCmdOffset != 0) {
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);
@ -148,9 +205,10 @@ UINTN LOADER_ENTRY::searchProcInDriver(UINT8 * driver, UINT32 driverLen, const c
return 0;
}
INT32 i;
size_t Offset;
bool found = false;
for (i = 0; i < lSizeVtable; ++i) {
size_t Offset = vArray[i].NameOffset;
Offset = vArray[i].n_un.n_strx;
if (strstr(&Names[Offset], procedure)) {
found = true;
break;
@ -160,8 +218,10 @@ UINTN LOADER_ENTRY::searchProcInDriver(UINT8 * driver, UINT32 driverLen, const c
DBG("%s not found\n", procedure);
return 0;
}
DBG("found section 0x%x at pos=%d\n", vArray[i].Seg, i);
INTN lSegVAddr;
DBG("found section %d at pos=%d\n", vArray[i].n_sect, i);
DBG("name offset=0x%lx vtable_off=0x%lx\n", symCmd->stroff + Offset, symCmd->symoff + i * sizeof(struct nlist_64));
INT32 lSegVAddr = searchSectionByNum(driver, vArray[i].n_sect);
/*
switch (vArray[i].Seg) {
case ID_SEG_DATA:
lSegVAddr = FindBin(driver, 0x1600, (const UINT8 *)kDataSegment, (UINT32)strlen(kDataSegment));
@ -207,11 +267,13 @@ UINTN LOADER_ENTRY::searchProcInDriver(UINT8 * driver, UINT32 driverLen, const c
lSegVAddr = 0x38;
}
SEGMENT *TextSeg = (SEGMENT*)&driver[lSegVAddr];
UINT64 Absolut = TextSeg->SegAddress;
UINT64 FileOff = TextSeg->fileoff;
*/
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].ProcAddr - Absolut + FileOff;
UINTN procAddr = vArray[i].n_value - Absolut + FileOff;
DBG("procAddr=0x%llx\n", procAddr);
return procAddr;
}
@ -222,7 +284,7 @@ UINTN LOADER_ENTRY::searchProc(const char *procedure)
if (!procedure) {
return 0;
}
DBG("search name in kernel: %s\n", procedure);
const char* Names = (const char*)(&KernelData[NamesTable]);
VTABLE * vArray = (VTABLE*)(&KernelData[AddrVtable]);
//search for the name
@ -283,6 +345,7 @@ UINTN LOADER_ENTRY::searchProc(const char *procedure)
}
*procLen = vArray[i].ProcAddr - prevAddr; //never worked
*/
DBG("kernel: procAddr=0x%llx\n", procAddr);
return procAddr;
}
@ -1931,7 +1994,7 @@ VOID Patcher_SSE3_7()
}
#endif
void LOADER_ENTRY::Get_Symtab(UINT8* binary, OUT void **symCmd)
void LOADER_ENTRY::Get_Symtab(UINT8* binary, OUT UINT32 *symCmd)
{
UINT32 ncmds, cmdsize;
UINT32 binaryIndex;
@ -1949,7 +2012,7 @@ void LOADER_ENTRY::Get_Symtab(UINT8* binary, OUT void **symCmd)
switch (loadCommand->cmd) {
case LC_SYMTAB:
*symCmd = (void *)loadCommand;
*symCmd = binaryIndex;
// struct symtab_command {
// uint32_t cmd; /* LC_SYMTAB == 2 */
// uint32_t cmdsize; /* sizeof(struct symtab_command) */
@ -2424,9 +2487,11 @@ LOADER_ENTRY::KernelAndKextPatcherInit()
// find __PRELINK_TEXT and __PRELINK_INFO
Get_PreLink();
//find symbol tables
struct symtab_command *symCmd = NULL;
Get_Symtab(&KernelData[KernelOffset], (void**)&symCmd);
if (symCmd != NULL) {
struct symtab_command *symCmd = NULL;
UINT32 symCmdOffset = 0;
Get_Symtab(&KernelData[KernelOffset], &symCmdOffset);
if (symCmdOffset != 0) {
symCmd = (struct symtab_command *)&KernelData[symCmdOffset];
AddrVtable = symCmd->symoff;
SizeVtable = symCmd->nsyms;
NamesTable = symCmd->stroff;

View File

@ -1036,6 +1036,7 @@ VOID LOADER_ENTRY::BDWE_IOPCIPatch(UINT8 *Driver, UINT32 DriverSize, CHAR8 *Info
VOID LOADER_ENTRY::EightApplePatch(UINT8 *Driver, UINT32 DriverSize)
{
// UINTN procLen = 0;
DBG("8 apple patch\n");
UINTN procAddr = searchProcInDriver(Driver, DriverSize, "initFB");
UINTN verbose = searchProcInDriver(Driver, DriverSize, "gIOFBVerboseBoot");
UINTN patchLoc = FindRelative32(Driver, procAddr, 0x300, verbose-1);

View File

@ -408,9 +408,10 @@ class REFIT_ABSTRACT_MENU_ENTRY
void FindBootArgs();
EFI_STATUS getVTable();
void Get_PreLink();
void Get_Symtab(UINT8* binary, OUT void **symCmd);
void Get_Symtab(UINT8* binary, OUT UINT32 *symCmd);
UINTN searchProc(const char *procedure);
UINTN searchProcInDriver(UINT8 * driver, UINT32 driverLen, const char *procedure);
UINT32 searchSectionByNum(UINT8 * Binary, UINT32 Num);
void KernelAndKextsPatcherStart();
void KernelAndKextPatcherInit();
BOOLEAN KernelUserPatch();