Skip to content

Commit be0a2f6

Browse files
authored
Add patch with masking support (#83)
1 parent 8542170 commit be0a2f6

File tree

3 files changed

+151
-18
lines changed

3 files changed

+151
-18
lines changed

Changelog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ Lilu Changelog
44
- Allow loading on macOS 13 without `-lilubetaall`
55
- Added Ventura dyld shared cache pathing
66
- Changed SKL default ig-platform-id to KBL on macOS 13+
7+
- Added patch with masking support
78

89
#### v1.6.0
910
- Dropped internal shared patcher instance grabbing API

Lilu/Headers/kern_patcher.hpp

Lines changed: 49 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -592,28 +592,31 @@ class KernelPatcher {
592592
}
593593

594594
/**
595-
* Simple find and replace in kernel memory.
595+
* Find one pattern with optional masking within a block of memory
596+
*
597+
* @param pattern pattern to search
598+
* @param patternMask pattern mask
599+
* @param patternSize size of pattern
600+
* @param data a block of memory
601+
* @param dataSize size of memory
602+
* @param dataOffset data offset, to be set by this function
603+
*
604+
* @return true if pattern is found in data
596605
*/
597-
static inline bool findAndReplace(void *data, size_t dataSize, const void *find, size_t findSize, const void *replace, size_t replaceSize) {
598-
void *res;
599-
if (UNLIKELY((res = lilu_os_memmem(data, dataSize, find, findSize)) != nullptr)) {
600-
if (UNLIKELY(MachInfo::setKernelWriting(true, KernelPatcher::kernelWriteLock) != KERN_SUCCESS)) {
601-
SYSLOG("patcher", "failed to obtain write permissions for f/r");
602-
return false;
603-
}
606+
EXPORT static bool findPattern(const void *pattern, const void *patternMask, size_t patternSize, const void *data, size_t dataSize, size_t *dataOffset);
604607

605-
lilu_os_memcpy(res, replace, replaceSize);
606-
607-
if (UNLIKELY(MachInfo::setKernelWriting(false, KernelPatcher::kernelWriteLock) != KERN_SUCCESS)) {
608-
SYSLOG("patcher", "failed to restore write permissions for f/r");
609-
}
610-
611-
return true;
612-
}
608+
/**
609+
* Simple find and replace with masking in kernel memory.
610+
*/
611+
EXPORT static bool findAndReplaceWithMask(void *data, size_t dataSize, const void *find, size_t findSize, const void *findMask, size_t findMaskSize, const void *replace, size_t replaceSize, const void *replaceMask, size_t replaceMaskSize, size_t count=0, size_t skip=0);
613612

614-
return false;
613+
/**
614+
* Simple find and replace in kernel memory.
615+
*/
616+
static inline bool findAndReplace(void *data, size_t dataSize, const void *find, size_t findSize, const void *replace, size_t replaceSize) {
617+
return findAndReplaceWithMask(data, dataSize, find, findSize, nullptr, 0, replace, replaceSize, nullptr, 0, 0, 0);
615618
}
616-
619+
617620
/**
618621
* Simple find and replace in kernel memory but require both `find` and `replace` buffers to have the same length
619622
*/
@@ -622,6 +625,14 @@ class KernelPatcher {
622625
return findAndReplace(data, dataSize, find, N, replace, N);
623626
}
624627

628+
/**
629+
* Simple find and replace with masking in kernel memory but require both `find` and `replace` buffers and masking buffers to have the same length
630+
*/
631+
template <size_t N>
632+
static inline bool findAndReplaceWithMask(void *data, size_t dataSize, const uint8_t (&find)[N], const uint8_t (&findMask)[N], const uint8_t (&replace)[N], const uint8_t (&replaceMask)[N], size_t count, size_t skip) {
633+
return findAndReplaceWithMask(data, dataSize, find, N, findMask, N, replace, N, replaceMask, N, count, skip);
634+
}
635+
625636
private:
626637
/**
627638
* Jump type for routing
@@ -707,6 +718,26 @@ class KernelPatcher {
707718
*/
708719
bool routeMultipleInternal(size_t id, RouteRequest *requests, size_t num, mach_vm_address_t start=0, size_t size=0, bool kernelRoute=true, bool force=false, JumpType jumpType=JumpType::Auto);
709720

721+
/**
722+
* Simple find and replace with masking in kernel memory
723+
*
724+
* @param data kernel memory
725+
* @param dataSize size of kernel memory
726+
* @param find find pattern
727+
* @param findSize size of find pattern
728+
* @param findMask find masking pattern
729+
* @param findMaskSize size of find masking pattern
730+
* @param replace replace pattern
731+
* @param replaceSize size of replace pattern
732+
* @param replaceMask replace masking pattern
733+
* @param replaceMaskSize repalce masking pattern
734+
* @param count maximum times of patching
735+
* @param skip number of skipping times before performing replacement
736+
*
737+
* @return true if the finding and replacing performance is successful
738+
*/
739+
static bool findAndReplaceWithMaskInternal(void *data, size_t dataSize, const void *find, size_t findSize, const void *findMask, size_t findMaskSize, const void *replace, size_t replaceSize, const void *replaceMask, size_t replaceMaskSize, size_t count, size_t skip);
740+
710741
#ifdef LILU_KEXTPATCH_SUPPORT
711742
/**
712743
* Process loaded kext

Lilu/Sources/kern_patcher.cpp

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -602,6 +602,107 @@ bool KernelPatcher::routeMultipleShort(size_t id, RouteRequest *requests, size_t
602602
return routeMultipleInternal(id, requests, num, start, size, kernelRoute, force, JumpType::Short);
603603
}
604604

605+
bool KernelPatcher::findPattern(const void *pattern, const void *patternMask, size_t patternSize, const void *data, size_t dataSize, size_t *dataOffset) {
606+
if (patternSize == 0 || dataSize < patternSize)
607+
return false;
608+
609+
size_t currOffset = *dataOffset;
610+
size_t lastOffset = dataSize - patternSize;
611+
612+
const uint8_t *d = (const uint8_t *) data;
613+
const uint8_t *ptn = (const uint8_t *) pattern;
614+
const uint8_t *ptnMask = (const uint8_t *) patternMask;
615+
616+
if (patternMask == nullptr) {
617+
while (currOffset <= lastOffset) {
618+
size_t i;
619+
for (i = 0; i < patternSize; i++) {
620+
if (d[currOffset + i] != ptn[i])
621+
break;
622+
}
623+
624+
if (i == patternSize) {
625+
*dataOffset = currOffset;
626+
return true;
627+
}
628+
629+
currOffset++;
630+
}
631+
} else {
632+
while (currOffset <= lastOffset) {
633+
size_t i;
634+
for (i = 0; i < patternSize; i++) {
635+
if ((d[currOffset + i] & ptnMask[i]) != ptn[i])
636+
break;
637+
}
638+
639+
if (i == patternSize) {
640+
*dataOffset = currOffset;
641+
return true;
642+
}
643+
644+
currOffset++;
645+
}
646+
}
647+
648+
return false;
649+
}
650+
651+
bool KernelPatcher::findAndReplaceWithMask(void *data, size_t dataSize, const void *find, size_t findSize, const void *findMask, size_t findMaskSize, const void *replace, size_t replaceSize, const void *replaceMask, size_t replaceMaskSize, size_t count, size_t skip) {
652+
if (dataSize < findSize) return false;
653+
654+
uint8_t *d = (uint8_t *) data;
655+
const uint8_t *repl = (const uint8_t *) replace;
656+
const uint8_t *replMsk = (const uint8_t *) replaceMask;
657+
658+
size_t replCount = 0;
659+
size_t dataOffset = 0;
660+
661+
while (true) {
662+
bool found = findPattern(find, findMask, findSize, data, dataSize, &dataOffset);
663+
if (!found) break;
664+
665+
// dataOffset + findSize - 1 is guaranteed to be a valid offset here. As
666+
// dataSize can at most be SIZE_T_MAX, the maximum valid offset is
667+
// SIZE_T_MAX - 1. In consequence, dataOffset + findSize cannot wrap around.
668+
669+
// skip this finding if requested
670+
if (skip > 0) {
671+
skip--;
672+
dataOffset += findSize;
673+
continue;
674+
}
675+
676+
if (UNLIKELY(MachInfo::setKernelWriting(true, KernelPatcher::kernelWriteLock) != KERN_SUCCESS)) {
677+
SYSLOG("patcher", "failed to obtain write permissions for f/r");
678+
return false;
679+
}
680+
681+
// perform replacement
682+
if (replaceMask == nullptr) {
683+
lilu_os_memcpy(&d[dataOffset], replace, replaceSize);
684+
} else {
685+
for (size_t i = 0; i < findSize; i++)
686+
d[dataOffset + i] = (d[dataOffset + i] & ~replMsk[i]) | (repl[i] & replMsk[i]);
687+
}
688+
689+
if (UNLIKELY(MachInfo::setKernelWriting(false, KernelPatcher::kernelWriteLock) != KERN_SUCCESS)) {
690+
SYSLOG("patcher", "failed to restore write permissions for f/r");
691+
}
692+
693+
replCount++;
694+
dataOffset += replaceSize;
695+
696+
// check replace count if requested
697+
if (count > 0) {
698+
count--;
699+
if (count == 0)
700+
break;
701+
}
702+
}
703+
704+
return replCount > 0;
705+
}
605706

606707
bool KernelPatcher::routeMultipleInternal(size_t id, RouteRequest *requests, size_t num, mach_vm_address_t start, size_t size, bool kernelRoute, bool force, JumpType jump) {
607708
bool errorsFound = false;

0 commit comments

Comments
 (0)