Last active
September 8, 2024 19:50
-
-
Save Wowfunhappy/8212f5bea4c601ac9a6297789f232321 to your computer and use it in GitHub Desktop.
KQueueScanContinuePatch
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="UTF-8"?> | |
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | |
<plist version="1.0"> | |
<dict> | |
<key>CFBundleDevelopmentRegion</key> | |
<string>en</string> | |
<key>CFBundleExecutable</key> | |
<string>$(EXECUTABLE_NAME)</string> | |
<key>CFBundleIdentifier</key> | |
<string>wowfunhappy.$(PRODUCT_NAME:rfc1034identifier)</string> | |
<key>CFBundleInfoDictionaryVersion</key> | |
<string>6.0</string> | |
<key>CFBundleName</key> | |
<string>$(PRODUCT_NAME)</string> | |
<key>CFBundlePackageType</key> | |
<string>KEXT</string> | |
<key>CFBundleShortVersionString</key> | |
<string>1.0</string> | |
<key>CFBundleSignature</key> | |
<string>????</string> | |
<key>CFBundleVersion</key> | |
<string>1</string> | |
<key>OSBundleLibraries</key> | |
<dict> | |
<key>com.apple.kpi.iokit</key> | |
<string>10.0.0</string> | |
<key>com.apple.kpi.libkern</key> | |
<string>10.0.0</string> | |
<key>com.apple.kpi.unsupported</key> | |
<string>10.0.0</string> | |
</dict> | |
</dict> | |
</plist> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// KQueueScanContinuePatch.c | |
// KQueueScanContinuePatch | |
// | |
// Created by Wowfunhappy with assistance from krackers. | |
// | |
#include <IOKit/IOLib.h> | |
#include <mach-o/loader.h> | |
#include <i386/proc_reg.h> | |
#define LENGTH(arr) sizeof(arr) / sizeof(*arr) | |
// Copied from github.com/leiless/ksymresolver/blob/master/ksymresolver/ksymresolver.h | |
#define KERN_TEXT_BASE ((vm_offset_t) 0xffffff8000200000ULL) | |
#define CR0_WP 0x00010000 | |
static size_t KASLRAlignment = 0x100000; | |
#if __LP64__ | |
#define NUM_SUPPORTED_KERNELS 5 | |
#else | |
#define NUM_SUPPORTED_KERNELS 1 | |
#endif | |
// Taken from Hopper | |
static vm_offset_t possible_kqueue_scan_continue_panic_start_locations[NUM_SUPPORTED_KERNELS] = { | |
#if __LP64__ | |
0xffffff800053b590, //10.7.5 11G63, xnu-1699.32.7 | |
0xffffff8000557afe, //10.8.4 12F2560, xnu-2050.48.19 | |
0xffffff80005c7a9c, //10.9.5 13F1911, xnu-2422.115.15 | |
0xffffff8000615928, //10.9.5 Bronya-Ryzen | |
0xffffff80005bf9bc, //10.9.5 IPCA | |
#else | |
0x0055bb7e, //10.7.5 11G63, xnu-1699.32.7 (32 bit) | |
#endif | |
}; | |
static vm_offset_t possible_kqueue_scan_continue_panic_end_locations[NUM_SUPPORTED_KERNELS] = { | |
#if __LP64__ | |
0xffffff800053b5a2, //10.7.5 11G63, xnu-1699.32.7 | |
0xffffff8000557b11, //10.8.4 12F2560, xnu-2050.48.19 | |
0xffffff80005c7ab7, //10.9.5 13F1911, xnu-2422.115.15 | |
0xffffff8000615942, //10.9.5 Bronya-Ryzen | |
0xffffff80005bf9d7, //10.9.5 IPCA | |
#else | |
0x0055bb90, //10.7.5 11G63, xnu-1699.32.7 (32 bit) | |
#endif | |
}; | |
static char possible_search_bytes[NUM_SUPPORTED_KERNELS][30] = { | |
#if __LP64__ | |
//10.7.5 11G63, xnu-1699.32.7 | |
{ | |
0x48, 0x8d, 0x3d, 0x69, 0xf4, 0x19, 0x00, //lea rdi,qword [aKeventscancont] | |
0x30, 0xc0, //xor al,al | |
0x89, 0xde, //mov esi,ebx | |
0xe8, 0xa0, 0x4f, 0xce, 0xff, //call _panic | |
0x31, 0xdb, 0x89, //xor ebx,ebx | |
0xda, 0x49, 0x8b, 0xb7, 0xc0, 0x00, 0x00, 0x00, 0x4c, 0x89, 0xf7, | |
}, | |
//10.8.4 12F2560, xnu-2050.48.19 | |
{ | |
0x48, 0x8d, 0x3d, 0x77, 0xe9, 0x19, 0x00, //lea rdi,qword [aKeventscancont] | |
0x89, 0xde, //mov esi,ebx | |
0x30, 0xc0, //xor al,al | |
0xe8, 0x02, 0x5b, 0xcc, 0xff, //call _panic | |
0x45, 0x31, 0xed, //xor r13d,r13d | |
0x49, 0x8b, 0xb6, 0xc0, 0x00, 0x00, 0x00, 0x4c, 0x89, 0xff, 0x44, | |
}, | |
//10.9.5 13F1911, xnu-2422.115.15 | |
{ | |
0x48, 0x8d, 0x3d, 0xbb, 0xf3, 0x19, 0x00, //lea rdi,qword | |
0x48, 0x8d, 0x35, 0x11, 0xf4, 0x19, 0x00, //lea rsi,qword | |
0x44, 0x89, 0xfa, //mov edx,r15d | |
0x30, 0xc0, //xor al,al | |
0xe8, 0xbc, 0xb5, 0xc5, 0xff, //call _panic | |
0x45, 0x31, 0xe4, //xor r12d,r12d | |
0x49, 0x8b, 0xb5, | |
}, | |
//10.9.5 Bronya-Ryzen | |
{ | |
0x48, 0x8d, 0x3d, 0xbb, 0xf3, 0x19, 0x00, //lea rdi,qword | |
0x48, 0x8d, 0x35, 0x11, 0xf4, 0x19, 0x00, //lea rsi,qword | |
0x44, 0x89, 0xfa, //mov edx,r15d | |
0x30, 0xc0, //xor al,al | |
0xe8, 0xbc, 0xb5, 0xc5, 0xff, //call _panic | |
0x49, 0x8b, 0x47, 0x70, 0x49, 0x8b, | |
}, | |
//10.9.5 IPCA | |
{ | |
0x48, 0x8d, 0x3d, 0x7c, 0x08, 0x1a, 0x00, //lea rdi,qword [aSInvalidWaitre] | |
0x48, 0x8d, 0x35, 0xdd, 0x08, 0x1a, 0x00, //lea rsi, qword [aKqueuescancont] | |
0x44, 0x89, 0xfa, //mov edx,r15d | |
0x30, 0xc0, //xor al,al | |
0xe8, 0xdc, 0x34, 0xc6, 0xff, //call _panic | |
0x45, 0x31, 0xe4, //xor r12d, r12d | |
0x49, 0x8b, 0xb5, | |
}, | |
#else | |
//10.7.5 11G63, xnu-1699.32.7 (32 bit) | |
{ | |
0x89, 0x4c, 0x24, 0x04, //mov dword[esp+0x28+var_24],ecx | |
0xc7, 0x04, 0x24, 0xa4, 0x06, 0x70, 0x00, //mov dword[esp+0x28+var_28],aKeventscancont | |
0xe8, 0x32, 0x46, 0xcc, 0xff, //call _panic | |
0x31, 0xf6, //xor esi,esi | |
0x8b, 0x45, 0xec, 0x8b, 0x88, 0x9c, 0x00, 0x00, 0x00, 0x89, 0x74, 0x24, | |
}, | |
#endif | |
}; | |
static char possible_replacement_bytes[NUM_SUPPORTED_KERNELS][7] = { | |
#if __LP64__ | |
{0x48, 0xc7, 0xc3, 0x09, 0x00, 0x00, 0x00}, // mov rbx,0x9 | 10.7.5 11G63, xnu-1699.32.7 | |
{0x41, 0xbd, 0x09, 0x00, 0x00, 0x00, 0x90}, // mov r13d,0x9 | 10.8.4 12F2560, xnu-2050.48.19 | |
{0x41, 0xbc, 0x09, 0x00, 0x00, 0x00, 0x90}, // mov r12d,0x9 | 10.9.5 13F1911, xnu-2422.115.15 | |
{0x41, 0xbd, 0x09, 0x00, 0x00, 0x00, 0x90}, // mov r13d,0x9 | 10.9.5 Bronya-Ryzen | |
{0x41, 0xbc, 0x09, 0x00, 0x00, 0x00, 0x90}, // mov r12d,0x9 | 10.9.5 IPCA | |
#else | |
{0xbe, 0x09, 0x00, 0x00, 0x00, 0x90, 0x90}, // mov esi,0x9 | 10.7.5 11G63, xnu-1699.32.7 (32 bit) | |
#endif | |
}; | |
// Adapted from github.com/acidanthera/Lilu/blob/137b4d9deb7022bb97fa9899303934534ff20ec7/Lilu/Sources/kern_mach.cpp | |
static vm_offset_t get_kernel_base() { | |
#if __LP64__ | |
// The function choice is mostly arbitrary, but IOLog frequently has a low address. | |
vm_offset_t tmp = (vm_offset_t)(IOLog); | |
// Align the address | |
tmp &= ~(KASLRAlignment - 1); | |
// Search backwards for the kernel base address (mach-o header) | |
while (tmp >= KASLRAlignment) { | |
if (*(uint32_t *)(tmp) == MH_MAGIC_64) { | |
// make sure it's the header and not some reference to the MAGIC number | |
struct segment_command_64 segmentCommand = *(struct segment_command_64 *)(tmp + sizeof(struct mach_header_64)); | |
if (!strncmp(segmentCommand.segname, "__TEXT", sizeof(segmentCommand.segname))) { | |
printf("KQueueScanContinuePatch: found kernel mach-o header address at %lx\n", tmp); | |
break; | |
} | |
} | |
tmp -= KASLRAlignment; | |
} | |
return tmp - KERN_TEXT_BASE; | |
#else | |
// No 32-bit XNU kernels have KASLR | |
return 0; | |
#endif | |
} | |
boolean_t write_protection_is_enabled() { | |
return (get_cr0() & CR0_WP) != 0; | |
} | |
kern_return_t KQueueScanContinuePatch_start(kmod_info_t * ki, void *d) | |
{ | |
printf("KQueueScanContinuePatch START\n"); | |
vm_offset_t kernel_base = get_kernel_base(); | |
vm_offset_t kqueue_scan_continue_panic_start_location = 0; | |
vm_offset_t kqueue_scan_continue_panic_end_location = 0; | |
char search_bytes[sizeof(possible_search_bytes[0])]; | |
char replacement_bytes[sizeof(possible_replacement_bytes[0])]; | |
uint8_t *kscpb = NULL; | |
for (int i = 0; i < LENGTH(possible_kqueue_scan_continue_panic_start_locations); i++) { | |
kqueue_scan_continue_panic_start_location = kernel_base + possible_kqueue_scan_continue_panic_start_locations[i]; | |
kqueue_scan_continue_panic_end_location = kernel_base + possible_kqueue_scan_continue_panic_end_locations[i]; | |
memcpy(search_bytes, possible_search_bytes[i], sizeof(search_bytes)); | |
memcpy(replacement_bytes, possible_replacement_bytes[i], sizeof(replacement_bytes)); | |
kscpb = (uint8_t*) kqueue_scan_continue_panic_start_location; | |
if (memcmp(kscpb, search_bytes, sizeof(search_bytes)) == 0) { | |
break; | |
} | |
if (i == LENGTH(possible_kqueue_scan_continue_panic_start_locations) - 1) { | |
printf("KQueueScanContinuePatch: Memory region not found. You are probably using an unsupported kernel, or your kernel has already been patched.\n"); | |
return KERN_FAILURE; | |
} | |
} | |
printf("KQueueScanContinuePatch: Pre-Patch: Bytes at kqueue_scan_continue panic location: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", kscpb[0], kscpb[1], kscpb[2], kscpb[3], kscpb[4], kscpb[5], kscpb[6], kscpb[7], kscpb[8], kscpb[9], kscpb[10], kscpb[11], kscpb[12], kscpb[13], kscpb[14], kscpb[15], kscpb[16], kscpb[17], kscpb[18], kscpb[19], kscpb[20], kscpb[21], kscpb[22], kscpb[23], kscpb[24], kscpb[25], kscpb[26], kscpb[27], kscpb[28], kscpb[29], kscpb[30], kscpb[31], kscpb[32], kscpb[33], kscpb[34], kscpb[35], kscpb[36], kscpb[37], kscpb[38], kscpb[39]); | |
unsigned long extra_space_to_fill = kqueue_scan_continue_panic_end_location - kqueue_scan_continue_panic_start_location - sizeof(replacement_bytes); | |
if (kqueue_scan_continue_panic_start_location + sizeof(replacement_bytes) + extra_space_to_fill != kqueue_scan_continue_panic_end_location) { | |
printf("kqueue_scan_continue_panic_start_location + sizeof(replacement_bytes) + extra_space_to_fill != kqueue_scan_continue_panic_end_location\n"); | |
return KERN_FAILURE; | |
} | |
boolean_t interrupts_were_enabled = ml_get_interrupts_enabled(); | |
if (interrupts_were_enabled) { | |
ml_set_interrupts_enabled(false); | |
if (! ml_get_interrupts_enabled()) { | |
printf("KQueueScanContinuePatch: Disabled interrupts\n"); | |
} else { | |
printf("KQueueScanContinuePatch: Failed to disable interrupts\n"); | |
return KERN_FAILURE; | |
} | |
} | |
boolean_t write_protection_was_enabled = write_protection_is_enabled(); | |
if (write_protection_was_enabled) { | |
set_cr0(get_cr0() & ~CR0_WP); // disable write protection | |
if (!write_protection_is_enabled()) { | |
printf("KQueueScanContinuePatch: Disabled write protection\n"); | |
} else { | |
printf("KQueueScanContinuePatch: Failed to disable write protection\n"); | |
//Re-enable interrupts before exiting. | |
if (interrupts_were_enabled && !ml_get_interrupts_enabled()) { | |
ml_set_interrupts_enabled(true); | |
if (ml_get_interrupts_enabled()) { | |
printf("KQueueScanContinuePatch: Re-enabled interrupts after failing to disable write protection.\n"); | |
} else { | |
panic("KQueueScanContinuePatch: Failed to re-enable interrupts after failing to disable write protection!\n"); | |
} | |
} | |
return KERN_FAILURE; | |
} | |
} | |
//commence memory rewriting | |
memcpy((void *)kqueue_scan_continue_panic_start_location, replacement_bytes, sizeof(replacement_bytes)); | |
memset((void *)kqueue_scan_continue_panic_start_location + sizeof(replacement_bytes), 0x90 /*nop*/, extra_space_to_fill); | |
printf("KQueueScanContinuePatch: Memory rewritten\n"); | |
//conclude memory rewriting | |
if (write_protection_was_enabled && !write_protection_is_enabled()) { | |
set_cr0(get_cr0() | CR0_WP); // re-enable write protection | |
if (write_protection_is_enabled()) { | |
printf("KQueueScanContinuePatch: Re-enabled write protection\n"); | |
} else { | |
panic("KQueueScanContinuePatch: failed to re-enable write protection!\n"); | |
} | |
} | |
if (interrupts_were_enabled && !ml_get_interrupts_enabled()) { | |
ml_set_interrupts_enabled(true); | |
if (ml_get_interrupts_enabled()) { | |
printf("KQueueScanContinuePatch: Re-enabled interrupts\n"); | |
} else { | |
panic("KQueueScanContinuePatch: Failed to re-enable interrupts!\n"); | |
} | |
} | |
printf("KQueueScanContinuePatch: Post-Patch: Bytes at kqueue_scan_continue panic location: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", kscpb[0], kscpb[1], kscpb[2], kscpb[3], kscpb[4], kscpb[5], kscpb[6], kscpb[7], kscpb[8], kscpb[9], kscpb[10], kscpb[11], kscpb[12], kscpb[13], kscpb[14], kscpb[15], kscpb[16], kscpb[17], kscpb[18], kscpb[19], kscpb[20], kscpb[21], kscpb[22], kscpb[23], kscpb[24], kscpb[25], kscpb[26], kscpb[27], kscpb[28], kscpb[29], kscpb[30], kscpb[31], kscpb[32], kscpb[33], kscpb[34], kscpb[35], kscpb[36], kscpb[37], kscpb[38], kscpb[39]); | |
return KERN_SUCCESS; | |
} | |
kern_return_t KQueueScanContinuePatch_stop(kmod_info_t *ki, void *d) | |
{ | |
printf("KQueueScanContinuePatch STOP\n"); | |
return KERN_SUCCESS; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="UTF-8"?> | |
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | |
<plist version="1.0"> | |
<dict> | |
<key>Label</key> | |
<string>wowfunhappy.KQueueScanContinuePatch-loader</string> | |
<key>ProgramArguments</key> | |
<array> | |
<string>/bin/sh</string> | |
<string>-c</string> | |
<string>/bin/cp -R /Library/Extensions/KQueueScanContinuePatch.kext /tmp/ && /sbin/kextload /tmp/KQueueScanContinuePatch.kext ; /bin/rm -r /tmp/KQueueScanContinuePatch.kext</string> | |
</array> | |
<key>RunAtLoad</key> | |
<true/> | |
</dict> | |
</plist> |
RJVB
commented
Feb 19, 2023
via email
Actually osx docs say kqueue fd isn't even inherited by child processes
Which isn't a problem because we were talking about threads ;)
When I evoked stability after patching the unimplemented case handling (EBADF instead of panic) I was thinking of the times I tried to replace an abort in userland code with a sensible return. Sometimes that worked (trivially so even), sometimes it led to issues down the line that would have required rewriting quite a bit of code.
...you know, there was that one report of odd stuff happening after the kqueue crash:
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment