From 7ecf020e69a0f35b539b43a09b70c2bca24a5735 Mon Sep 17 00:00:00 2001 From: htrowii Date: Mon, 15 Jul 2024 20:34:47 +0800 Subject: [PATCH] feat: MediaRemoteUI support, cleanup csopshook for springboard --- Makefile | 12 +- RootHelperSample/Makefile | 16 +- .../project.pbxproj | 4 + RootHelperSample/TSUtil.m | 2 +- RootHelperSample/exepatch.c | 630 ++++++++++++++++++ RootHelperSample/exepatch.h | 22 + .../launchdshim/SpringBoardShim/Makefile | 4 +- .../SpringBoardShim/SpringBoardEnts.plist | 2 + .../launchdshim/SpringBoardShim/build.sh | 7 +- .../launchdshim/SpringBoardShim/fishhook.c | 277 ++++++++ .../launchdshim/SpringBoardShim/fishhook.h | 76 +++ .../launchdshim/SpringBoardShim/main.c | 14 - .../launchdshim/SpringBoardShim/main.m | 168 +++++ .../springboardshimsignedinjected | Bin 153149 -> 173245 bytes .../launchdshim/SpringBoardShim/utils.h | 20 + .../launchdshim/SpringBoardShim/utils.m | 138 ++++ .../launchdshim/generalhook/LICENCE | 21 + .../launchdshim/generalhook/Makefile | 16 + .../launchdshim/generalhook/README.md | 3 + .../launchdshim/generalhook/build.sh | 2 + .../launchdshim/generalhook/control | 9 + .../generalhook/entitlements.plist | 20 + .../launchdshim/generalhook/fishhook.c | 277 ++++++++ .../launchdshim/generalhook/fishhook.h | 76 +++ .../launchdshim/generalhook/main.m | 186 ++++++ .../launchdshim/generalhook/utils.h | 20 + .../launchdshim/generalhook/utils.m | 138 ++++ .../launchdshim/generalhookents.plist | 231 +++++++ .../launchdshim/launchdhook/main.m | 50 +- RootHelperSample/main.m | 176 +++-- Serotonin.xcodeproj/project.pbxproj | 4 + .../xcshareddata/swiftpm/Package.resolved | 23 - .../UI/Tabs/JailbreakViewController.swift | 8 +- usprebooter/UI/Tabs/ToolbarButton.swift | 1 + usprebooter/fun/offsets.h | 2 +- usprebooter/fun/offsets.m | 2 +- usprebooter/fun/vnode.m | 5 +- usprebooter/overwriter.m | 2 +- usprebooter/troller.m | 3 +- 39 files changed, 2511 insertions(+), 156 deletions(-) create mode 100644 RootHelperSample/exepatch.c create mode 100644 RootHelperSample/exepatch.h create mode 100644 RootHelperSample/launchdshim/SpringBoardShim/fishhook.c create mode 100644 RootHelperSample/launchdshim/SpringBoardShim/fishhook.h delete mode 100644 RootHelperSample/launchdshim/SpringBoardShim/main.c create mode 100644 RootHelperSample/launchdshim/SpringBoardShim/main.m create mode 100644 RootHelperSample/launchdshim/SpringBoardShim/utils.h create mode 100644 RootHelperSample/launchdshim/SpringBoardShim/utils.m create mode 100644 RootHelperSample/launchdshim/generalhook/LICENCE create mode 100644 RootHelperSample/launchdshim/generalhook/Makefile create mode 100644 RootHelperSample/launchdshim/generalhook/README.md create mode 100755 RootHelperSample/launchdshim/generalhook/build.sh create mode 100644 RootHelperSample/launchdshim/generalhook/control create mode 100644 RootHelperSample/launchdshim/generalhook/entitlements.plist create mode 100644 RootHelperSample/launchdshim/generalhook/fishhook.c create mode 100644 RootHelperSample/launchdshim/generalhook/fishhook.h create mode 100644 RootHelperSample/launchdshim/generalhook/main.m create mode 100644 RootHelperSample/launchdshim/generalhook/utils.h create mode 100644 RootHelperSample/launchdshim/generalhook/utils.m create mode 100644 RootHelperSample/launchdshim/generalhookents.plist delete mode 100644 Serotonin.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved diff --git a/Makefile b/Makefile index 0c12d875..ca88b422 100644 --- a/Makefile +++ b/Makefile @@ -30,10 +30,15 @@ Serotonin.tipa: $(wildcard **/*.c **/*.m **/*.swift **/*.plist **/*.xml) echo "[*] Signing SB hook" ./ChOma_host/output/tests/ct_bypass -i RootHelperSample/launchdshim/SpringBoardShim/SpringBoardHook/.theos/obj/debug/SpringBoardHook.dylib -r -o RootHelperSample/launchdshim/SpringBoardShim/SpringBoardHook/springboardhooksigned.dylib + echo "[*] Building general hook" + $(MAKE) -C RootHelperSample/launchdshim/generalhook + + echo "[*] Signing general hook" + ./ChOma_host/output/tests/ct_bypass -i RootHelperSample/launchdshim/generalhook/.theos/obj/debug/generalhook.dylib -r -o RootHelperSample/launchdshim/generalhook/generalhook.dylib + echo "[*] Building hideconfidentiatext" $(MAKE) -C RootHelperSample/launchdshim/hideConfidentialText/ - echo "[*] Signing hideconfidentialtext" ./ChOma_host/output/tests/ct_bypass -i RootHelperSample/launchdshim/hideConfidentialText/.theos/obj/debug/hideConfidentialText.dylib -r -o RootHelperSample/launchdshim/SpringBoardShim/SpringBoardHook/hideConfidentialText.dylib @@ -51,12 +56,13 @@ Serotonin.tipa: $(wildcard **/*.c **/*.m **/*.swift **/*.plist **/*.xml) mkdir Payload cp -a build/Build/Products/Release-iphoneos/Serotonin.app Payload rm -rf Payload/Serotonin.app/Frameworks - cp RootHelperSample/.theos/obj/debug/arm64/trolltoolsroothelper Payload/Serotonin.app/trolltoolsroothelper + cp RootHelperSample/.theos/obj/debug/arm64/serotoninroothelper Payload/Serotonin.app/serotoninroothelper install -m755 RootHelperSample/launchdshim/launchdhook/launchdhooksigned.dylib Payload/Serotonin.app/launchdhooksigned.dylib install -m755 RootHelperSample/launchdshim/SpringBoardShim/SpringBoardHook/springboardhooksigned.dylib Payload/Serotonin.app/springboardhooksigned.dylib + install -m755 RootHelperSample/launchdshim/generalhook/generalhook.dylib Payload/Serotonin.app/generalhooksigned.dylib install -m755 RootHelperSample/launchdshim/hideConfidentialText/.theos/obj/debug/hideConfidentialText.dylib Payload/Serotonin.app/hideconfidentialtext.dylib cp RootHelperSample/launchdshim/hideConfidentialText/hideconfidentialtext.plist Payload/Serotonin.app/hideconfidentialtext.plist - $(LDID) -S./RootHelperSample/entitlements.plist -Cadhoc Payload/Serotonin.app/{fastPathSign,ldid,trolltoolsroothelper} + $(LDID) -S./RootHelperSample/entitlements.plist -Cadhoc Payload/Serotonin.app/{fastPathSign,ldid,serotoninroothelper} $(LDID) -Sent.plist -Cadhoc Payload/Serotonin.app/Serotonin zip -vr9 Serotonin.tipa Payload/ -x "*.DS_Store" diff --git a/RootHelperSample/Makefile b/RootHelperSample/Makefile index 87f8b373..3e20a052 100644 --- a/RootHelperSample/Makefile +++ b/RootHelperSample/Makefile @@ -3,14 +3,14 @@ ARCHS = arm64 include $(THEOS)/makefiles/common.mk -TOOL_NAME = trolltoolsroothelper +TOOL_NAME = serotoninroothelper -trolltoolsroothelper_FILES = $(wildcard *.m) Exploits/fastPathSign/src/coretrust_bug.c Exploits/fastPathSign/src/codesign.m -trolltoolsroothelper_LDFLAGS = -Lexternal/lib -lcrypto -lchoma -trolltoolsroothelper_CFLAGS = -fobjc-arc $(shell pkg-config --cflags libcrypto) -Iexternal/include -Wmissing-braces -IExploits/fastPathSign/src -trolltoolsroothelper_CODESIGN_FLAGS = -Sentitlements.plist -trolltoolsroothelper_INSTALL_PATH = /usr/local/bin -trolltoolsroothelper_LIBRARIES = archive -trolltoolsroothelper_PRIVATE_FRAMEWORKS = SpringBoardServices BackBoardServices MobileCoreServices MobileContainerManager IOKit +$(TOOL_NAME)_FILES = $(wildcard *.m) $(wildcard *.c) Exploits/fastPathSign/src/coretrust_bug.c Exploits/fastPathSign/src/codesign.m +$(TOOL_NAME)_LDFLAGS = -Lexternal/lib -lcrypto -lchoma +$(TOOL_NAME)_CFLAGS = -fobjc-arc $(shell pkg-config --cflags libcrypto) -Iexternal/include -Wno-error -IExploits/fastPathSign/src +$(TOOL_NAME)_CODESIGN_FLAGS = -Sentitlements.plist +$(TOOL_NAME)_INSTALL_PATH = /usr/local/bin +$(TOOL_NAME)_LIBRARIES = archive +$(TOOL_NAME)_PRIVATE_FRAMEWORKS = SpringBoardServices BackBoardServices MobileCoreServices MobileContainerManager IOKit include $(THEOS_MAKE_PATH)/tool.mk diff --git a/RootHelperSample/RootHelperSample.xcodeproj/project.pbxproj b/RootHelperSample/RootHelperSample.xcodeproj/project.pbxproj index 4c0641c9..161269ec 100644 --- a/RootHelperSample/RootHelperSample.xcodeproj/project.pbxproj +++ b/RootHelperSample/RootHelperSample.xcodeproj/project.pbxproj @@ -19,12 +19,16 @@ C82AFF042B1762CD0070EA49 /* CoreServices.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CoreServices.h; sourceTree = ""; }; C82AFF052B1762CD0070EA49 /* RemoteLog.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RemoteLog.h; sourceTree = ""; }; C82AFF062B1762CD0070EA49 /* control */ = {isa = PBXFileReference; lastKnownFileType = text; path = control; sourceTree = ""; }; + C870DFE02C42EFA2003A17A5 /* exepatch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = exepatch.h; sourceTree = ""; }; + C870DFE12C42EFA2003A17A5 /* exepatch.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = exepatch.c; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXGroup section */ C82AFEF52B1762CD0070EA49 = { isa = PBXGroup; children = ( + C870DFE12C42EFA2003A17A5 /* exepatch.c */, + C870DFE02C42EFA2003A17A5 /* exepatch.h */, C82AFEFB2B1762CD0070EA49 /* .DS_Store */, C82AFEFC2B1762CD0070EA49 /* uicache.h */, C82AFEFD2B1762CD0070EA49 /* .theos */, diff --git a/RootHelperSample/TSUtil.m b/RootHelperSample/TSUtil.m index d3bf96ac..99efd8ee 100644 --- a/RootHelperSample/TSUtil.m +++ b/RootHelperSample/TSUtil.m @@ -40,7 +40,7 @@ void loadMCMFramework(void) #else NSString* rootHelperPath(void) { - return [[NSBundle mainBundle].bundlePath stringByAppendingPathComponent:@"trolltoolsroothelper"]; + return [[NSBundle mainBundle].bundlePath stringByAppendingPathComponent:@"serotoninroothelper"]; } #endif diff --git a/RootHelperSample/exepatch.c b/RootHelperSample/exepatch.c new file mode 100644 index 00000000..2a1267cc --- /dev/null +++ b/RootHelperSample/exepatch.c @@ -0,0 +1,630 @@ + +#include "exepatch.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SYSLOG(...) // do {printf(__VA_ARGS__);printf("\n");} while(0) + +#define BOOTSTRAP_INSTALL_NAME "@loader_path/generalhooksigned.dylib" + +extern void abort(void); //??? +static size_t write_uleb128(uint64_t val, uint8_t buf[10]) +{ + uint8_t* start=buf; + unsigned char c; + bool flag; + do { + c = val & 0x7f; + val >>= 7; + flag = val != 0; + *buf++ = c | (flag ? 0x80 : 0); + } while (flag); + return buf-start; +} +static size_t write_sleb128(uint64_t val, uint8_t buf[10]) +{ + uint8_t* start=buf; + unsigned char c; + bool flag; + do { + c = val & 0x7f; + val >>= 7; + flag = c & 0x40 ? val != -1 : val != 0; + *buf++ = c | (flag ? 0x80 : 0); + } while (flag); + return buf-start; +} +static uint64_t read_uleb128(uint8_t** pp, uint8_t* end) +{ + uint8_t* p = *pp; + uint64_t result = 0; + int bit = 0; + do { + if ( p == end ) { + abort(); + break; + } + uint64_t slice = *p & 0x7f; + + if ( bit > 63 ) { + abort(); + break; + } + else { + result |= (slice << bit); + bit += 7; + } + } + while (*p++ & 0x80); + *pp = p; + return result; +} +static int64_t read_sleb128(uint8_t** pp, uint8_t* end) +{ + uint8_t* p = *pp; + int64_t result = 0; + int bit = 0; + uint8_t byte = 0; + do { + if ( p == end ) { + abort(); + break; + } + byte = *p++; + result |= (((int64_t)(byte & 0x7f)) << bit); + bit += 7; + } while (byte & 0x80); + *pp = p; + // sign extend negative numbers + if ( ((byte & 0x40) != 0) && (bit < 64) ) + result |= (~0ULL) << bit; + return result; +} + +char* BindCodeDesc[] = +{ +"BIND_OPCODE_DONE", // 0x00 +"BIND_OPCODE_SET_DYLIB_ORDINAL_IMM", // 0x10 +"BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB", // 0x20 +"BIND_OPCODE_SET_DYLIB_SPECIAL_IMM", // 0x30 +"BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM", // 0x40 +"BIND_OPCODE_SET_TYPE_IMM", // 0x50 +"BIND_OPCODE_SET_ADDEND_SLEB", // 0x60 +"BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB", // 0x70 +"BIND_OPCODE_ADD_ADDR_ULEB", // 0x80 +"BIND_OPCODE_DO_BIND", // 0x90 +"BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB", // 0xA0 +"BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED", // 0xB0 +"BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB", // 0xC0 +"BIND_OPCODE_THREADED", // 0xD0 +}; + +enum bindtype { + bindtype_bind, + bindtype_lazy, + bindtype_weak +}; + +#define rebuild(p, copysize, resized) {\ +newbind = realloc(newbind, newsize+copysize);\ +memcpy((void*)((uint64_t)newbind+newsize), p, copysize);\ +newsize += copysize;\ +copied=true;\ +if(resized) rebuilt=true;\ +} + +void* rebind(struct mach_header_64* header, enum bindtype type, void* data, uint32_t* size) +{ + bool rebuilt=false; + void* newbind = NULL; + size_t newsize = 0; + + uint8_t* p = (uint8_t*)data; + uint8_t* end = (uint8_t*)((uint64_t)data + *size); + bool stop=false; + int i=0; + while ( !stop && (p < end) ) + { + bool copied=false; + uint8_t immediate = *p & BIND_IMMEDIATE_MASK; + uint8_t opcode = *p & BIND_OPCODE_MASK; + uint8_t* curp = p++; + static char* bindtypedesc[] = {"bind","lazy","weak"}; + SYSLOG("[%s][%d] %02X %s %02X", bindtypedesc[type], i++, opcode, BindCodeDesc[opcode>>4], immediate); + switch (opcode) { + case BIND_OPCODE_DONE: + if(type!=bindtype_lazy) stop = true; + break; + case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM: + { + assert(type != bindtype_weak); + int libraryOrdinal = (int)immediate; + SYSLOG("=%d", libraryOrdinal); + if(libraryOrdinal > 0) { + SYSLOG("rebind -> %d", libraryOrdinal+1); + if(libraryOrdinal 0) { + SYSLOG("rebind -> %d", libraryOrdinal+1); + uint8_t ordinal[10]; + int newlen = write_uleb128(libraryOrdinal+1, ordinal); + if(newlen==(p-oldp)) { + memcpy(oldp, ordinal, newlen); + } else { + rebuild(curp, 1, false); + rebuild(ordinal, newlen, true); + } + } + } + break; + + case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM: + assert(type != bindtype_weak); + break; + case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM: + ++i; + while (*p != '\0') + ++p; + ++p; + break; + case BIND_OPCODE_SET_TYPE_IMM: + assert(type != bindtype_lazy); + break; + case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB: + ++i; + read_uleb128(&p, end); + break; + case BIND_OPCODE_SET_ADDEND_SLEB: + ++i; + read_sleb128(&p, end); + break; + case BIND_OPCODE_DO_BIND: + break; + case BIND_OPCODE_THREADED: + switch (immediate) { + case BIND_SUBOPCODE_THREADED_SET_BIND_ORDINAL_TABLE_SIZE_ULEB: + { + ++i; + uint64_t targetTableCount = read_uleb128(&p, end); + assert (!( targetTableCount > 65535 )); + } + break; + case BIND_SUBOPCODE_THREADED_APPLY: + break; + default: + abort(); + } + break; + case BIND_OPCODE_ADD_ADDR_ULEB: + case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB: + assert(type != bindtype_lazy); + read_uleb128(&p, end); + ++i; + break; + case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED: + assert(type != bindtype_lazy); + break; + case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB: + assert(type != bindtype_lazy); + read_uleb128(&p, end); + ++i; + read_uleb128(&p, end); + ++i; + break; + default: + abort(); + } + + if(!copied) rebuild(curp, p-curp, false); + } + + if(rebuilt) { + *size = newsize; + return newbind; + } + + if(newbind) free(newbind); + return NULL; +} + +int patch_macho(int fd, struct mach_header_64* header) +{ + int libOrdinal=1; + int prelibOrdinal=0; + int first_sec_off = 0; + struct segment_command_64* linkedit_seg = NULL; + struct symtab_command* symtab = NULL; + struct dysymtab_command* dysymtab = NULL; + struct linkedit_data_command* fixup = NULL; + struct dylib_command* first_dylib = NULL; + struct dyld_info_command* dyld_info = NULL; + struct linkedit_data_command* code_sign = NULL; + + struct load_command* lc = (struct load_command*)((uint64_t)header + sizeof(*header)); + for (int i = 0; i < header->ncmds; i++) { + + switch(lc->cmd) { + + case LC_LOAD_DYLIB: + case LC_LOAD_WEAK_DYLIB: + case LC_REEXPORT_DYLIB: + case LC_LOAD_UPWARD_DYLIB: + { + if(!first_dylib) first_dylib = (struct dylib_command*)lc; + + struct dylib_command* idcmd = (struct dylib_command*)lc; + char* name = (char*)((uint64_t)idcmd + idcmd->dylib.name.offset); + SYSLOG("libOrdinal=%d, %s\n", libOrdinal, name); + + if(strcmp(name, BOOTSTRAP_INSTALL_NAME)==0) { + SYSLOG("bootstrap library exists @ %d!\n", libOrdinal); + prelibOrdinal = libOrdinal; + } + + libOrdinal++; + break; + } + + case LC_SYMTAB: { + symtab = (struct symtab_command*)lc; + SYSLOG("symtab offset=%x count=%d strtab offset=%x size=%x\n", symtab->symoff, symtab->nsyms, symtab->stroff, symtab->strsize); + + break; + } + + case LC_DYSYMTAB: { + dysymtab = (struct dysymtab_command*)lc; + SYSLOG("dysymtab export_index=%d count=%d, import_index=%d count=%d, \n", dysymtab->iextdefsym, dysymtab->nextdefsym, dysymtab->iundefsym, dysymtab->nundefsym); + + break; + } + + case LC_SEGMENT_64: { + struct segment_command_64 * seg = (struct segment_command_64 *) lc; + + SYSLOG("segment: %s file=%llx:%llx vm=%16llx:%16llx\n", seg->segname, seg->fileoff, seg->filesize, seg->vmaddr, seg->vmsize); + + if(strcmp(seg->segname,SEG_LINKEDIT)==0) + linkedit_seg = seg; + + struct section_64* sec = (struct section_64*)((uint64_t)seg+sizeof(*seg)); + for(int j=0; jnsects; j++) + { + SYSLOG("section[%d] = %s/%s offset=%x vm=%16llx:%16llx\n", j, sec[j].segname, sec[j].sectname, + sec[j].offset, sec[j].addr, sec[j].size); + + if(sec[j].offset && (first_sec_off==0 || first_sec_off>sec[j].offset)) { + SYSLOG("first_sec_off %x => %x\n", first_sec_off, sec[j].offset); + first_sec_off = sec[j].offset; + } + } + break; + } + + case LC_DYLD_CHAINED_FIXUPS: { + fixup = (struct linkedit_data_command*)lc; + break; + } + + case LC_DYLD_INFO: + case LC_DYLD_INFO_ONLY: + assert(dyld_info==NULL); + dyld_info = (struct dyld_info_command*)lc; + break; + + case LC_CODE_SIGNATURE: + code_sign = (struct linkedit_data_command*)lc; + break; + } + + ///////// + lc = (struct load_command *) ((char *)lc + lc->cmdsize); + } + + if(prelibOrdinal > 0) { + //keep old way, assert(prelibOrdinal == 1); + return 0; + } + + struct stat st; + assert(fstat(fd, &st)==0); + assert(st.st_size == (linkedit_seg->fileoff+linkedit_seg->filesize)); + + int addsize = sizeof(struct dylib_command) + strlen(BOOTSTRAP_INSTALL_NAME) + 1; + if(addsize%sizeof(void*)) addsize = (addsize/sizeof(void*) + 1) * sizeof(void*); //align + if(first_sec_off < (sizeof(*header)+header->sizeofcmds+addsize)) + { + fprintf(stderr, "mach-o header has no enough space!\n"); + return -1; + } + + + + uint32_t* itab = (uint32_t*)( (uint64_t)header + dysymtab->indirectsymoff); + for(int i=0; inindirectsyms; i++) { + SYSLOG("indirect sym[%d] %d\n", i, itab[i]); + } + + struct nlist_64* symbols64 = (struct nlist_64*)( (uint64_t)header + symtab->symoff); + for(int i=0; insyms; i++) { + char* symstr = (char*)( (uint64_t)header + symtab->stroff + symbols64[i].n_un.n_strx); + SYSLOG("sym[%d] type:%02x sect:%02x desc:%04x value:%llx \tstr:%x\t%s\n", i, symbols64[i].n_type, symbols64[i].n_sect, symbols64[i].n_desc, symbols64[i].n_value, symbols64[i].n_un.n_strx, symstr); + + if(i>=dysymtab->iundefsym && i<(dysymtab->iundefsym+dysymtab->nundefsym)) + { + uint16_t n_desc = symbols64[i].n_desc; + uint8_t n_type = symbols64[i].n_type; + + int ordinal= GET_LIBRARY_ORDINAL(n_desc); + //assert(ordinal > 0); ordinal=0:BIND_SPECIAL_DYLIB_SELF + + // Handle defined weak def symbols which need to get a special ordinal + if ( ((n_type & N_TYPE) == N_SECT) && ((n_type & N_EXT) != 0) && ((n_desc & N_WEAK_DEF) != 0) ) + ordinal = BIND_SPECIAL_DYLIB_WEAK_LOOKUP; + + if(ordinal > 0) SET_LIBRARY_ORDINAL(symbols64[i].n_desc, ordinal+1); + } + } + + if(fixup) + { + struct dyld_chained_fixups_header* chainsHeader = (struct dyld_chained_fixups_header*)((uint64_t)header + fixup->dataoff); + assert(chainsHeader->fixups_version == 0); + assert(chainsHeader->symbols_format == 0); + SYSLOG("import format=%d offset=%x count=%d\n", chainsHeader->imports_format, chainsHeader->imports_offset, + chainsHeader->imports_count); + + struct dyld_chained_import* imports; + struct dyld_chained_import_addend* importsA32; + struct dyld_chained_import_addend64* importsA64; + char* symbolsPool = (char*)chainsHeader + chainsHeader->symbols_offset; + int libOrdinal; + switch (chainsHeader->imports_format) { + case DYLD_CHAINED_IMPORT: + imports = (struct dyld_chained_import*)((uint8_t*)chainsHeader + chainsHeader->imports_offset); + for (uint32_t i=0; i < chainsHeader->imports_count; ++i) { + char* symbolName = &symbolsPool[imports[i].name_offset]; + uint8_t libVal = imports[i].lib_ordinal; + if ( libVal > 0xF0 ) + libOrdinal = (int8_t)libVal; + else + libOrdinal = libVal; + + /* c++ template may link as weak symbols:BIND_SPECIAL_DYLIB_WEAK_LOOKUP + https://stackoverflow.com/questions/58241873/why-are-functions-generated-on-use-of-template-have-weak-as-symbol-type + https://stackoverflow.com/questions/44335046/how-does-the-linker-handle-identical-template-instantiations-across-translation + */ + + SYSLOG("import[%d] ordinal=%x weak=%d name=%s\n", i, imports[i].lib_ordinal, imports[i].weak_import, symbolName); + if(libOrdinal > 0) imports[i].lib_ordinal = libOrdinal+1; + } + break; + case DYLD_CHAINED_IMPORT_ADDEND: + importsA32 = (struct dyld_chained_import_addend*)((uint8_t*)chainsHeader + chainsHeader->imports_offset); + for (uint32_t i=0; i < chainsHeader->imports_count; ++i) { + char* symbolName = &symbolsPool[importsA32[i].name_offset]; + uint8_t libVal = importsA32[i].lib_ordinal; + if ( libVal > 0xF0 ) + libOrdinal = (int8_t)libVal; + else + libOrdinal = libVal; + + SYSLOG("importA32[%d] ordinal=%x weak=%d name=%s\n", i, importsA32[i].lib_ordinal, importsA32[i].weak_import, symbolName); + if(libOrdinal > 0) importsA32[i].lib_ordinal = libOrdinal+1; + } + break; + case DYLD_CHAINED_IMPORT_ADDEND64: + importsA64 = (struct dyld_chained_import_addend64*)((uint8_t*)chainsHeader + chainsHeader->imports_offset); + for (uint32_t i=0; i < chainsHeader->imports_count; ++i) { + char* symbolName = &symbolsPool[importsA64[i].name_offset]; + uint16_t libVal = importsA64[i].lib_ordinal; + if ( libVal > 0xFFF0 ) + libOrdinal = (int16_t)libVal; + else + libOrdinal = libVal; + + SYSLOG("importA64[%d] ordinal=%x weak=%d name=%s\n", i, importsA64[i].lib_ordinal, importsA64[i].weak_import, symbolName); + if(libOrdinal > 0) importsA64[i].lib_ordinal = libOrdinal+1; + } + break; + default: + fprintf(stderr, "unknown imports format: %d\n", chainsHeader->imports_format); + return -1; + } + } + + size_t newfsize = 0; + + if(dyld_info) + { + assert(dyld_info->bind_off != 0); //follow dyld + + newfsize = st.st_size; + + if(dyld_info->bind_off && dyld_info->bind_size) + { + SYSLOG("bind_off=%x size=%x", dyld_info->bind_off, dyld_info->bind_size); + uint32_t size = dyld_info->bind_size; + void* data = (void*)((uint64_t)header + dyld_info->bind_off); + void* newbind = rebind(header, bindtype_bind, data, &size); + SYSLOG("new bind=%p size=%x", newbind, size); + if(newbind) + { + assert(lseek(fd, 0, SEEK_END)==newfsize); + assert(write(fd, newbind, size)==size); + dyld_info->bind_off = newfsize; + dyld_info->bind_size = size; + linkedit_seg->filesize += size; + linkedit_seg->vmsize += size; + newfsize += size; + + free(newbind); + } + } + if(dyld_info->weak_bind_off && dyld_info->weak_bind_size) + { + SYSLOG("weak_bind_off=%x size=%x", dyld_info->weak_bind_off, dyld_info->weak_bind_size); + uint32_t size = dyld_info->weak_bind_size; + void* data = (void*)((uint64_t)header + dyld_info->weak_bind_off); + void* newbind = rebind(header, bindtype_weak, data, &size); + SYSLOG("new weak bind=%p size=%x", newbind, size); + assert(newbind == NULL); //weak bind, no ordinal + } + if(dyld_info->lazy_bind_off && dyld_info->lazy_bind_size) + { + SYSLOG("lazy_bind_off=%x size=%x", dyld_info->lazy_bind_off, dyld_info->lazy_bind_size); + uint32_t size = dyld_info->lazy_bind_size; + void* data = (void*)((uint64_t)header + dyld_info->lazy_bind_off); + void* newbind = rebind(header, bindtype_lazy, data, &size); + SYSLOG("new lazy bind=%p size=%x", newbind, size); + if(newbind) + { + assert(lseek(fd, 0, SEEK_END)==newfsize); + assert(write(fd, newbind, size)==size); + dyld_info->lazy_bind_off = newfsize; + dyld_info->lazy_bind_size = size; + linkedit_seg->filesize += size; + linkedit_seg->vmsize += size; + newfsize += size; + + free(newbind); + } + } + + if(code_sign && newfsize!=st.st_size) + { + // some machos has padding data in the end + // assert(st.st_size == (code_sign->dataoff+code_sign->datasize)); + + void* data = (void*)((uint64_t)header + code_sign->dataoff); + size_t size = code_sign->datasize; + assert(lseek(fd, 0, SEEK_END)==newfsize); + assert(write(fd, data, size)==size); + code_sign->dataoff = newfsize; + linkedit_seg->filesize += size; + linkedit_seg->vmsize += size; + newfsize += size; + } + + // for(int i=0; i<(newfsize%0x10); i++) { + // int zero=0; + // linkedit_seg->filesize++; + // assert(write(fd, &zero, 1)==1); + // } + + linkedit_seg->vmsize = round_page(linkedit_seg->vmsize); + } + + + // struct dylib_command* newlib = (struct dylib_command*)((uint64_t)header + sizeof(*header) + header->sizeofcmds); + + //last + struct dylib_command* newlib = first_dylib; + size_t first_dylib_offset = (uint64_t)newlib - ((uint64_t)header + sizeof(*header)); + memmove((void*)((uint64_t)newlib + addsize), newlib, header->sizeofcmds-first_dylib_offset); + + newlib->cmd = LC_LOAD_DYLIB; + newlib->cmdsize = addsize; + newlib->dylib.timestamp = 0; + newlib->dylib.current_version = 0; + newlib->dylib.compatibility_version = 0; + newlib->dylib.name.offset = sizeof(*newlib); + strcpy((char*)newlib+sizeof(*newlib), BOOTSTRAP_INSTALL_NAME); + + header->sizeofcmds += addsize; + header->ncmds++; + + assert(lseek(fd, 0, SEEK_SET) == 0); + if(write(fd, header, st.st_size) != st.st_size) { + fprintf(stderr, "write %lld error:%d,%s\n", st.st_size, errno, strerror(errno)); + return -1; + } + + return 0; +} + +int patch_executable(const char* file, uint64_t offset, uint64_t size) +{ + int fd = open(file, O_RDWR); + if(fd < 0) { + fprintf(stderr, "open %s error:%d,%s\n", file, errno, strerror(errno)); + return -1; + } + + struct stat st; + if(stat(file, &st) < 0) { + fprintf(stderr, "stat %s error:%d,%s\n", file, errno, strerror(errno)); + return -1; + } + + SYSLOG("file size = %lld\n", st.st_size); + + void* macho = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, offset); + if(macho == MAP_FAILED) { + fprintf(stderr, "map %s error:%d,%s\n", file, errno, strerror(errno)); + return -1; + } + + if(offset != 0) { + assert(ftruncate(fd, 0)==0); + assert(write(fd, macho, size)==size); + assert(fsync(fd)==0); + assert(stat(file, &st)==0); + assert(st.st_size==size); + } + + struct mach_header_64* header = (struct mach_header_64*)((uint64_t)macho + 0); + + int retval = patch_macho(fd, header); + SYSLOG("patch macho @ %x : %d", offset, retval); + + munmap(macho, st.st_size); + + close(fd); + + return retval; +} + +#include +#include + +int patch_app_exe(const char* file) +{ + FAT *fat = fat_init_from_path(file); + if (!fat) return -1; + MachO *macho = fat_find_preferred_slice(fat); + if (!macho) return -1; + // printf("offset=%llx size=%llx\n", macho->archDescriptor.offset, macho->archDescriptor.size); + return patch_executable(file, macho->archDescriptor.offset, macho->archDescriptor.size); +} + diff --git a/RootHelperSample/exepatch.h b/RootHelperSample/exepatch.h new file mode 100644 index 00000000..3663e7b2 --- /dev/null +++ b/RootHelperSample/exepatch.h @@ -0,0 +1,22 @@ +#ifndef EXEPATCH_H +#define EXEPATCH_H + +#include +#include + +// Define the bootstrap install name +#define BOOTSTRAP_INSTALL_NAME "@loader_path/generalhook.dylib" + +//// Function to rebind Mach-O binary +//void* rebind(struct mach_header_64* header, enum bindtype type, void* data, uint32_t* size); +// +//// Function to patch Mach-O binary +//int patch_macho(int fd, struct mach_header_64* header); +// +//// Function to patch executable +//int patch_executable(const char* file, uint64_t offset, uint64_t size); + +// Function to patch application executable +int patch_app_exe(const char* file); + +#endif // MACHO_PATCHER_H diff --git a/RootHelperSample/launchdshim/SpringBoardShim/Makefile b/RootHelperSample/launchdshim/SpringBoardShim/Makefile index adc6af6e..1cf8fbce 100644 --- a/RootHelperSample/launchdshim/SpringBoardShim/Makefile +++ b/RootHelperSample/launchdshim/SpringBoardShim/Makefile @@ -5,8 +5,8 @@ include $(THEOS)/makefiles/common.mk TOOL_NAME = springboardshim -springboardshim_FILES = main.c -springboardshim_CFLAGS = -fobjc-arc -isystem +springboardshim_FILES = $(wildcard *.c) $(wildcard *.m) +springboardshim_CFLAGS = -fobjc-arc -isystem -Wno-error springboardshim_LDFLAGS = -L./ -lbsm springboardshim_CODESIGN_FLAGS = -SSpringBoardEnts.plist #springboardshim_PRIVATE_FRAMEWORKS = SpringBoard SpringBoardServices Foundation // adding SpringBoard to privateframeworks here will add it into load command before the tweak dylib is loaded, which causes the platform check to fail - thanks DuyKhanhTran diff --git a/RootHelperSample/launchdshim/SpringBoardShim/SpringBoardEnts.plist b/RootHelperSample/launchdshim/SpringBoardShim/SpringBoardEnts.plist index 050350d4..d03368cc 100644 --- a/RootHelperSample/launchdshim/SpringBoardShim/SpringBoardEnts.plist +++ b/RootHelperSample/launchdshim/SpringBoardShim/SpringBoardEnts.plist @@ -8,6 +8,8 @@ com.apple.springboard com.apple.private.security.no-sandbox + com.apple.security.network.client + com.apple.private.domain-extension com.apple.private.security.container-required diff --git a/RootHelperSample/launchdshim/SpringBoardShim/build.sh b/RootHelperSample/launchdshim/SpringBoardShim/build.sh index 6eec0732..d7e7d8ca 100755 --- a/RootHelperSample/launchdshim/SpringBoardShim/build.sh +++ b/RootHelperSample/launchdshim/SpringBoardShim/build.sh @@ -5,8 +5,9 @@ function replaceByte() { make # /Users/ibarahime/insert_dylib/insert_dylib/insert_dylib /var/jb/usr/lib/ellekit/libinjector.dylib .theos/obj/debug/arm64e/springboardshim springboardshiminjected --all-yes # /Users/ibarahime/insert_dylib/insert_dylib/insert_dylib /var/jb/usr/lib/libellekit.dylib springboardshiminjected springboardshiminjected --all-yes -insert_dylib @loader_path/springboardhook.dylib .theos/obj/debug/arm64/springboardshim springboardshiminjected --all-yes +# /Users/ibarahime/dev/insert_dylib/insert_dylib/a.out @loader_path/springboardhook.dylib .theos/obj/debug/arm64/springboardshim springboardshiminjected --all-yes # replaceByte 'springboardshiminjected' 8 -ldid -SSpringBoardEnts.plist springboardshiminjected -ct_bypass -i springboardshiminjected -r -o springboardshimsignedinjected +/Users/ibarahime/Downloads/ldid_macosx_arm64 -SSpringBoardEnts.plist springboardshiminjected +/Users/ibarahime/dev/ChOma/ct_bypass -i springboardshiminjected -r -o springboardshimsignedinjected + diff --git a/RootHelperSample/launchdshim/SpringBoardShim/fishhook.c b/RootHelperSample/launchdshim/SpringBoardShim/fishhook.c new file mode 100644 index 00000000..e6d92d1d --- /dev/null +++ b/RootHelperSample/launchdshim/SpringBoardShim/fishhook.c @@ -0,0 +1,277 @@ +// Copyright (c) 2013, Facebook, Inc. +// All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name Facebook nor the names of its contributors may be used to +// endorse or promote products derived from this software without specific +// prior written permission. +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "fishhook.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if __has_include() +#include +#endif + +#ifdef __LP64__ +typedef struct mach_header_64 mach_header_t; +typedef struct segment_command_64 segment_command_t; +typedef struct section_64 section_t; +typedef struct nlist_64 nlist_t; +#define LC_SEGMENT_ARCH_DEPENDENT LC_SEGMENT_64 +#else +typedef struct mach_header mach_header_t; +typedef struct segment_command segment_command_t; +typedef struct section section_t; +typedef struct nlist nlist_t; +#define LC_SEGMENT_ARCH_DEPENDENT LC_SEGMENT +#endif + +#ifndef SEG_DATA_CONST +#define SEG_DATA_CONST "__DATA_CONST" +#endif + +struct rebindings_entry { + struct rebinding *rebindings; + size_t rebindings_nel; + struct rebindings_entry *next; +}; + +static struct rebindings_entry *_rebindings_head; + +static int prepend_rebindings(struct rebindings_entry **rebindings_head, + struct rebinding rebindings[], + size_t nel) { + struct rebindings_entry *new_entry = (struct rebindings_entry *) malloc(sizeof(struct rebindings_entry)); + if (!new_entry) { + return -1; + } + new_entry->rebindings = (struct rebinding *) malloc(sizeof(struct rebinding) * nel); + if (!new_entry->rebindings) { + free(new_entry); + return -1; + } + memcpy(new_entry->rebindings, rebindings, sizeof(struct rebinding) * nel); + new_entry->rebindings_nel = nel; + new_entry->next = *rebindings_head; + *rebindings_head = new_entry; + return 0; +} + +#if 0 +static int get_protection(void *addr, vm_prot_t *prot, vm_prot_t *max_prot) { + mach_port_t task = mach_task_self(); + vm_size_t size = 0; + vm_address_t address = (vm_address_t)addr; + memory_object_name_t object; +#ifdef __LP64__ + mach_msg_type_number_t count = VM_REGION_BASIC_INFO_COUNT_64; + vm_region_basic_info_data_64_t info; + kern_return_t info_ret = vm_region_64( + task, &address, &size, VM_REGION_BASIC_INFO_64, (vm_region_info_64_t)&info, &count, &object); +#else + mach_msg_type_number_t count = VM_REGION_BASIC_INFO_COUNT; + vm_region_basic_info_data_t info; + kern_return_t info_ret = vm_region(task, &address, &size, VM_REGION_BASIC_INFO, (vm_region_info_t)&info, &count, &object); +#endif + if (info_ret == KERN_SUCCESS) { + if (prot != NULL) + *prot = info.protection; + + if (max_prot != NULL) + *max_prot = info.max_protection; + + return 0; + } + + return -1; +} +#endif + +static void perform_rebinding_with_section(struct rebindings_entry *rebindings, + section_t *section, + intptr_t slide, + nlist_t *symtab, + char *strtab, + uint32_t *indirect_symtab) { + uint32_t *indirect_symbol_indices = indirect_symtab + section->reserved1; + void **indirect_symbol_bindings = (void **)((uintptr_t)slide + section->addr); + + for (uint i = 0; i < section->size / sizeof(void *); i++) { + uint32_t symtab_index = indirect_symbol_indices[i]; + if (symtab_index == INDIRECT_SYMBOL_ABS || symtab_index == INDIRECT_SYMBOL_LOCAL || + symtab_index == (INDIRECT_SYMBOL_LOCAL | INDIRECT_SYMBOL_ABS)) { + continue; + } + uint32_t strtab_offset = symtab[symtab_index].n_un.n_strx; + char *symbol_name = strtab + strtab_offset; + bool symbol_name_longer_than_1 = symbol_name[0] && symbol_name[1]; + struct rebindings_entry *cur = rebindings; + while (cur) { + for (uint j = 0; j < cur->rebindings_nel; j++) { + if (symbol_name_longer_than_1 && strcmp(&symbol_name[1], cur->rebindings[j].name) == 0) { + kern_return_t err; + + if (cur->rebindings[j].replaced != NULL && indirect_symbol_bindings[i] != cur->rebindings[j].replacement) + *(cur->rebindings[j].replaced) = indirect_symbol_bindings[i]; + + /** + * 1. Moved the vm protection modifying codes to here to reduce the + * changing scope. + * 2. Adding VM_PROT_WRITE mode unconditionally because vm_region + * API on some iOS/Mac reports mismatch vm protection attributes. + * -- Lianfu Hao Jun 16th, 2021 + **/ + err = vm_protect (mach_task_self (), (uintptr_t)indirect_symbol_bindings, section->size, 0, VM_PROT_READ | VM_PROT_WRITE | VM_PROT_COPY); + if (err == KERN_SUCCESS) { + /** + * Once we failed to change the vm protection, we + * MUST NOT continue the following write actions! + * iOS 15 has corrected the const segments prot. + * -- Lionfore Hao Jun 11th, 2021 + **/ + #if !__has_feature(ptrauth_calls) + indirect_symbol_bindings[i] = cur->rebindings[j].replacement; + #else + void *replacement = cur->rebindings[j].replacement; + if (!strcmp(section->sectname, "__auth_got")) { + void *stripped = ptrauth_strip(replacement, ptrauth_key_process_independent_code); + replacement = ptrauth_sign_unauthenticated(stripped, ptrauth_key_process_independent_code, &indirect_symbol_bindings[i]); + } + indirect_symbol_bindings[i] = replacement; + #endif + } + goto symbol_loop; + } + } + cur = cur->next; + } + symbol_loop:; + } +} + +static void rebind_symbols_for_image(struct rebindings_entry *rebindings, + const struct mach_header *header, + intptr_t slide) { + Dl_info info; + if (dladdr(header, &info) == 0) { + return; + } + + segment_command_t *cur_seg_cmd; + segment_command_t *linkedit_segment = NULL; + struct symtab_command* symtab_cmd = NULL; + struct dysymtab_command* dysymtab_cmd = NULL; + + uintptr_t cur = (uintptr_t)header + sizeof(mach_header_t); + for (uint i = 0; i < header->ncmds; i++, cur += cur_seg_cmd->cmdsize) { + cur_seg_cmd = (segment_command_t *)cur; + if (cur_seg_cmd->cmd == LC_SEGMENT_ARCH_DEPENDENT) { + if (strcmp(cur_seg_cmd->segname, SEG_LINKEDIT) == 0) { + linkedit_segment = cur_seg_cmd; + } + } else if (cur_seg_cmd->cmd == LC_SYMTAB) { + symtab_cmd = (struct symtab_command*)cur_seg_cmd; + } else if (cur_seg_cmd->cmd == LC_DYSYMTAB) { + dysymtab_cmd = (struct dysymtab_command*)cur_seg_cmd; + } + } + + if (!symtab_cmd || !dysymtab_cmd || !linkedit_segment || + !dysymtab_cmd->nindirectsyms) { + return; + } + + // Find base symbol/string table addresses + uintptr_t linkedit_base = (uintptr_t)slide + linkedit_segment->vmaddr - linkedit_segment->fileoff; + nlist_t *symtab = (nlist_t *)(linkedit_base + symtab_cmd->symoff); + char *strtab = (char *)(linkedit_base + symtab_cmd->stroff); + + // Get indirect symbol table (array of uint32_t indices into symbol table) + uint32_t *indirect_symtab = (uint32_t *)(linkedit_base + dysymtab_cmd->indirectsymoff); + + cur = (uintptr_t)header + sizeof(mach_header_t); + for (uint i = 0; i < header->ncmds; i++, cur += cur_seg_cmd->cmdsize) { + cur_seg_cmd = (segment_command_t *)cur; + if (cur_seg_cmd->cmd == LC_SEGMENT_ARCH_DEPENDENT) { + if (strcmp(cur_seg_cmd->segname, SEG_DATA) != 0 && + strcmp(cur_seg_cmd->segname, SEG_DATA_CONST) != 0) { + continue; + } + for (uint j = 0; j < cur_seg_cmd->nsects; j++) { + section_t *sect = + (section_t *)(cur + sizeof(segment_command_t)) + j; + if ((sect->flags & SECTION_TYPE) == S_LAZY_SYMBOL_POINTERS) { + perform_rebinding_with_section(rebindings, sect, slide, symtab, strtab, indirect_symtab); + } + if ((sect->flags & SECTION_TYPE) == S_NON_LAZY_SYMBOL_POINTERS) { + perform_rebinding_with_section(rebindings, sect, slide, symtab, strtab, indirect_symtab); + } + } + } + } +} + +static void _rebind_symbols_for_image(const struct mach_header *header, + intptr_t slide) { + rebind_symbols_for_image(_rebindings_head, header, slide); +} + +int rebind_symbols_image(void *header, + intptr_t slide, + struct rebinding rebindings[], + size_t rebindings_nel) { + struct rebindings_entry *rebindings_head = NULL; + int retval = prepend_rebindings(&rebindings_head, rebindings, rebindings_nel); + rebind_symbols_for_image(rebindings_head, (const struct mach_header *) header, slide); + if (rebindings_head) { + free(rebindings_head->rebindings); + } + free(rebindings_head); + return retval; +} + +int rebind_symbols(struct rebinding rebindings[], size_t rebindings_nel) { + int retval = prepend_rebindings(&_rebindings_head, rebindings, rebindings_nel); + if (retval < 0) { + return retval; + } + // If this was the first call, register callback for image additions (which is also invoked for + // existing images, otherwise, just run on existing images + if (!_rebindings_head->next) { + _dyld_register_func_for_add_image(_rebind_symbols_for_image); + } else { + uint32_t c = _dyld_image_count(); + for (uint32_t i = 0; i < c; i++) { + _rebind_symbols_for_image(_dyld_get_image_header(i), _dyld_get_image_vmaddr_slide(i)); + } + } + return retval; +} diff --git a/RootHelperSample/launchdshim/SpringBoardShim/fishhook.h b/RootHelperSample/launchdshim/SpringBoardShim/fishhook.h new file mode 100644 index 00000000..0d8e36a9 --- /dev/null +++ b/RootHelperSample/launchdshim/SpringBoardShim/fishhook.h @@ -0,0 +1,76 @@ +// Copyright (c) 2013, Facebook, Inc. +// All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name Facebook nor the names of its contributors may be used to +// endorse or promote products derived from this software without specific +// prior written permission. +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef fishhook_h +#define fishhook_h + +#include +#include + +#if !defined(FISHHOOK_EXPORT) +#define FISHHOOK_VISIBILITY __attribute__((visibility("hidden"))) +#else +#define FISHHOOK_VISIBILITY __attribute__((visibility("default"))) +#endif + +#ifdef __cplusplus +extern "C" { +#endif //__cplusplus + +/* + * A structure representing a particular intended rebinding from a symbol + * name to its replacement + */ +struct rebinding { + const char *name; + void *replacement; + void **replaced; +}; + +/* + * For each rebinding in rebindings, rebinds references to external, indirect + * symbols with the specified name to instead point at replacement for each + * image in the calling process as well as for all future images that are loaded + * by the process. If rebind_functions is called more than once, the symbols to + * rebind are added to the existing list of rebindings, and if a given symbol + * is rebound more than once, the later rebinding will take precedence. + */ +FISHHOOK_VISIBILITY +int rebind_symbols(struct rebinding rebindings[], size_t rebindings_nel); + +/* + * Rebinds as above, but only in the specified image. The header should point + * to the mach-o header, the slide should be the slide offset. Others as above. + */ +FISHHOOK_VISIBILITY +int rebind_symbols_image(void *header, + intptr_t slide, + struct rebinding rebindings[], + size_t rebindings_nel); + +#ifdef __cplusplus +} +#endif //__cplusplus + +#endif //fishhook_h + diff --git a/RootHelperSample/launchdshim/SpringBoardShim/main.c b/RootHelperSample/launchdshim/SpringBoardShim/main.c deleted file mode 100644 index 5f567e5f..00000000 --- a/RootHelperSample/launchdshim/SpringBoardShim/main.c +++ /dev/null @@ -1,14 +0,0 @@ -#include -#include -#include -#include -#include - -int (*SBSystemAppMain)(int argc, char *argv[], char *envp[], char* apple[]); - -int main(int argc, char *argv[], char *envp[], char* apple[]) { - void *handle = dlopen("/System/Library/PrivateFrameworks/SpringBoard.framework/SpringBoard", RTLD_GLOBAL); - SBSystemAppMain = dlsym(handle, "SBSystemAppMain"); - return SBSystemAppMain(argc, argv, envp, apple); -} - diff --git a/RootHelperSample/launchdshim/SpringBoardShim/main.m b/RootHelperSample/launchdshim/SpringBoardShim/main.m new file mode 100644 index 00000000..5c67836f --- /dev/null +++ b/RootHelperSample/launchdshim/SpringBoardShim/main.m @@ -0,0 +1,168 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#import +#include +#include +#include +#include +#include "utils.h" +#include +#include + +@interface NSBundle(private) +- (id)_cfBundle;#include +#include +#include +#include +#include + +int (*SBSystemAppMain)(int argc, char *argv[], char *envp[], char* apple[]); + +int main(int argc, char *argv[], char *envp[], char* apple[]) { + void *handle = dlopen("/System/Library/PrivateFrameworks/SpringBoard.framework/SpringBoard", RTLD_GLOBAL); + SBSystemAppMain = dlsym(handle, "SBSystemAppMain"); + return SBSystemAppMain(argc, argv, envp, apple); +} + +@end + +@implementation NSBundle (Loaded) + +- (BOOL)isLoaded { + return YES; +} + +@end + +int (*orig_csops)(pid_t pid, unsigned int ops, void * useraddr, size_t usersize); +int (*orig_csops_audittoken)(pid_t pid, unsigned int ops, void * useraddr, size_t usersize, audit_token_t * token); +int csops_audittoken(pid_t pid, unsigned int ops, void * useraddr, size_t usersize, audit_token_t * token); +int csops(pid_t pid, unsigned int ops, void *useraddr, size_t usersize); +int ptrace(int, int, int, int); + +int hooked_csops(pid_t pid, unsigned int ops, void *useraddr, size_t usersize) { + int result = orig_csops(pid, ops, useraddr, usersize); + if (result != 0) return result; + if (ops == 0) { + *((uint32_t *)useraddr) |= 0x4000000; + } + return result; +} + +int hooked_csops_audittoken(pid_t pid, unsigned int ops, void * useraddr, size_t usersize, audit_token_t * token) { + int result = orig_csops_audittoken(pid, ops, useraddr, usersize, token); + if (result != 0) return result; + if (ops == 0) { + *((uint32_t *)useraddr) |= 0x4000000; + } + return result; +} + +int (*SBSystemAppMain)(int argc, char *argv[], char *envp[], char* apple[]); + +static void overwriteMainCFBundle() { + // Overwrite CFBundleGetMainBundle + uint32_t *pc = (uint32_t *)CFBundleGetMainBundle; + void **mainBundleAddr = 0; + while (true) { + uint64_t addr = aarch64_get_tbnz_jump_address(*pc, (uint64_t)pc); + if (addr) { + // adrp <- pc-1 + // tbnz <- pc + // ... + // ldr <- addr + mainBundleAddr = (void **)aarch64_emulate_adrp_ldr(*(pc-1), *(uint32_t *)addr, (uint64_t)(pc-1)); + break; + } + ++pc; + } + assert(mainBundleAddr != NULL); + *mainBundleAddr = (__bridge void *)NSBundle.mainBundle._cfBundle; +} + +static void overwriteMainNSBundle(NSBundle *newBundle) { + // Overwrite NSBundle.mainBundle + // iOS 16: x19 is _MergedGlobals + // iOS 17: x19 is _MergedGlobals+4 + + NSString *oldPath = NSBundle.mainBundle.executablePath; + uint32_t *mainBundleImpl = (uint32_t *)method_getImplementation(class_getClassMethod(NSBundle.class, @selector(mainBundle))); + for (int i = 0; i < 20; i++) { + void **_MergedGlobals = (void **)aarch64_emulate_adrp_add(mainBundleImpl[i], mainBundleImpl[i+1], (uint64_t)&mainBundleImpl[i]); + if (!_MergedGlobals) continue; + + // In iOS 17, adrp+add gives _MergedGlobals+4, so it uses ldur instruction instead of ldr + if ((mainBundleImpl[i+4] & 0xFF000000) == 0xF8000000) { + uint64_t ptr = (uint64_t)_MergedGlobals - 4; + _MergedGlobals = (void **)ptr; + } + + for (int mgIdx = 0; mgIdx < 20; mgIdx++) { + if (_MergedGlobals[mgIdx] == (__bridge void *)NSBundle.mainBundle) { + _MergedGlobals[mgIdx] = (__bridge void *)newBundle; + break; + } + } + } + +// assert(![NSBundle.mainBundle.executablePath isEqualToString:oldPath]); +} + +int main(int argc, char *argv[], char *envp[], char* apple[]) { + @autoreleasepool { + +// memorystatus_memlimit_properties_t props; +// memset(&props, '\0', sizeof(props)); +// props.memlimit_active = -1; +// props.memlimit_active_attr = MEMORYSTATUS_MEMLIMIT_ATTR_FATAL; +// props.memlimit_inactive = -1; +// props.memlimit_active_attr = MEMORYSTATUS_MEMLIMIT_ATTR_FATAL; +// memorystatus_control(MEMORYSTATUS_CMD_SET_MEMLIMIT_PROPERTIES, getpid(), 0, &props, sizeof(props)); + + if (argc > 1 && strcmp(argv[1], "--jit") == 0) { + NSLog(@"jit 1"); + ptrace(0, 0, 0, 0); + exit(0); + } else { + pid_t pid; + char *modified_argv[] = {argv[0], "--jit", NULL }; + int ret = posix_spawnp(&pid, argv[0], NULL, NULL, modified_argv, envp); + if (ret == 0) { + NSLog(@"jit 2"); + waitpid(pid, NULL, WUNTRACED); + ptrace(11, pid, 0, 0); + kill(pid, SIGTERM); + wait(NULL); + } + } + + NSString *bundlePath = @"/System/Library/CoreServices/SpringBoard.app"; + NSBundle *appBundle = [[NSBundle alloc] initWithPath:bundlePath]; + + overwriteMainNSBundle(appBundle); + overwriteMainCFBundle(); + + NSMutableArray *objcArgv = NSProcessInfo.processInfo.arguments.mutableCopy; + objcArgv[0] = appBundle.executablePath; + [NSProcessInfo.processInfo performSelector:@selector(setArguments:) withObject:objcArgv]; + NSProcessInfo.processInfo.processName = appBundle.infoDictionary[@"CFBundleExecutable"]; + *_CFGetProgname() = NSProcessInfo.processInfo.processName.UTF8String; + + const struct LHFunctionHook hooks[] = { + {(void *)csops, (void *)hooked_csops, (void *)&orig_csops, 0}, + {(void *)csops_audittoken, (void *)hooked_csops_audittoken, (void *)&orig_csops_audittoken, 0} + }; + LHHookFunctions(hooks, 2); + void *handle = dlopen("/System/Library/PrivateFrameworks/SpringBoard.framework/SpringBoard", RTLD_GLOBAL); +// spawnRoot(jbroot(@"/basebin/bootstrapd"), @[@"daemon",@"-f"], nil, nil); + dlopen(jbroot(@"/basebin/bootstrap.dylib").UTF8String, RTLD_GLOBAL | RTLD_NOW); + SBSystemAppMain = dlsym(handle, "SBSystemAppMain"); + return SBSystemAppMain(argc, argv, envp, apple); + } +} diff --git a/RootHelperSample/launchdshim/SpringBoardShim/springboardshimsignedinjected b/RootHelperSample/launchdshim/SpringBoardShim/springboardshimsignedinjected index 042956bb897949cd7a7c9663a0c062df5c6a1c4e..111fffff07d7f27e9f2adc0215b3af7990ab90d8 100755 GIT binary patch delta 10118 zcma)C4Rljgwm$bJfwV;^Edo-0QUPfTw1E7zh@=*<{1)4yh{z>vQWDxEB}w@iI*!bKyPNVH})vLKDYjyFm2maHk2{DGM0Y*0&z?SWsnfI|5FR&F#2GhO;WazA6)f^(}^9c(;&x>m`+@ zQbip4G~vB+bq(&Xw{C z78h~T)CGGQggvK(yYqEfQQy;Msv2Kf_4ahDUQr;v zCl1|EUU`z%c^jdP^UwcnVV_fh%pv8D`ST%FRBLZt7XqCfYo`zqQFM#Fa;;!417sH;lAG*r6Tuh7}}mli8v0j|j>-&9hV%0-qW= zmCX#@sS`poH6hhQ2-=KH6=fEuFw^5jASjYRH_rI$;6M@LrSFkhR=LS+V*Mk~if>@D zHnkhf2O`h_T5ThZ-|gxe6dBtcZ26+9<(TfddQG$HhoG?%lz1vZNq95KN)hJ1W0AD@q;z{e@@H#Sd?<7VC#8Kj$2OusFXtj=Mh^lTLm0nOt@bK4-* zZG&RmCc|&}3BTYs^R<3U9XB)du1L`gt#AalY8KG>HZ^}{=!gzSi!bE)0bR+8KyoCR zBwEptp35cYfs}9R7Ra0`gxY}2Bk6@{nI5T%{6nVhFlx@oa+vUH#w!nM~3TQBRtw=QyI8vJLaI z2-$$NjPZDkPaD{QHiNYjRhME;%yZ4b>|d%yG{ML^*CeEBhJ++ET+L%4r1ef23_D4B z2I#B` ztFJ}^LJX)$3RY2$b4&u0JJNC7;spd(+y~DB={#jJ=KwY0t5Nltc{bW=OxP**myEg0=G-Y?6RY=5J2enJ&a{iwdcC!_Cm) zgro_IHPRT9Ys|U)3T`?LVoI4J;sMuhpm+LK0f4BNr$ z8^lf8#teRe(dDFCE}AEvr+cN}B$yf!k$;}mClm@g^l}ELX5obpTMGV3Lssid!^6YIL-gp)_ z2W(Ko9Iy$VB)SM&pGVF-08=!yu564L;tsSMSZFM4mSF-uDvy!CEe(pHdDto&9q05o zWvSB;g=eZ^=A^i`7bxuIa(+9gsR${DU(_6Fv#H2DlO>s}h8IOp;6+fRQE5Xq)WQ{6 zr!$%ax{J0D*H24z6aXrJZN45#4uj3%Uud^s7L3JqP@zY4Pj8GPNMjZjJRu;A`vE3G z+LS>%?vDiJ{)AwiL~|MGPRUM4e+fK5wtt5?9@Y?qHY5kr?bDha~#K*B$quFAsW*uDaL&1db%=1!`%$p5GxbT}eoym~ItyVQJLz@F1Uyt$^N5q_- zFp1WcXbU#U=3{}Aqy?AsSYUh9#Mq3G+Hjb=TGc#D!j6TohzqSAN9ogKCVyJG1&*i! zqm+dba3N)yW|ocDfdL$U{6GjFUj&QFO?<)>kBNarkt~)S$wDT9zd^)Pn#PR$kC5kc zN3j9k;FOyQ=1vn>6P+O_(PUmUpr~D)>xH>kA^K@T^k+%!$*8Z1mk%6c%W`PL^mEz?^hb}?Yi+Dx^aeXoT(clH%Dow>c%;` z@!h)dT-|uSI>xJNP2yq&$i+C7Sv$EVqB3V;mQS=UNekyKUNC3&ykdNlp>Ip-L;b`Q z{*AR*&h`5pK6>@Hl-XPr4ttIzZL~jqoTUtaWwd{srNZUGz@8b;@(UKtVLqG7@5m|h z`rNia4k|$eH)BXL{At0Hngw0?X2Fci%Ghkc)af%JH5w}|JS4Zz?IsW?=*D;^IB`&i zCNS|7eaWDO2~5P>{R>%gVvsh&>wi$eP7LzzD1eRXJU-s=bwoFR_Ew)}^@%SbXo*2= z!JmjF{-mvF{ucF#YLvq`N&J~ej|D(bzTYJVlV}2Pvid~iqFI7Rl^xl^0)i*740@=| ziYMMYsRf~sH|JoT=`EvhHZ(CAqg4dfm~OFP*@@nQJ}}(BWrQ#xJh5ejOy6^u6^hY< z+Q=LNY+)FVZ)zpzKJ=H+-$XYG%#?&a9o>n(0Uh;+=~Z-8RHhT?ZRogXOhZIw%0Qng zGQ(W-C%{zsWb5{?E^>J6OqLcG&GQ5tK98+po~P97@w@Oj$y2&<&W2J)B?S=oWh z2c8l>NZF;;j)26!P)h6EHoM&?`72y@e0H^05Ts%G9IJ_uPb#bOluC#z39AYnq53zv z6--&3luGfjDxgt!@8NXV><)0njKi}I>-gC0^ORO@luDiD1iBsWD1@a75){u;cO{c- zC0-wRu5(M3K5xKLim}^P>XZUDf4Ss$RFp~3ztmPy;VorSna=?&+$tnVd2{n%jeyM) zDB>S;^XS`Zp`*;w~gJ_87fsi4J#Fg$=xHcIG5I21-1?lGaqYE6D>s2R_JF8QF{5fofWq zmoIzWjwQB$lf@O?qkKust*l&Rb9q=liH)$?e5KB*lO?vvO;dHG6t!Sb2nrElNAF9* zX&6%sL zk-dmsgE8d0?SK^22qt=UUHO1c3^aR^eTjhv69I{P37s0j#6Z7J^qT$2A4IRggirL7 z(Wwzk^vb&GRAQhxj2uV|G?)m8fjLG4ZJiu?ht8pdZ>Jx%T>+h41Mqy%sDq0!u?iF9 zz{gJZbl|voinOi3A%Qel6DXiEC73kQ*87ID-x?u*rQZe^_uyvIi!mQC?b;R-Hg)Q* zsG9h$8m#TA@z8eFuag;#s1NXv**=wlI>8M;3Ujdx^y|dHsW9LPh}70#47nc;;Yp2P zQd_@H^g|cW8XUVE2*f~{PzXqX7tyI{4D{>7;3#LnST1mgUV{mr=<&IqH+ql&`gNi| zwGh0qKdVG127CfzA|M7Yqf;Z880goD!PZ5}+7nnOdJQIgqW=(`8o@-bty3zYNTgK4 z4>lp#=|^o?XLvV^nv9B!eyBJGwA^S4Ro69*$-;!MS&$Sa7z!x| zn>3&aO~QRDtofWmo7T0^eIGDD^`tR&J_a^nQNKP$ft8{QxKpAq*&l6obV7kw#K6Cb zfqxqV(>;NI(G3pAz|Ar6dm60n&py&7l>OOfG4K~L@VOZHhZy*(0^?U{3GgX^sDQ~T ztnJTIVh~n?&W28RMJYN}dL`(q(AS_#=qu5^=pJ-CI{DRs?n19XccasPMc#myd_!jC zAl5Sk$Sh34Ew5ejQtTy<0;;VX76@D8pr5hpXkYQm|@;acp55tz`LMXlUhrv^3UAWqobzbCkF|b_un4iMPV9 z73-Bg2X?hfw2J>Z#-BC#83%NzRNr$gV^XPUis>YYZ;bpTv&NC~iqRm>0BHN$kDzW)&PM6z}Wp}L0a^tnvQH}*~!0T~& z!js?5&MI^HoldW}JhSxXXb!zyu%w$N(>7_!l*!X4IWoPm+N(CXNkQ(u!+o>+7f*ES zx4p>?vd2{gTowMzo8G2iq)MRQjIs)~%U||sVZx4-a9Zog{;%MEM9QpcrL@U}jVlkX zXk9IfH3MotFA`s=U6&^usjX=g;%c9qFPLllJ}qR{UN|Qt9$qk8So&nIvZRTRmi0RP z!U^F>Vz1H)m%|e{oO@Q7w{*B+Clif)J8-4sNPhxB@8U^JNUW=^pDsRN>6;Z8`nGjn zVR`@8o4uC$=6{5be!lm=&V=8*;GX#9bID8br!^MKBF?xUUxPTU`kxYwhlA(Q4_F8W?`zjYMJZ+{Oi2bj6Ihw z=H={KS=*H@uCng(oeF%j`S_Gpd%}SQp4T^4AKQ82%SDT9eHZLsyR~}Zs^fY8^ONrHyIcsJ_zS#fX@q#^16Bnz+du7VlU9T^{vfz_ON89ng6wLUc zdiQNrk^1GAA8LB`_C1sNUL(Fw{ygEXfgaAtz5rx zVrlJ_VlhXKpMA$iIl~q|Gi_T+#1?++o0pR+Hl5AA{9w+Oarge`=xfhduS^Scq&#?b zP0F%K!z(ve?*Dw;^yXye@we6$_nH3v#H_$wk7gVhANcsCg^T}hJA3Evu2;Suu>K!! zUQBzlWoDQ1h**i1&{1a2{ zS;wXq_Wz^3*RKN0tM9&NN8ii;T$p>}uC6hSAI^X1)WqhIt&10T6x_epwJPJ##__jY ud@AEo!oLPR{Qlhwo_}Zkg|FAlFeNWJaq;B*c{!q^{P31S@eTZO%l`wWznSp> delta 2014 zcmb_cX;4#F6u$Q*kN}|su_#L=)jA+c0*J~Y5VUo{!O9|1l?H?dM3R6c2naP1YpGNz z;VBPyt5&6=qE;hC6m_g<#ib)w5D_~qqKrBNtrc9_b6-Fme)mkyJxk8|%}E+ASvS;J zIbIuh{91$%MnDv>BXG8b(J`L-8XGmim~X6>Q95L7n=wHrH^+^J5JJQzDMKXWBLmSz z%qHwUVx8O^9Y*UN>D(wAEx!Ik-IT0c@#jFy#Fy$1VszOX96^t=+gOXt}gLy6^ z-tFK7Nf0uIKhBt7XT<}HFlPGs?u>zN&-hu)(l>$!D72DWiCfI9nf(C>8N@_wL?{Eq z#6dd)>{(!wc4WbmVA~OS7NI04U<3L*U_#b|Oq$yQzdItcPAIn64@rDuv;!lt^oX=C zIQuYB6X{c>)(;%0jIs2G49QRyWe@50+?1pm!moLrAh-#M4dek6a*)fJ3QJEfUvLqV zYr0KtN#K;_YI9^N0LU=p%oW;7z@7(8j*Qx9kKHiZ=!f0(JZQ>;g^(gum6c6vh}0IS z0YU{Lw}s$>4LlB7qCsU|?6lYdt&UblWM@YuD>cYUq0Ugy`E*LIj#gyQ$*FV>vQv|9 z9AJjQVaQ0SgL9FxQ;ChxbfR-~9A0p|p;Mrx!Gc|AD@~jvS4tkaS$7BZBhF^qEbths zAwR`pOYFw_3bBPAE`c01iGop(9Tvm;Hr?)>az181cX1?U(lDDG^?SfWQi2r2aZn7$ zApw9;a6k+LS2kZu=V)bWrG}<6WgpYpOkGyCEITJ_DV?Iz$}-bZ({eRFxfk90_ z8jRSAZS2L?rqBxPTxLl>@++o0Oo{Pz#0gWvnxv|xx}&kW?7yzv?}5GYUR^;l6~UdlJY>C zW!(ebhqjz+s=m#3lu${M;3HEWdKQ)R1aG)u)$mgUuP45Vu?`44QP*5={pW_NSaVcz z%#SOV-YmV$UpH+}F;W(t*{LcmxNNUl{A5l*ae?E0b5!Ri-U&gMuZN#%e0(@gEp#ru z^;?<09z6-YQWZXq?_y_qy_U)zDX|%^>2u0lwJ6+AVrY4)yKdYX;l1YZ@oTAyW=GTb zyIrQT?bHX@WqLt;ZeYGDCp}&(i;A5d;YSDg`bN%7iH^-<3wKk&`k*_lc{wi??W5d} zcBE|kWv=y!2$|6Hq6crQ^rZSpk#k{!cVW;tQ+;@CvE%l8w|2&FZvIlGY^hV`Uo`~e zUpVu9bZh0gkhZw{>4sfnYdx0H<$VrEN7im@FMU*BQ=KLX)3jWzDO~c>x$v-f)$Siu z0juY1jEw0Rm=u)IRFd>cFS4nQFhx%tc{EyebH&qzx@j$w|EN5Cy0}}Ec)IVQOLmWF z!TqR2-<@~Dn|HjtbV;h|E!lMNRoEfHj2C_91oxgja6Y#8z?Huivw3Tucg+f!{7>#@ zP2JIrrhhHIS>HIfZB%{A-oKyCXD%eS2_r(guUGu;^=qkX{O5hib+_lb?kJ;VRwurr HPVxQ&qGT>P diff --git a/RootHelperSample/launchdshim/SpringBoardShim/utils.h b/RootHelperSample/launchdshim/SpringBoardShim/utils.h new file mode 100644 index 00000000..d8914a28 --- /dev/null +++ b/RootHelperSample/launchdshim/SpringBoardShim/utils.h @@ -0,0 +1,20 @@ +#import +#include +#include + +const char **_CFGetProgname(void); +const char **_CFGetProcessPath(void); +int _NSGetExecutablePath(char* buf, uint32_t* bufsize); +const char *LCHomePath(); + +#define CS_DEBUGGED 0x10000000 +int csops(pid_t pid, unsigned int ops, void *useraddr, size_t usersize); + +void init_bypassDyldLibValidation(); +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); + +uint64_t aarch64_get_tbnz_jump_address(uint32_t instruction, uint64_t pc); +uint64_t aarch64_emulate_adrp(uint32_t instruction, uint64_t pc); +bool aarch64_emulate_add_imm(uint32_t instruction, uint32_t *dst, uint32_t *src, uint32_t *imm); +uint64_t aarch64_emulate_adrp_add(uint32_t instruction, uint32_t addInstruction, uint64_t pc); +uint64_t aarch64_emulate_adrp_ldr(uint32_t instruction, uint32_t ldrInstruction, uint64_t pc); diff --git a/RootHelperSample/launchdshim/SpringBoardShim/utils.m b/RootHelperSample/launchdshim/SpringBoardShim/utils.m new file mode 100644 index 00000000..f60b9f10 --- /dev/null +++ b/RootHelperSample/launchdshim/SpringBoardShim/utils.m @@ -0,0 +1,138 @@ +#import "utils.h" + +void __assert_rtn(const char* func, const char* file, int line, const char* failedexpr) { + [NSException raise:NSInternalInconsistencyException format:@"Assertion failed: (%s), file %s, line %d.\n", failedexpr, file, line]; + abort(); // silent compiler warning +} + +uint64_t aarch64_get_tbnz_jump_address(uint32_t instruction, uint64_t pc) { + // Check that this is a tbnz instruction + if ((instruction & 0xFF000000) != 0x37000000) { + return 0; + } + + uint32_t imm = ((instruction >> 5) & 0xFFFF) * 4; + return imm + pc; +} + +const char *LCHomePath() { + static const char *path; + if (path) return path; + const char *pathEnv = getenv("HOME"); + path = calloc(1, strlen(pathEnv)+1); + strncpy((char *)path, pathEnv, strlen(pathEnv)); + return path; +} + +// https://github.com/pinauten/PatchfinderUtils/blob/master/Sources/CFastFind/CFastFind.c +// +// CFastFind.c +// CFastFind +// +// Created by Linus Henze on 2021-10-16. +// Copyright © 2021 Linus Henze. All rights reserved. +// + +/** + * Emulate an adrp instruction at the given pc value + * Returns adrp destination + */ +uint64_t aarch64_emulate_adrp(uint32_t instruction, uint64_t pc) { + // Check that this is an adrp instruction + if ((instruction & 0x9F000000) != 0x90000000) { + return 0; + } + + // Calculate imm from hi and lo + int32_t imm_hi_lo = (instruction & 0xFFFFE0) >> 3; + imm_hi_lo |= (instruction & 0x60000000) >> 29; + if (instruction & 0x800000) { + // Sign extend + imm_hi_lo |= 0xFFE00000; + } + + // Build real imm + int64_t imm = ((int64_t) imm_hi_lo << 12); + + // Emulate + return (pc & ~(0xFFFULL)) + imm; +} + +bool aarch64_emulate_add_imm(uint32_t instruction, uint32_t *dst, uint32_t *src, uint32_t *imm) { + // Check that this is an add instruction with immediate + if ((instruction & 0xFF000000) != 0x91000000) { + return 0; + } + + int32_t imm12 = (instruction & 0x3FFC00) >> 10; + + uint8_t shift = (instruction & 0xC00000) >> 22; + switch (shift) { + case 0: + *imm = imm12; + break; + + case 1: + *imm = imm12 << 12; + break; + + default: + return false; + } + + *dst = instruction & 0x1F; + *src = (instruction >> 5) & 0x1F; + + return true; +} + +/** + * Emulate an adrp and add instruction at the given pc value + * Returns destination + */ + +uint64_t aarch64_emulate_adrp_add(uint32_t instruction, uint32_t addInstruction, uint64_t pc) { + uint64_t adrp_target = aarch64_emulate_adrp(instruction, pc); + if (!adrp_target) { + return 0; + } + + uint32_t addDst; + uint32_t addSrc; + uint32_t addImm; + if (!aarch64_emulate_add_imm(addInstruction, &addDst, &addSrc, &addImm)) { + return 0; + } + + if ((instruction & 0x1F) != addSrc) { + return 0; + } + + // Emulate + return adrp_target + (uint64_t) addImm; +} + +/** + * Emulate an adrp and ldr instruction at the given pc value + * Returns destination + */ + +uint64_t aarch64_emulate_adrp_ldr(uint32_t instruction, uint32_t ldrInstruction, uint64_t pc) { + uint64_t adrp_target = aarch64_emulate_adrp(instruction, pc); + if (!adrp_target) { + return 0; + } + + if ((instruction & 0x1F) != ((ldrInstruction >> 5) & 0x1F)) { + return 0; + } + + if ((ldrInstruction & 0xFFC00000) != 0xF9400000) { + return 0; + } + + uint32_t imm12 = ((ldrInstruction >> 10) & 0xFFF) << 3; + + // Emulate + return adrp_target + (uint64_t) imm12; +} diff --git a/RootHelperSample/launchdshim/generalhook/LICENCE b/RootHelperSample/launchdshim/generalhook/LICENCE new file mode 100644 index 00000000..f637fd2f --- /dev/null +++ b/RootHelperSample/launchdshim/generalhook/LICENCE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Hariz Shirazi (https://bomberfish.ca) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/RootHelperSample/launchdshim/generalhook/Makefile b/RootHelperSample/launchdshim/generalhook/Makefile new file mode 100644 index 00000000..e0902802 --- /dev/null +++ b/RootHelperSample/launchdshim/generalhook/Makefile @@ -0,0 +1,16 @@ +TARGET := iphone:clang:latest:15.0 +ARCHS = arm64 +THEOS_PACKAGE_SCHEME = roothide +include $(THEOS)/makefiles/common.mk + +LIBRARY_NAME = generalhook + +generalhook_FILES = $(wildcard *.m) $(wildcard *.c) $(wildcard verbose/*.m) +generalhook_CFLAGS = -fobjc-arc -isystem "../../../usprebooter/Private Headers I stole from the macOS SDK" -Wno-error +generalhook_CODESIGN_FLAGS = -S../launchdentitlements.plist +launchdhook_LDFLAGS = -L./ -lbsm -L/Users/nathan/theos/vendor/lib/ -lhooker -I/Users/nathan/theos/vendor/include -dynamiclib +#launchdhook_EXTRA_FRAMEWORKS += IOMobileFramebuffer IOSurface +after-package:: + echo "[*] Signing launchd hook" + ct_bypass -i .theos/obj/debug/generalhook.dylib -o generalhooksigned.dylib +include $(THEOS_MAKE_PATH)/library.mk diff --git a/RootHelperSample/launchdshim/generalhook/README.md b/RootHelperSample/launchdshim/generalhook/README.md new file mode 100644 index 00000000..17d0ef28 --- /dev/null +++ b/RootHelperSample/launchdshim/generalhook/README.md @@ -0,0 +1,3 @@ +# FBWrite + +Write text to the framebuffer, with style. \ No newline at end of file diff --git a/RootHelperSample/launchdshim/generalhook/build.sh b/RootHelperSample/launchdshim/generalhook/build.sh new file mode 100755 index 00000000..76bddd1d --- /dev/null +++ b/RootHelperSample/launchdshim/generalhook/build.sh @@ -0,0 +1,2 @@ +make +/Users/ibarahime/ChOma/ct_bypass -i .theos/obj/debug/launchdhook.dylib -r -o launchdhooksigned.dylib diff --git a/RootHelperSample/launchdshim/generalhook/control b/RootHelperSample/launchdshim/generalhook/control new file mode 100644 index 00000000..5315e07a --- /dev/null +++ b/RootHelperSample/launchdshim/generalhook/control @@ -0,0 +1,9 @@ +Package: ca.bomberfish.fbwrite +Name: FBWrite +Version: 0.0.1 +Architecture: iphoneos-arm +Description: Write to the framebuffer with style. +Maintainer: BomberFish Industries +Author: BomberFish Industries +Section: System +Tag: role::hacker diff --git a/RootHelperSample/launchdshim/generalhook/entitlements.plist b/RootHelperSample/launchdshim/generalhook/entitlements.plist new file mode 100644 index 00000000..86a8dcef --- /dev/null +++ b/RootHelperSample/launchdshim/generalhook/entitlements.plist @@ -0,0 +1,20 @@ + + + + + get-task-allow + + platform-application + + com.apple.private.security.no-container + + com.apple.private.allow-explicit-graphics-priority + + com.apple.security.iokit-user-client-class + + IOSurfaceRootUserClient + IOMobileFramebufferUserClient + IOHIDEventServiceUserClient + + + \ No newline at end of file diff --git a/RootHelperSample/launchdshim/generalhook/fishhook.c b/RootHelperSample/launchdshim/generalhook/fishhook.c new file mode 100644 index 00000000..e6d92d1d --- /dev/null +++ b/RootHelperSample/launchdshim/generalhook/fishhook.c @@ -0,0 +1,277 @@ +// Copyright (c) 2013, Facebook, Inc. +// All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name Facebook nor the names of its contributors may be used to +// endorse or promote products derived from this software without specific +// prior written permission. +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "fishhook.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if __has_include() +#include +#endif + +#ifdef __LP64__ +typedef struct mach_header_64 mach_header_t; +typedef struct segment_command_64 segment_command_t; +typedef struct section_64 section_t; +typedef struct nlist_64 nlist_t; +#define LC_SEGMENT_ARCH_DEPENDENT LC_SEGMENT_64 +#else +typedef struct mach_header mach_header_t; +typedef struct segment_command segment_command_t; +typedef struct section section_t; +typedef struct nlist nlist_t; +#define LC_SEGMENT_ARCH_DEPENDENT LC_SEGMENT +#endif + +#ifndef SEG_DATA_CONST +#define SEG_DATA_CONST "__DATA_CONST" +#endif + +struct rebindings_entry { + struct rebinding *rebindings; + size_t rebindings_nel; + struct rebindings_entry *next; +}; + +static struct rebindings_entry *_rebindings_head; + +static int prepend_rebindings(struct rebindings_entry **rebindings_head, + struct rebinding rebindings[], + size_t nel) { + struct rebindings_entry *new_entry = (struct rebindings_entry *) malloc(sizeof(struct rebindings_entry)); + if (!new_entry) { + return -1; + } + new_entry->rebindings = (struct rebinding *) malloc(sizeof(struct rebinding) * nel); + if (!new_entry->rebindings) { + free(new_entry); + return -1; + } + memcpy(new_entry->rebindings, rebindings, sizeof(struct rebinding) * nel); + new_entry->rebindings_nel = nel; + new_entry->next = *rebindings_head; + *rebindings_head = new_entry; + return 0; +} + +#if 0 +static int get_protection(void *addr, vm_prot_t *prot, vm_prot_t *max_prot) { + mach_port_t task = mach_task_self(); + vm_size_t size = 0; + vm_address_t address = (vm_address_t)addr; + memory_object_name_t object; +#ifdef __LP64__ + mach_msg_type_number_t count = VM_REGION_BASIC_INFO_COUNT_64; + vm_region_basic_info_data_64_t info; + kern_return_t info_ret = vm_region_64( + task, &address, &size, VM_REGION_BASIC_INFO_64, (vm_region_info_64_t)&info, &count, &object); +#else + mach_msg_type_number_t count = VM_REGION_BASIC_INFO_COUNT; + vm_region_basic_info_data_t info; + kern_return_t info_ret = vm_region(task, &address, &size, VM_REGION_BASIC_INFO, (vm_region_info_t)&info, &count, &object); +#endif + if (info_ret == KERN_SUCCESS) { + if (prot != NULL) + *prot = info.protection; + + if (max_prot != NULL) + *max_prot = info.max_protection; + + return 0; + } + + return -1; +} +#endif + +static void perform_rebinding_with_section(struct rebindings_entry *rebindings, + section_t *section, + intptr_t slide, + nlist_t *symtab, + char *strtab, + uint32_t *indirect_symtab) { + uint32_t *indirect_symbol_indices = indirect_symtab + section->reserved1; + void **indirect_symbol_bindings = (void **)((uintptr_t)slide + section->addr); + + for (uint i = 0; i < section->size / sizeof(void *); i++) { + uint32_t symtab_index = indirect_symbol_indices[i]; + if (symtab_index == INDIRECT_SYMBOL_ABS || symtab_index == INDIRECT_SYMBOL_LOCAL || + symtab_index == (INDIRECT_SYMBOL_LOCAL | INDIRECT_SYMBOL_ABS)) { + continue; + } + uint32_t strtab_offset = symtab[symtab_index].n_un.n_strx; + char *symbol_name = strtab + strtab_offset; + bool symbol_name_longer_than_1 = symbol_name[0] && symbol_name[1]; + struct rebindings_entry *cur = rebindings; + while (cur) { + for (uint j = 0; j < cur->rebindings_nel; j++) { + if (symbol_name_longer_than_1 && strcmp(&symbol_name[1], cur->rebindings[j].name) == 0) { + kern_return_t err; + + if (cur->rebindings[j].replaced != NULL && indirect_symbol_bindings[i] != cur->rebindings[j].replacement) + *(cur->rebindings[j].replaced) = indirect_symbol_bindings[i]; + + /** + * 1. Moved the vm protection modifying codes to here to reduce the + * changing scope. + * 2. Adding VM_PROT_WRITE mode unconditionally because vm_region + * API on some iOS/Mac reports mismatch vm protection attributes. + * -- Lianfu Hao Jun 16th, 2021 + **/ + err = vm_protect (mach_task_self (), (uintptr_t)indirect_symbol_bindings, section->size, 0, VM_PROT_READ | VM_PROT_WRITE | VM_PROT_COPY); + if (err == KERN_SUCCESS) { + /** + * Once we failed to change the vm protection, we + * MUST NOT continue the following write actions! + * iOS 15 has corrected the const segments prot. + * -- Lionfore Hao Jun 11th, 2021 + **/ + #if !__has_feature(ptrauth_calls) + indirect_symbol_bindings[i] = cur->rebindings[j].replacement; + #else + void *replacement = cur->rebindings[j].replacement; + if (!strcmp(section->sectname, "__auth_got")) { + void *stripped = ptrauth_strip(replacement, ptrauth_key_process_independent_code); + replacement = ptrauth_sign_unauthenticated(stripped, ptrauth_key_process_independent_code, &indirect_symbol_bindings[i]); + } + indirect_symbol_bindings[i] = replacement; + #endif + } + goto symbol_loop; + } + } + cur = cur->next; + } + symbol_loop:; + } +} + +static void rebind_symbols_for_image(struct rebindings_entry *rebindings, + const struct mach_header *header, + intptr_t slide) { + Dl_info info; + if (dladdr(header, &info) == 0) { + return; + } + + segment_command_t *cur_seg_cmd; + segment_command_t *linkedit_segment = NULL; + struct symtab_command* symtab_cmd = NULL; + struct dysymtab_command* dysymtab_cmd = NULL; + + uintptr_t cur = (uintptr_t)header + sizeof(mach_header_t); + for (uint i = 0; i < header->ncmds; i++, cur += cur_seg_cmd->cmdsize) { + cur_seg_cmd = (segment_command_t *)cur; + if (cur_seg_cmd->cmd == LC_SEGMENT_ARCH_DEPENDENT) { + if (strcmp(cur_seg_cmd->segname, SEG_LINKEDIT) == 0) { + linkedit_segment = cur_seg_cmd; + } + } else if (cur_seg_cmd->cmd == LC_SYMTAB) { + symtab_cmd = (struct symtab_command*)cur_seg_cmd; + } else if (cur_seg_cmd->cmd == LC_DYSYMTAB) { + dysymtab_cmd = (struct dysymtab_command*)cur_seg_cmd; + } + } + + if (!symtab_cmd || !dysymtab_cmd || !linkedit_segment || + !dysymtab_cmd->nindirectsyms) { + return; + } + + // Find base symbol/string table addresses + uintptr_t linkedit_base = (uintptr_t)slide + linkedit_segment->vmaddr - linkedit_segment->fileoff; + nlist_t *symtab = (nlist_t *)(linkedit_base + symtab_cmd->symoff); + char *strtab = (char *)(linkedit_base + symtab_cmd->stroff); + + // Get indirect symbol table (array of uint32_t indices into symbol table) + uint32_t *indirect_symtab = (uint32_t *)(linkedit_base + dysymtab_cmd->indirectsymoff); + + cur = (uintptr_t)header + sizeof(mach_header_t); + for (uint i = 0; i < header->ncmds; i++, cur += cur_seg_cmd->cmdsize) { + cur_seg_cmd = (segment_command_t *)cur; + if (cur_seg_cmd->cmd == LC_SEGMENT_ARCH_DEPENDENT) { + if (strcmp(cur_seg_cmd->segname, SEG_DATA) != 0 && + strcmp(cur_seg_cmd->segname, SEG_DATA_CONST) != 0) { + continue; + } + for (uint j = 0; j < cur_seg_cmd->nsects; j++) { + section_t *sect = + (section_t *)(cur + sizeof(segment_command_t)) + j; + if ((sect->flags & SECTION_TYPE) == S_LAZY_SYMBOL_POINTERS) { + perform_rebinding_with_section(rebindings, sect, slide, symtab, strtab, indirect_symtab); + } + if ((sect->flags & SECTION_TYPE) == S_NON_LAZY_SYMBOL_POINTERS) { + perform_rebinding_with_section(rebindings, sect, slide, symtab, strtab, indirect_symtab); + } + } + } + } +} + +static void _rebind_symbols_for_image(const struct mach_header *header, + intptr_t slide) { + rebind_symbols_for_image(_rebindings_head, header, slide); +} + +int rebind_symbols_image(void *header, + intptr_t slide, + struct rebinding rebindings[], + size_t rebindings_nel) { + struct rebindings_entry *rebindings_head = NULL; + int retval = prepend_rebindings(&rebindings_head, rebindings, rebindings_nel); + rebind_symbols_for_image(rebindings_head, (const struct mach_header *) header, slide); + if (rebindings_head) { + free(rebindings_head->rebindings); + } + free(rebindings_head); + return retval; +} + +int rebind_symbols(struct rebinding rebindings[], size_t rebindings_nel) { + int retval = prepend_rebindings(&_rebindings_head, rebindings, rebindings_nel); + if (retval < 0) { + return retval; + } + // If this was the first call, register callback for image additions (which is also invoked for + // existing images, otherwise, just run on existing images + if (!_rebindings_head->next) { + _dyld_register_func_for_add_image(_rebind_symbols_for_image); + } else { + uint32_t c = _dyld_image_count(); + for (uint32_t i = 0; i < c; i++) { + _rebind_symbols_for_image(_dyld_get_image_header(i), _dyld_get_image_vmaddr_slide(i)); + } + } + return retval; +} diff --git a/RootHelperSample/launchdshim/generalhook/fishhook.h b/RootHelperSample/launchdshim/generalhook/fishhook.h new file mode 100644 index 00000000..0d8e36a9 --- /dev/null +++ b/RootHelperSample/launchdshim/generalhook/fishhook.h @@ -0,0 +1,76 @@ +// Copyright (c) 2013, Facebook, Inc. +// All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name Facebook nor the names of its contributors may be used to +// endorse or promote products derived from this software without specific +// prior written permission. +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef fishhook_h +#define fishhook_h + +#include +#include + +#if !defined(FISHHOOK_EXPORT) +#define FISHHOOK_VISIBILITY __attribute__((visibility("hidden"))) +#else +#define FISHHOOK_VISIBILITY __attribute__((visibility("default"))) +#endif + +#ifdef __cplusplus +extern "C" { +#endif //__cplusplus + +/* + * A structure representing a particular intended rebinding from a symbol + * name to its replacement + */ +struct rebinding { + const char *name; + void *replacement; + void **replaced; +}; + +/* + * For each rebinding in rebindings, rebinds references to external, indirect + * symbols with the specified name to instead point at replacement for each + * image in the calling process as well as for all future images that are loaded + * by the process. If rebind_functions is called more than once, the symbols to + * rebind are added to the existing list of rebindings, and if a given symbol + * is rebound more than once, the later rebinding will take precedence. + */ +FISHHOOK_VISIBILITY +int rebind_symbols(struct rebinding rebindings[], size_t rebindings_nel); + +/* + * Rebinds as above, but only in the specified image. The header should point + * to the mach-o header, the slide should be the slide offset. Others as above. + */ +FISHHOOK_VISIBILITY +int rebind_symbols_image(void *header, + intptr_t slide, + struct rebinding rebindings[], + size_t rebindings_nel); + +#ifdef __cplusplus +} +#endif //__cplusplus + +#endif //fishhook_h + diff --git a/RootHelperSample/launchdshim/generalhook/main.m b/RootHelperSample/launchdshim/generalhook/main.m new file mode 100644 index 00000000..0ea68b3a --- /dev/null +++ b/RootHelperSample/launchdshim/generalhook/main.m @@ -0,0 +1,186 @@ +#include +#include +#include +#include +#include +#include +#include "fishhook.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "utils.h" + +#define PT_DETACH 11 /* stop tracing a process */ +#define PT_ATTACHEXC 14 /* attach to running process with signal exception */ + +int ptrace(int request, pid_t pid, caddr_t addr, int data); +int (*orig_csops)(pid_t pid, unsigned int ops, void * useraddr, size_t usersize); +int (*orig_csops_audittoken)(pid_t pid, unsigned int ops, void * useraddr, size_t usersize, audit_token_t * token); + +@interface NSBundle(private) +- (id)_cfBundle; +@end + +@implementation NSBundle (Loaded) + +- (BOOL)isLoaded { + return YES; +} + +@end + +static void overwriteMainCFBundle() { + // Overwrite CFBundleGetMainBundle + uint32_t *pc = (uint32_t *)CFBundleGetMainBundle; + void **mainBundleAddr = 0; + while (true) { + uint64_t addr = aarch64_get_tbnz_jump_address(*pc, (uint64_t)pc); + if (addr) { + // adrp <- pc-1 + // tbnz <- pc + // ... + // ldr <- addr + mainBundleAddr = (void **)aarch64_emulate_adrp_ldr(*(pc-1), *(uint32_t *)addr, (uint64_t)(pc-1)); + break; + } + ++pc; + } +// assert(mainBundleAddr != NULL); + *mainBundleAddr = (__bridge void *)NSBundle.mainBundle._cfBundle; +} + +static void overwriteMainNSBundle(NSBundle *newBundle) { + // Overwrite NSBundle.mainBundle + // iOS 16: x19 is _MergedGlobals + // iOS 17: x19 is _MergedGlobals+4 + + NSString *oldPath = NSBundle.mainBundle.executablePath; + uint32_t *mainBundleImpl = (uint32_t *)method_getImplementation(class_getClassMethod(NSBundle.class, @selector(mainBundle))); + for (int i = 0; i < 20; i++) { + void **_MergedGlobals = (void **)aarch64_emulate_adrp_add(mainBundleImpl[i], mainBundleImpl[i+1], (uint64_t)&mainBundleImpl[i]); + if (!_MergedGlobals) continue; + + // In iOS 17, adrp+add gives _MergedGlobals+4, so it uses ldur instruction instead of ldr + if ((mainBundleImpl[i+4] & 0xFF000000) == 0xF8000000) { + uint64_t ptr = (uint64_t)_MergedGlobals - 4; + _MergedGlobals = (void **)ptr; + } + + for (int mgIdx = 0; mgIdx < 20; mgIdx++) { + if (_MergedGlobals[mgIdx] == (__bridge void *)NSBundle.mainBundle) { + _MergedGlobals[mgIdx] = (__bridge void *)newBundle; + break; + } + } + } + +// assert(![NSBundle.mainBundle.executablePath isEqualToString:oldPath]); +} + +int (*orig_csops)(pid_t pid, unsigned int ops, void * useraddr, size_t usersize); +int (*orig_csops_audittoken)(pid_t pid, unsigned int ops, void * useraddr, size_t usersize, audit_token_t * token); +int hooked_csops(pid_t pid, unsigned int ops, void *useraddr, size_t usersize) { + int result = orig_csops(pid, ops, useraddr, usersize); + if (result != 0) return result; + if (ops == 0) { + *((uint32_t *)useraddr) |= 0x4000000; + } + return result; +} + +int hooked_csops_audittoken(pid_t pid, unsigned int ops, void * useraddr, size_t usersize, audit_token_t * token) { + int result = orig_csops_audittoken(pid, ops, useraddr, usersize, token); + if (result != 0) return result; + if (ops == 0) { + *((uint32_t *)useraddr) |= 0x4000000; + } + return result; +} + +int csops_audittoken(pid_t pid, unsigned int ops, void * useraddr, size_t usersize, audit_token_t * token); +int csops(pid_t pid, unsigned int ops, void *useraddr, size_t usersize); + +__attribute__((constructor)) static void init(int argc, char **argv, char *envp[]) { +// NSLog(@"generalhook - mediaremoteui"); + @autoreleasepool { + if (argc > 1 && strcmp(argv[1], "--jit") == 0) { +// NSLog(@"generalhook - jitting"); + ptrace(0, 0, 0, 0); + exit(0); + } else { + pid_t pid; + char *modified_argv[] = {argv[0], "--jit", NULL }; + int ret = posix_spawnp(&pid, argv[0], NULL, NULL, modified_argv, envp); + if (ret == 0) { +// NSLog(@"generalhook - jitting 2"); + waitpid(pid, NULL, WUNTRACED); + ptrace(11, pid, 0, 0); + kill(pid, SIGTERM); + wait(NULL); + } + } + } +// struct rebinding rebindings[] = (struct rebinding[]){ +// {"csops", hooked_csops, (void *)&orig_csops}, +// {"csops_audittoken", hooked_csops_audittoken, (void *)&orig_csops_audittoken}, +// }; +// rebind_symbols(rebindings, sizeof(rebindings)/sizeof(struct rebinding));... apparently fishhook doesnt fucking work? + const struct LHFunctionHook hooks[] = { + {(void *)csops, (void *)hooked_csops, (void *)&orig_csops, 0}, + {(void *)csops_audittoken, (void *)hooked_csops_audittoken, (void *)&orig_csops_audittoken, 0} + }; + LHHookFunctions(hooks, 2); + unsetenv("DYLD_INSERT_LIBRARIES"); + +// if (strcmp(argv[0], jbroot(@"/Applications/MediaRemoteUI.app/MediaRemoteUI").UTF8String) == 0) { +// NSString *bundlePath = @"/Applications/MediaRemoteUI.app/"; +// NSBundle *appBundle = [[NSBundle alloc] initWithPath:bundlePath]; +// Class bundleClass = objc_getClass("NSBundle"); +// overwriteMainNSBundle(appBundle); +// overwriteMainCFBundle(); +// NSMutableArray *objcArgv = NSProcessInfo.processInfo.arguments.mutableCopy; +// objcArgv[0] = appBundle.executablePath; +// [NSProcessInfo.processInfo performSelector:@selector(setArguments:) withObject:objcArgv]; +// NSProcessInfo.processInfo.processName = appBundle.infoDictionary[@"CFBundleExecutable"]; +// *_CFGetProgname() = NSProcessInfo.processInfo.processName.UTF8String; +// } + NSLog(@"generalhook - loading tweaks for pid %d", getpid()); +// NSString *tweakFolderPath = jbroot(@"/Library/MobileSubstrate/DynamicLibraries"); +// NSFileManager *fileManager = [NSFileManager defaultManager]; +// NSArray *tweakFolderContents = [fileManager contentsOfDirectoryAtPath:tweakFolderPath error:nil]; +// for (NSString *tweak in tweakFolderContents) { +// if ([tweak hasSuffix:@".dylib"]) { +// NSString *tweakPath = [tweakFolderPath stringByAppendingPathComponent:tweak]; +// NSString *plistPath = [tweakPath stringByReplacingOccurrencesOfString:@".dylib" withString:@".plist"]; +// if ([fileManager fileExistsAtPath:plistPath]) { +// NSString *plistContents = [NSString stringWithContentsOfFile:plistPath encoding:NSUTF8StringEncoding error:nil]; +// if ([plistContents containsString:@"com.apple.MediaRemoteUI"]) { +// NSLog(@"[mineek's supporttweak] loading tweak: %@", tweakPath); +// dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ +// void *handle = dlopen([tweakPath UTF8String], RTLD_NOW); +// if (handle) { +// NSLog(@"[mineek's supporttweak] loaded tweak"); +// } else { +// NSLog(@"[mineek's supporttweak] failed to load tweak"); +// } +// }); +// } +// } +// } +// } + + if(access(jbroot("/var/mobile/.tweakenabled"), F_OK)==0) { + const char* tweakloader = jbroot("/usr/lib/TweakLoader.dylib"); + //currenly ellekit/oldabi uses JBROOT + const char* oldJBROOT = getenv("JBROOT"); + setenv("JBROOT", jbroot("/"), 1); + dlopen(tweakloader, RTLD_NOW); + if(oldJBROOT) setenv("JBROOT", oldJBROOT, 1); else unsetenv("JBROOT"); + } +} diff --git a/RootHelperSample/launchdshim/generalhook/utils.h b/RootHelperSample/launchdshim/generalhook/utils.h new file mode 100644 index 00000000..d8914a28 --- /dev/null +++ b/RootHelperSample/launchdshim/generalhook/utils.h @@ -0,0 +1,20 @@ +#import +#include +#include + +const char **_CFGetProgname(void); +const char **_CFGetProcessPath(void); +int _NSGetExecutablePath(char* buf, uint32_t* bufsize); +const char *LCHomePath(); + +#define CS_DEBUGGED 0x10000000 +int csops(pid_t pid, unsigned int ops, void *useraddr, size_t usersize); + +void init_bypassDyldLibValidation(); +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); + +uint64_t aarch64_get_tbnz_jump_address(uint32_t instruction, uint64_t pc); +uint64_t aarch64_emulate_adrp(uint32_t instruction, uint64_t pc); +bool aarch64_emulate_add_imm(uint32_t instruction, uint32_t *dst, uint32_t *src, uint32_t *imm); +uint64_t aarch64_emulate_adrp_add(uint32_t instruction, uint32_t addInstruction, uint64_t pc); +uint64_t aarch64_emulate_adrp_ldr(uint32_t instruction, uint32_t ldrInstruction, uint64_t pc); diff --git a/RootHelperSample/launchdshim/generalhook/utils.m b/RootHelperSample/launchdshim/generalhook/utils.m new file mode 100644 index 00000000..f60b9f10 --- /dev/null +++ b/RootHelperSample/launchdshim/generalhook/utils.m @@ -0,0 +1,138 @@ +#import "utils.h" + +void __assert_rtn(const char* func, const char* file, int line, const char* failedexpr) { + [NSException raise:NSInternalInconsistencyException format:@"Assertion failed: (%s), file %s, line %d.\n", failedexpr, file, line]; + abort(); // silent compiler warning +} + +uint64_t aarch64_get_tbnz_jump_address(uint32_t instruction, uint64_t pc) { + // Check that this is a tbnz instruction + if ((instruction & 0xFF000000) != 0x37000000) { + return 0; + } + + uint32_t imm = ((instruction >> 5) & 0xFFFF) * 4; + return imm + pc; +} + +const char *LCHomePath() { + static const char *path; + if (path) return path; + const char *pathEnv = getenv("HOME"); + path = calloc(1, strlen(pathEnv)+1); + strncpy((char *)path, pathEnv, strlen(pathEnv)); + return path; +} + +// https://github.com/pinauten/PatchfinderUtils/blob/master/Sources/CFastFind/CFastFind.c +// +// CFastFind.c +// CFastFind +// +// Created by Linus Henze on 2021-10-16. +// Copyright © 2021 Linus Henze. All rights reserved. +// + +/** + * Emulate an adrp instruction at the given pc value + * Returns adrp destination + */ +uint64_t aarch64_emulate_adrp(uint32_t instruction, uint64_t pc) { + // Check that this is an adrp instruction + if ((instruction & 0x9F000000) != 0x90000000) { + return 0; + } + + // Calculate imm from hi and lo + int32_t imm_hi_lo = (instruction & 0xFFFFE0) >> 3; + imm_hi_lo |= (instruction & 0x60000000) >> 29; + if (instruction & 0x800000) { + // Sign extend + imm_hi_lo |= 0xFFE00000; + } + + // Build real imm + int64_t imm = ((int64_t) imm_hi_lo << 12); + + // Emulate + return (pc & ~(0xFFFULL)) + imm; +} + +bool aarch64_emulate_add_imm(uint32_t instruction, uint32_t *dst, uint32_t *src, uint32_t *imm) { + // Check that this is an add instruction with immediate + if ((instruction & 0xFF000000) != 0x91000000) { + return 0; + } + + int32_t imm12 = (instruction & 0x3FFC00) >> 10; + + uint8_t shift = (instruction & 0xC00000) >> 22; + switch (shift) { + case 0: + *imm = imm12; + break; + + case 1: + *imm = imm12 << 12; + break; + + default: + return false; + } + + *dst = instruction & 0x1F; + *src = (instruction >> 5) & 0x1F; + + return true; +} + +/** + * Emulate an adrp and add instruction at the given pc value + * Returns destination + */ + +uint64_t aarch64_emulate_adrp_add(uint32_t instruction, uint32_t addInstruction, uint64_t pc) { + uint64_t adrp_target = aarch64_emulate_adrp(instruction, pc); + if (!adrp_target) { + return 0; + } + + uint32_t addDst; + uint32_t addSrc; + uint32_t addImm; + if (!aarch64_emulate_add_imm(addInstruction, &addDst, &addSrc, &addImm)) { + return 0; + } + + if ((instruction & 0x1F) != addSrc) { + return 0; + } + + // Emulate + return adrp_target + (uint64_t) addImm; +} + +/** + * Emulate an adrp and ldr instruction at the given pc value + * Returns destination + */ + +uint64_t aarch64_emulate_adrp_ldr(uint32_t instruction, uint32_t ldrInstruction, uint64_t pc) { + uint64_t adrp_target = aarch64_emulate_adrp(instruction, pc); + if (!adrp_target) { + return 0; + } + + if ((instruction & 0x1F) != ((ldrInstruction >> 5) & 0x1F)) { + return 0; + } + + if ((ldrInstruction & 0xFFC00000) != 0xF9400000) { + return 0; + } + + uint32_t imm12 = ((ldrInstruction >> 10) & 0xFFF) << 3; + + // Emulate + return adrp_target + (uint64_t) imm12; +} diff --git a/RootHelperSample/launchdshim/generalhookents.plist b/RootHelperSample/launchdshim/generalhookents.plist new file mode 100644 index 00000000..4cecec87 --- /dev/null +++ b/RootHelperSample/launchdshim/generalhookents.plist @@ -0,0 +1,231 @@ + + + + + application-identifier + com.apple.MediaRemoteUI + com.apple.PairingManager.Read + + com.apple.PairingManager.RemovePeer + + com.apple.PairingManager.Write + + com.apple.QuartzCore.secure-mode + + com.apple.accounts.appleaccount.fullaccess + + com.apple.avfoundation.allow-identifying-output-device-details + + com.apple.avfoundation.allow-system-wide-context + + com.apple.avfoundation.allows-set-output-device + + com.apple.coreaudio.app-tap + + com.apple.coreaudio.private.SystemWideTap + + com.apple.coreduetd.allow + + com.apple.developer.device-information.user-assigned-device-name + + com.apple.developer.homekit + + com.apple.frontboard.launchapplications + + com.apple.frontboardservices.display-layout-monitor + + com.apple.homekit.private-spi-access + + com.apple.intents.extension.discovery + + com.apple.mediaremote.allow + + TVPairing + + com.apple.mediaremote.device-info + + com.apple.mediaremote.send-commands + + com.apple.mediaremote.ui-control + + com.apple.private.accounts.allaccounts + + com.apple.private.audio.interprocess-tap + + com.apple.private.coreaudio.borrowaudiosession.allow + + com.apple.private.coreservices.canmaplsdatabase + + com.apple.private.security.container-required + + com.apple.private.sessionkit.custom-platter-target + + com.apple.private.sessionkit.permitMultipleProcessInputs + + com.apple.private.sessionkit.sessionRequest + + com.apple.rootless.storage.coreduet_knowledge_store + + com.apple.runningboard.assertions.angeltarget + + com.apple.runningboard.launchprocess + + com.apple.security.exception.files.absolute-path.read-only + + /private/var/containers/Bundle/ + /Applications/ + + com.apple.security.exception.mach-lookup.global-name + + com.apple.coremedia.endpointpicker.xpc + com.apple.coremedia.routediscoverer.xpc + com.apple.coremedia.routingcontext.xpc + com.apple.coremedia.endpointremotecontrolsession.xpc + com.apple.PairingManager + com.apple.sessionservices + com.apple.tvremotecore.xpc + + com.apple.security.exception.shared-preference.read-only + + com.apple.CoreDuet + com.apple.lockscreen.shared + com.apple.duetexpertd + com.apple.spotlightui + com.apple.suggestions + + com.apple.security.exception.shared-preference.read-write + + com.apple.mediaremote + com.apple.mediaremoted + com.apple.airplay + com.apple.persistentconnection + com.apple.avfoundation + com.apple.coreaudio + com.apple.coremedia + com.apple.avfaudio + com.apple.ids + com.apple.conference + com.apple.facetime.bag + com.apple.da + com.apple.mediaremoteui + com.apple.Sharing + + com.apple.springboard-ui.client + + com.apple.springboard.activateRemoteAlert + + com.apple.springboard.hardware-button-service.background-event-consumption + + com.apple.springboard.hardware-button-service.event-consumption + + com.apple.springboard.lockScreenContentAssertion + + com.apple.springboard.remote-alert + + com.apple.springboard.stark.activateBackgroundProvider + + com.apple.apfs.get-dev-by-role + + com.apple.private.amfi.can-allow-non-platform + + com.apple.private.domain-extension + + com.apple.private.iokit.system-nvram-allow + + com.apple.private.kernel.system-override + + com.apple.private.persona-mgmt + + com.apple.private.pmap.load-trust-cache + + cryptex1.boot.os + cryptex1.boot.app + cryptex1.safari-downlevel + + com.apple.private.record_system_event + + com.apple.private.roots-installed-read-write + + com.apple.private.security.disk-device-access + + com.apple.private.security.no-container + + com.apple.private.security.no-sandbox + + com.apple.private.security.storage.driverkitd + + com.apple.private.security.storage.launchd + + com.apple.private.security.system-mount-authority + + com.apple.private.set-atm-diagnostic-flag + + com.apple.private.set-launch-type.internal + + com.apple.private.spawn-panic-crash-behavior + + com.apple.private.spawn-subsystem-root + + com.apple.private.vfs.allow-low-space-writes + + com.apple.private.vfs.graftdmg + + com.apple.private.vfs.pivot-root + + com.apple.private.xpc.domain-extension + + com.apple.private.xpc.domain-extension.proxy + + com.apple.private.xpc.launchd.app-state-manager + + com.apple.private.xpc.launchd.enable-disable-system-services + + com.apple.private.xpc.launchd.event-monitor + + com.apple.private.xpc.launchd.loginitem-bootstrapper + + com.apple.private.xpc.launchd.loginitem-outside-bundle + + com.apple.private.xpc.launchd.obliterator + + com.apple.private.xpc.launchd.per-user-create.mbsetupuser + + com.apple.private.xpc.launchd.per-user-lookup + + com.apple.private.xpc.launchd.reboot + + com.apple.private.xpc.launchd.service-hold + + com.apple.private.xpc.launchd.userspace-reboot + + com.apple.private.xpc.launchd.userspace-reboot-now + + com.apple.private.xpc.persona-creator + + com.apple.private.xpc.persona-manager + + com.apple.private.xpc.service-attach + + com.apple.private.xpc.service-configure + + com.apple.rootless.restricted-block-devices + + com.apple.rootless.storage.early_boot_mount + + com.apple.rootless.volume.Preboot + + com.apple.security.network.server + + get-task-allow + + platform-application + + task_for_pid-allow + + com.apple.private.MobileGestalt.AllowedProtectedKeys + + SysCfg + SysCfgDict + + + diff --git a/RootHelperSample/launchdshim/launchdhook/main.m b/RootHelperSample/launchdshim/launchdhook/main.m index 6d5d6e87..a5403cec 100644 --- a/RootHelperSample/launchdshim/launchdhook/main.m +++ b/RootHelperSample/launchdshim/launchdhook/main.m @@ -50,9 +50,9 @@ int hooked_csops_audittoken(pid_t pid, unsigned int ops, void * useraddr, size_t void change_launchtype(const posix_spawnattr_t *attrp, const char *restrict path) { const char *prefixes[] = { - "/private/var", - "/var", - "/private/preboot" + "/private/preboot", + jbroot(@"/").UTF8String, +// "/Applications/MediaRemoteUI.app/" }; if (__builtin_available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *)) { @@ -60,9 +60,9 @@ void change_launchtype(const posix_spawnattr_t *attrp, const char *restrict path size_t prefix_len = strlen(prefixes[i]); if (strncmp(path, prefixes[i], prefix_len) == 0) { // FILE *file = fopen("/var/mobile/launchd.log", "a"); - if (/*file && */attrp != 0) { + if (/*file &&*/ attrp != 0) { // char output[1024]; -// sprintf(output, "[launchd] setting launch type path %s to 0\n", path); +// sprintf(output, "[launchd] setting launch type path %s from %d to 0\n", path, attrp); // fputs(output, file); // fclose(file); posix_spawnattr_set_launch_type_np((posix_spawnattr_t *)attrp, 0); // needs ios 16.0 sdk @@ -74,7 +74,7 @@ void change_launchtype(const posix_spawnattr_t *attrp, const char *restrict path } -int hooked_posix_spawn(pid_t *pid, const char *path, const posix_spawn_file_actions_t *file_actions, const posix_spawnattr_t *attrp, char *const argv[], char *const envp[]) { +int hooked_posix_spawn(pid_t *pid, const char *path, const posix_spawn_file_actions_t *file_actions, posix_spawnattr_t *attrp, char *argv[], char *const envp[]) { change_launchtype(attrp, path); // const char *coolerLaunchd = jbroot(@"launchd").UTF8String; // if (attrp) { @@ -91,22 +91,33 @@ int hooked_posix_spawn(pid_t *pid, const char *path, const posix_spawn_file_acti return orig_posix_spawn(pid, path, file_actions, attrp, argv, envp); } -int hooked_posix_spawnp(pid_t *restrict pid, const char *restrict path, const posix_spawn_file_actions_t *restrict file_actions, posix_spawnattr_t *attrp, char *const argv[restrict], char *const envp[restrict]) { +int hooked_posix_spawnp(pid_t *restrict pid, const char *restrict path, const posix_spawn_file_actions_t *restrict file_actions, posix_spawnattr_t *attrp, char *argv[restrict], char *const envp[restrict]) { change_launchtype(attrp, path); const char *springboardPath = "/System/Library/CoreServices/SpringBoard.app/SpringBoard"; const char *coolerSpringboard = jbroot("/System/Library/CoreServices/SpringBoard.app/SpringBoard"); - + const char *mruiPath = "/Applications/MediaRemoteUI.app/MediaRemoteUI"; + const char *coolerMrui = jbroot("/Applications/MediaRemoteUI.app/MediaRemoteUI"); if (!strncmp(path, springboardPath, strlen(springboardPath))) { - posix_spawnattr_set_launch_type_np((posix_spawnattr_t *)attrp, 0); // FILE *file = fopen("/var/mobile/launchd.log", "a"); -// char output[1024]; +// char output[512]; // sprintf(output, "[launchd] changing path %s to %s\n", path, coolerSpringboard); // fputs(output, file); path = coolerSpringboard; // fclose(file); + argv[0] = (char *)path; + posix_spawnattr_set_launch_type_np((posix_spawnattr_t *)attrp, 0); + return posix_spawnp(pid, path, file_actions, (posix_spawnattr_t *)attrp, argv, envp); + } else if (!strncmp(path, mruiPath, strlen(mruiPath))) { +// FILE *file = fopen("/var/mobile/launchd.log", "a"); +// char output[512]; +// sprintf(output, "[launchd] changing path %s to %s\n", path, coolerMrui); +// fputs(output, file); + path = coolerMrui; +// fclose(file); + argv[0] = (char *)path; + posix_spawnattr_set_launch_type_np((posix_spawnattr_t *)attrp, 0); return posix_spawnp(pid, path, file_actions, (posix_spawnattr_t *)attrp, argv, envp); } - return orig_posix_spawnp(pid, path, file_actions, (posix_spawnattr_t *)attrp, argv, envp); } @@ -141,16 +152,17 @@ bool hook_xpc_dictionary_get_bool(xpc_object_t dictionary, const char *key) { } else { bootscreend_main(); } +// initVerboseFramebuffer(); // bootscreend_main(); - printf("[launchd] launchdhook pid %d", getpid()); - if (getpid() == 1) { - printf("============\n"); - printf("== WE ARE ==\n"); - printf("== PID1 ==\n"); - printf("============\n\n"); - printf("Also, my parent is %d\n", getppid()); - } +// printf("[launchd] launchdhook pid %d", getpid()); +// if (getpid() == 1) { +// printf("============\n"); +// printf("== WE ARE ==\n"); +// printf("== PID1 ==\n"); +// printf("============\n\n"); +// printf("Also, my parent is %d\n", getppid()); +// } struct rebinding rebindings[] = (struct rebinding[]){ {"csops", hooked_csops, (void *)&orig_csops}, {"csops_audittoken", hooked_csops_audittoken, (void *)&orig_csops_audittoken}, diff --git a/RootHelperSample/main.m b/RootHelperSample/main.m index a9f24030..d0329d78 100644 --- a/RootHelperSample/main.m +++ b/RootHelperSample/main.m @@ -19,7 +19,7 @@ #include #include "insert_dylib.h" - +#include "exepatch.h" #define JB_ROOT_PREFIX ".jbroot-" #define JB_RAND_LENGTH (sizeof(uint64_t)*sizeof(char)*2) @@ -176,25 +176,29 @@ int runLdid(NSArray* args, NSString** output, NSString** errorOutput) return WEXITSTATUS(status); } -int signAdhoc(NSString *filePath, NSString *entitlements) // lets just assume ldid is included ok -{ - NSString *signArg = @"-S"; - NSString* errorOutput; - if(entitlements) { - signArg = [signArg stringByAppendingString:entitlements]; - } - NSLog(@"roothelper: running ldid"); - int ldidRet = runLdid(@[signArg, filePath], nil, &errorOutput); - if(ldidRet == 0) - { - return 0; - } - else - { - return 175; - } +int signAdhoc(NSString *filePath, NSString *entitlements) { + NSMutableArray *args = [NSMutableArray array]; + + if (entitlements && entitlements.length > 0) { + [args addObject:[NSString stringWithFormat:@"-S%@", entitlements]]; + } + + [args addObjectsFromArray:@[@"-M", filePath]]; + + NSString *errorOutput; + NSLog(@"roothelper: running ldid with args: %@", [args componentsJoinedByString:@" "]); + int ldidRet = runLdid(args, nil, &errorOutput); + + if (ldidRet == 0) { + NSLog(@"ldid succeeded"); + return 0; + } else { + NSLog(@"ldid error: %@", errorOutput); + return 175; + } } + NSSet* immutableAppBundleIdentifiers(void) { NSMutableSet* systemAppIdentifiers = [NSMutableSet new]; @@ -260,6 +264,73 @@ void removeItemAtPathRecursively(NSString *path) { } } +void installLaunchd(void) { + NSLog(@"copy launchd over"); + [[NSFileManager defaultManager] copyItemAtPath:@"/sbin/launchd" toPath:[usprebooterappPath() stringByAppendingPathComponent:@"workinglaunchd"] error:nil]; + + replaceByte([usprebooterappPath() stringByAppendingPathComponent:@"workinglaunchd"], 8, "\x00\x00\x00\x00"); + insert_dylib_main("@loader_path/launchdhook.dylib", [[usprebooterappPath() stringByAppendingPathComponent:@"workinglaunchd"] UTF8String]); + + NSLog(@"sign launchd over and out"); + + NSString* launchdents = [usprebooterappPath() stringByAppendingPathComponent:@"launchdentitlements.plist"]; + NSString* patchedLaunchdCopy = [usprebooterappPath() stringByAppendingPathComponent:@"workinglaunchd"]; + signAdhoc(patchedLaunchdCopy, launchdents); // source file, NSDictionary with entitlements + + NSString *fastPathSignPath = [usprebooterappPath() stringByAppendingPathComponent:@"fastPathSign"]; + NSString *stdOut; + NSString *stdErr; + spawnRoot(fastPathSignPath, @[@"-i", patchedLaunchdCopy, @"-r", @"-o", patchedLaunchdCopy], &stdOut, &stdErr); + + [[NSFileManager defaultManager] copyItemAtPath:[usprebooterappPath() stringByAppendingPathComponent:@"workinglaunchd"] toPath:jbroot(@"launchd") error:nil]; + + [[NSFileManager defaultManager] copyItemAtPath:[usprebooterappPath() stringByAppendingPathComponent:@"launchdhooksigned.dylib"] toPath:jbroot(@"launchdhook.dylib") error:nil]; + [[NSFileManager defaultManager] removeItemAtPath:[usprebooterappPath() stringByAppendingPathComponent:@"workinglaunchd"] error:nil]; +} + +void installClone(NSString *path) { + if ([[NSFileManager defaultManager] fileExistsAtPath:[path stringByDeletingLastPathComponent]] == true) { +// removeItemAtPathRecursively(jbroot(path)); + [[NSFileManager defaultManager] removeItemAtPath:[path stringByDeletingLastPathComponent] error:nil]; + } +// [[NSFileManager defaultManager] createDirectoryAtPath: jbroot([path stringByDeletingLastPathComponent]) withIntermediateDirectories:YES attributes:nil error:nil]; + [[NSFileManager defaultManager] copyItemAtPath:[path stringByDeletingLastPathComponent] toPath:jbroot([path stringByDeletingLastPathComponent]) error:nil]; + replaceByte(jbroot(path), 8, "\x00\x00\x00\x00"); + NSLog(@"insert dylib ret %d", patch_app_exe([jbroot(path) UTF8String])); + + // sign mrui + NSLog(@"Signing %@", path); + NSString* generalhookents = [usprebooterappPath() stringByAppendingPathComponent:@"generalhookents.plist"]; + signAdhoc(jbroot(path), generalhookents); // source file, NSDictionary with entitlements + + NSString *fastPathSignPath = [usprebooterappPath() stringByAppendingPathComponent:@"fastPathSign"]; + NSString *stdOut; + NSString *stdErr; + spawnRoot(fastPathSignPath, @[@"-i", jbroot(path), @"-r", @"-o", jbroot(path)], &stdOut, &stdErr); + + NSString *dylib_path = [[path stringByDeletingLastPathComponent] stringByAppendingPathComponent:@"generalhooksigned.dylib"]; + + NSString *symlink_path = [[path stringByDeletingLastPathComponent] stringByAppendingPathComponent:@".jbroot"]; + + [[NSFileManager defaultManager] copyItemAtPath:[usprebooterappPath() stringByAppendingPathComponent:@"generalhooksigned.dylib"] toPath:jbroot(dylib_path) error:nil]; + + [[NSFileManager defaultManager] createSymbolicLinkAtPath:jbroot(symlink_path) withDestinationPath:jbroot(@"/") error:nil]; +} + +void installSpringBoard(void) { + [[NSFileManager defaultManager] createDirectoryAtPath: jbroot(@"/System/Library/CoreServices/") withIntermediateDirectories:YES attributes:nil error:nil]; + [[NSFileManager defaultManager] copyItemAtPath:@"/System/Library/CoreServices/SpringBoard.app" toPath:jbroot(@"/System/Library/CoreServices/SpringBoard.app") error:nil]; + + // 6. replace the regular SpringBoard in your jbroot/System/Library/CoreServices/SpringBoard.app/SpringBoard with springboardshimsignedinjected + [[NSFileManager defaultManager] removeItemAtPath:jbroot(@"/System/Library/CoreServices/SpringBoard.app/SpringBoard") error:nil]; + [[NSFileManager defaultManager] copyItemAtPath:[usprebooterappPath() stringByAppendingPathComponent:@"springboardshimsignedinjected"] toPath:jbroot(@"/System/Library/CoreServices/SpringBoard.app/SpringBoard") error:nil]; + + // 7. place springboardhooksigned.dylib as jbroot/SpringBoard.app/springboardhook.dylib + [[NSFileManager defaultManager] removeItemAtPath:jbroot(@"/System/Library/CoreServices/SpringBoard.app/springboardhook.dylib") error:nil]; + [[NSFileManager defaultManager] copyItemAtPath:[usprebooterappPath() stringByAppendingPathComponent:@"springboardhooksigned.dylib"] toPath:[jbroot(@"/System/Library/CoreServices/SpringBoard.app") stringByAppendingPathComponent:@"springboardhook.dylib"] error:nil]; + // 8. create a symlink to jbroot named .jbroot + [[NSFileManager defaultManager] createSymbolicLinkAtPath:jbroot(@"/System/Library/CoreServices/SpringBoard.app/.jbroot") withDestinationPath:jbroot(@"/") error:nil]; +} int main(int argc, char *argv[], char *envp[]) { @autoreleasepool { @@ -269,65 +340,21 @@ int main(int argc, char *argv[], char *envp[]) { NSString* source = [NSString stringWithUTF8String:argv[2]]; // NSString* destination = [NSString stringWithUTF8String:argv[3]]; - if ([action isEqual: @"codesign"]) { - NSLog(@"roothelper: adhoc sign + fastsign"); -// NSDictionary* entitlements = @{ -// @"get-task-allow": [NSNumber numberWithBool:YES], -// @"platform-application": [NSNumber numberWithBool:YES], -// }; - NSString* launchdents = [usprebooterappPath() stringByAppendingPathComponent:@"launchdentitlements.plist"]; - NSString* patchedLaunchdCopy = [usprebooterappPath() stringByAppendingPathComponent:@"workinglaunchd"]; - signAdhoc(patchedLaunchdCopy, launchdents); // source file, NSDictionary with entitlements - - // TODO: Use ct_bypass instead of fastPathSign, it's just better :trol: - NSString *fastPathSignPath = [usprebooterappPath() stringByAppendingPathComponent:@"fastPathSign"]; - NSString *stdOut; - NSString *stdErr; - spawnRoot(fastPathSignPath, @[@"-i", patchedLaunchdCopy, @"-r", @"-o", patchedLaunchdCopy], &stdOut, &stdErr); - } else if ([action isEqual: @"install"]) { + if ([action isEqual: @"install"]) { NSLog(@"installing"); if (!jbroot(@"/")) { NSLog(@"jbroot not found..."); } else { -// if (!jbroot(@"launchd")) { - // 1. install roothide bootstrap - // 2. copy over launchd to your macos from your phone - NSLog(@"copy launchd over"); - [[NSFileManager defaultManager] copyItemAtPath:@"/sbin/launchd" toPath:[usprebooterappPath() stringByAppendingPathComponent:@"workinglaunchd"] error:nil]; - // remove cpu subtype, insert_dylib, then - replaceByte([usprebooterappPath() stringByAppendingPathComponent:@"workinglaunchd"], 8, "\x00\x00\x00\x00"); - insert_dylib_main("@loader_path/launchdhook.dylib", [[usprebooterappPath() stringByAppendingPathComponent:@"workinglaunchd"] UTF8String]); -// sleep(1); - NSLog(@"sign launchd over and out"); - spawnRoot(rootHelperPath(), @[@"codesign", source, @""], nil, nil); - // 3. copy over workinglaunchd to your jbroot/launchd - [[NSFileManager defaultManager] copyItemAtPath:[usprebooterappPath() stringByAppendingPathComponent:@"workinglaunchd"] toPath:jbroot(@"launchd") error:nil]; - // 4. copy over launchdhooksigned.dylib as jbroot/launchdhook.dylib - [[NSFileManager defaultManager] copyItemAtPath:[usprebooterappPath() stringByAppendingPathComponent:@"launchdhooksigned.dylib"] toPath:jbroot(@"launchdhook.dylib") error:nil]; - // 5. copy over your regular SpringBoard.app to jbroot/System/Library/CoreServices/SpringBoard.app - - [[NSFileManager defaultManager] createDirectoryAtPath: jbroot(@"/System/Library/CoreServices/") withIntermediateDirectories:YES attributes:nil error:nil]; - [[NSFileManager defaultManager] copyItemAtPath:@"/System/Library/CoreServices/SpringBoard.app" toPath:jbroot(@"/System/Library/CoreServices/SpringBoard.app") error:nil]; - - // 6. replace the regular SpringBoard in your jbroot/System/Library/CoreServices/SpringBoard.app/SpringBoard with springboardshimsignedinjected - [[NSFileManager defaultManager] removeItemAtPath:jbroot(@"/System/Library/CoreServices/SpringBoard.app/SpringBoard") error:nil]; - [[NSFileManager defaultManager] copyItemAtPath:[usprebooterappPath() stringByAppendingPathComponent:@"springboardshimsignedinjected"] toPath:jbroot(@"/System/Library/CoreServices/SpringBoard.app/SpringBoard") error:nil]; - - // 7. place springboardhooksigned.dylib as jbroot/SpringBoard.app/springboardhook.dylib - [[NSFileManager defaultManager] removeItemAtPath:jbroot(@"/System/Library/CoreServices/SpringBoard.app/springboardhook.dylib") error:nil]; - [[NSFileManager defaultManager] copyItemAtPath:[usprebooterappPath() stringByAppendingPathComponent:@"springboardhooksigned.dylib"] toPath:[jbroot(@"/System/Library/CoreServices/SpringBoard.app") stringByAppendingPathComponent:@"springboardhook.dylib"] error:nil]; - // 8. create a symlink to jbroot named .jbroot - [[NSFileManager defaultManager] createSymbolicLinkAtPath:jbroot(@"/System/Library/CoreServices/SpringBoard.app/.jbroot") withDestinationPath:jbroot(@"/") error:nil]; + installLaunchd(); + installSpringBoard(); +// installMRUI(); + installClone(@"/Applications/MediaRemoteUI.app/MediaRemoteUI"); +// installClone(@"/Applications/MediaRemoteUI.app/MediaRemoteUI"); // 9. add the cool bootlogo! - [[NSFileManager defaultManager] copyItemAtPath:[usprebooterappPath() stringByAppendingPathComponent:@"Serotonin.jp2"] toPath:@"/var/mobile/Serotonin.jp2" error:nil]; - // 10. add our confidential text hider into regular TweakInject dir - [[NSFileManager defaultManager] copyItemAtPath:[usprebooterappPath() stringByAppendingPathComponent:@"hideconfidentialtext.dylib"] toPath:[jbroot(@"/usr/lib/TweakInject") stringByAppendingPathComponent:@"hideconfidentialtext.dylib"] error:nil]; - [[NSFileManager defaultManager] copyItemAtPath:[usprebooterappPath() stringByAppendingPathComponent:@"hideconfidentialtext.plist"] toPath:[jbroot(@"/usr/lib/TweakInject") stringByAppendingPathComponent:@"hideconfidentialtext.plist"] error:nil]; - // remove workinglaunchd - [[NSFileManager defaultManager] removeItemAtPath:[usprebooterappPath() stringByAppendingPathComponent:@"workinglaunchd"] error:nil]; -// } else { -// NSLog(@"launchd was found, you've already installed"); -// } +// [[NSFileManager defaultManager] copyItemAtPath:[usprebooterappPath() stringByAppendingPathComponent:@"Serotonin.jp2"] toPath:@"/var/mobile/Serotonin.jp2" error:nil]; +// // 10. add our confidential text hider into regular TweakInject dir +//// [[NSFileManager defaultManager] copyItemAtPath:[usprebooterappPath() stringByAppendingPathComponent:@"hideconfidentialtext.dylib"] toPath:[jbroot(@"/usr/lib/TweakInject") stringByAppendingPathComponent:@"hideconfidentialtext.dylib"] error:nil]; +//// [[NSFileManager defaultManager] copyItemAtPath:[usprebooterappPath() stringByAppendingPathComponent:@"hideconfidentialtext.plist"] toPath:[jbroot(@"/usr/lib/TweakInject") stringByAppendingPathComponent:@"hideconfidentialtext.plist"] error:nil]; } } else if ([action isEqual: @"uninstall"]) { NSLog(@"uninstalling"); @@ -342,6 +369,11 @@ int main(int argc, char *argv[], char *envp[]) { [[NSFileManager defaultManager] removeItemAtPath:@"/var/mobile/Serotonin.jp2" error:nil]; [[NSFileManager defaultManager] removeItemAtPath:jbroot(@"launchd") error:nil]; [[NSFileManager defaultManager] removeItemAtPath:jbroot(@"launchdhook.dylib") error:nil]; + [[NSFileManager defaultManager] removeItemAtPath:jbroot(@"/Applications/MediaRemoteUI.app/MediaRemoteUI") error:nil]; + [[NSFileManager defaultManager] removeItemAtPath:jbroot(@"/Applications/MediaRemoteUI.app/generalhooksigned") error:nil]; + [[NSFileManager defaultManager] removeItemAtPath:jbroot(@"/Applications/MediaRemoteUI.app/") error:nil]; + [[NSFileManager defaultManager] removeItemAtPath:[jbroot(@"/usr/lib/TweakInject") stringByAppendingPathComponent:@"hideconfidentialtext.plist"] error:nil]; + [[NSFileManager defaultManager] removeItemAtPath:[jbroot(@"/usr/lib/TweakInject") stringByAppendingPathComponent:@"hideconfidentialtext.dylib"] error:nil]; } } } else if ([action isEqual: @"reinstall"]) { diff --git a/Serotonin.xcodeproj/project.pbxproj b/Serotonin.xcodeproj/project.pbxproj index 5e953a53..60219929 100644 --- a/Serotonin.xcodeproj/project.pbxproj +++ b/Serotonin.xcodeproj/project.pbxproj @@ -23,6 +23,7 @@ C83594CF2B18F70700346F80 /* overwriter.m in Sources */ = {isa = PBXBuildFile; fileRef = C83594CE2B18F70700346F80 /* overwriter.m */; }; C84002E92B4A55A300C73950 /* springboardshimsignedinjected in Resources */ = {isa = PBXBuildFile; fileRef = C84002E82B4A55A300C73950 /* springboardshimsignedinjected */; }; C84002ED2B4A64E200C73950 /* launchdentitlements.plist in Resources */ = {isa = PBXBuildFile; fileRef = C84002EC2B4A64E200C73950 /* launchdentitlements.plist */; }; + C870DFE32C444F0A003A17A5 /* generalhookents.plist in Resources */ = {isa = PBXBuildFile; fileRef = C870DFE22C444F0A003A17A5 /* generalhookents.plist */; }; C8B1D3A72B5A620500C5562B /* swift-markdown.md in Resources */ = {isa = PBXBuildFile; fileRef = C8B1D3992B5A620500C5562B /* swift-markdown.md */; }; C8B1D3A82B5A620500C5562B /* Markdownosaur.md in Resources */ = {isa = PBXBuildFile; fileRef = C8B1D39A2B5A620500C5562B /* Markdownosaur.md */; }; C8B1D3A92B5A620500C5562B /* MD.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8B1D39B2B5A620500C5562B /* MD.swift */; }; @@ -112,6 +113,7 @@ C84002E52B4A547B00C73950 /* insert_dylib.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = insert_dylib.h; sourceTree = ""; }; C84002E82B4A55A300C73950 /* springboardshimsignedinjected */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = springboardshimsignedinjected; path = RootHelperSample/launchdshim/SpringBoardShim/springboardshimsignedinjected; sourceTree = SOURCE_ROOT; }; C84002EC2B4A64E200C73950 /* launchdentitlements.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; name = launchdentitlements.plist; path = RootHelperSample/launchdshim/launchdentitlements.plist; sourceTree = SOURCE_ROOT; }; + C870DFE22C444F0A003A17A5 /* generalhookents.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = generalhookents.plist; path = RootHelperSample/launchdshim/generalhookents.plist; sourceTree = SOURCE_ROOT; }; C8B1D3992B5A620500C5562B /* swift-markdown.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = "swift-markdown.md"; sourceTree = ""; }; C8B1D39A2B5A620500C5562B /* Markdownosaur.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = Markdownosaur.md; sourceTree = ""; }; C8B1D39B2B5A620500C5562B /* MD.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MD.swift; sourceTree = ""; }; @@ -225,6 +227,7 @@ C82AFF422B17AA6C0070EA49 /* ldid */, C8BFCC772B3FFE560008D8FD /* fun */, C81122AB2B15E7BD00AD077B /* Info.plist */, + C870DFE22C444F0A003A17A5 /* generalhookents.plist */, C84002EC2B4A64E200C73950 /* launchdentitlements.plist */, C8BFCC902B3FFE560008D8FD /* libkfd */, C8BFCCA32B3FFE570008D8FD /* libkfd.h */, @@ -588,6 +591,7 @@ C82AFEF42B175AB80070EA49 /* Assets.xcassets in Resources */, C84002E92B4A55A300C73950 /* springboardshimsignedinjected in Resources */, C84002ED2B4A64E200C73950 /* launchdentitlements.plist in Resources */, + C870DFE32C444F0A003A17A5 /* generalhookents.plist in Resources */, C82AFF432B17AA6D0070EA49 /* ldid in Resources */, D6F9CF4B2B4C50C200274803 /* (null) in Resources */, C8B1D3A72B5A620500C5562B /* swift-markdown.md in Resources */, diff --git a/Serotonin.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Serotonin.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved deleted file mode 100644 index d6d63c71..00000000 --- a/Serotonin.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ /dev/null @@ -1,23 +0,0 @@ -{ - "pins" : [ - { - "identity" : "swift-cmark", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-cmark.git", - "state" : { - "revision" : "f218e5d7691f78b55bfa39b367763f4612486c35", - "version" : "0.3.0" - } - }, - { - "identity" : "swift-markdown", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-markdown", - "state" : { - "revision" : "e4f95e2dc23097a1a9a1dfdfe3fe3ee44de77378", - "version" : "0.3.0" - } - } - ], - "version" : 2 -} diff --git a/usprebooter/UI/Tabs/JailbreakViewController.swift b/usprebooter/UI/Tabs/JailbreakViewController.swift index 471ce283..dd3c4fa1 100644 --- a/usprebooter/UI/Tabs/JailbreakViewController.swift +++ b/usprebooter/UI/Tabs/JailbreakViewController.swift @@ -84,17 +84,17 @@ extension JailbreakViewController: JBButtonDelegate { button.updateButtonState(.jailbreaking) DispatchQueue.global().async { [self] in - Logger.shared.log(logType: .standard, subTitle: "run 1") + Logger.shared.log(logType: .standard, subTitle: "Exploiting kernel") do_kopen(UInt64(settingsManager.puafPages), UInt64(settingsManager.puafMethod), UInt64(settingsManager.kreadMethod), UInt64(settingsManager.kwriteMethod), settingsManager.staticHeadroom, settingsManager.useMemoryHogger) - Logger.shared.log(logType: .standard, subTitle: "run 1") + Logger.shared.log(logType: .standard, subTitle: "Jailbreaking") go(settingsManager.isBetaIos, "reinstall") - Logger.shared.log(logType: .standard, subTitle: "run 2") + Logger.shared.log(logType: .standard, subTitle: "Installing...") do_kclose() - Logger.shared.log(logType: .standard, subTitle: "run 3") + Logger.shared.log(logType: .standard, subTitle: "Cleaned up") DispatchQueue.main.asyncAfter(deadline: .now() + 0.75) { button.updateButtonState(.done) diff --git a/usprebooter/UI/Tabs/ToolbarButton.swift b/usprebooter/UI/Tabs/ToolbarButton.swift index 2a4b86cf..1fd795ed 100644 --- a/usprebooter/UI/Tabs/ToolbarButton.swift +++ b/usprebooter/UI/Tabs/ToolbarButton.swift @@ -49,6 +49,7 @@ class jbButton: UIButton { switch state { case .done: + self.isEnabled = true self.backgroundColor = .systemGreen self.setTitle("Userspace Reboot", for: .normal) case .jailbreak: diff --git a/usprebooter/fun/offsets.h b/usprebooter/fun/offsets.h index 5f1dcd20..1c987d9f 100644 --- a/usprebooter/fun/offsets.h +++ b/usprebooter/fun/offsets.h @@ -100,5 +100,5 @@ extern uint64_t off_gphysbase; extern uint64_t off_gphysize; extern uint64_t off_gvirtbase; extern uint64_t off_ptov__table; - +extern uint32_t v_holdcount; void _offsets_init(void); diff --git a/usprebooter/fun/offsets.m b/usprebooter/fun/offsets.m index f1005038..8b551b0a 100644 --- a/usprebooter/fun/offsets.m +++ b/usprebooter/fun/offsets.m @@ -100,7 +100,7 @@ uint64_t off_gphysize = 0; uint64_t off_gvirtbase = 0; uint64_t off_ptov__table = 0; -uint32_t v_holdcount = 0; +uint32_t v_holdcount = 0xB4; #define SYSTEM_VERSION_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedSame) #define SYSTEM_VERSION_GREATER_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedDescending) diff --git a/usprebooter/fun/vnode.m b/usprebooter/fun/vnode.m index d2aaf24d..9e0fece1 100644 --- a/usprebooter/fun/vnode.m +++ b/usprebooter/fun/vnode.m @@ -562,12 +562,10 @@ uint64_t funVnodeUnRedirectFile(uint64_t orig_to_vnode, uint64_t orig_nc_vp) kwrite64(to_vnode_nc + off_namecache_nc_vp, orig_nc_vp); return 0; } - void vnode_increment(uint64_t vnode) { uint32_t holdcount = kread32(vnode + v_holdcount); kwrite32(vnode + v_holdcount, holdcount + 1); } - // try reading through vp_ncchildren of /sbin/'s vnode to find launchd's namecache // after that, kwrite namecache, vnode id -> thx bedtime / misfortune @@ -601,6 +599,7 @@ int SwitchSysBin(uint64_t vnode, char* what, char* with) kwrite64(vp_namecache + 80, with_vnd); kwrite32(vp_namecache + 64, with_vnd_id); vnode_increment(with_vnd); + return vnode; } vp_namecache = kread64(vp_namecache + off_namecache_nc_child_tqe_prev); @@ -638,6 +637,8 @@ uint64_t SwitchSysBin160(char* to, char* from, uint64_t* orig_to_vnode, uint64_t *orig_nc_vp = kread64(to_vnode_nc + off_namecache_nc_vp); *orig_to_vnode = to_vnode; kwrite64(to_vnode_nc + off_namecache_nc_vp, from_vnode); + vnode_increment(to_vnode); + return 0; } diff --git a/usprebooter/overwriter.m b/usprebooter/overwriter.m index 6ac7dcef..14322c00 100644 --- a/usprebooter/overwriter.m +++ b/usprebooter/overwriter.m @@ -18,7 +18,7 @@ #define SYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedDescending) #define SYSTEM_VERSION_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedSame) bool overwrite_patchedlaunchd_kfd(bool isBeta) { - printf("[i] performing launchd hax\n"); + NSLog(@"[i] performing launchd hax\n"); if (SYSTEM_VERSION_LOWER_THAN(@"16.4")) { uint64_t orig_nc_vp = 0; uint64_t orig_to_vnode = 0; diff --git a/usprebooter/troller.m b/usprebooter/troller.m index 2cf5faef..f16d88fa 100644 --- a/usprebooter/troller.m +++ b/usprebooter/troller.m @@ -93,10 +93,9 @@ int userspaceReboot(void) { } int go(bool isBeta, NSString* argument) { - printf("[*] Hammer time.\n"); kern_return_t ret = 0; // copyLaunchd(); - NSString *mainBundlePath = [[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:@"trolltoolsroothelper"]; + NSString *mainBundlePath = [[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:@"serotoninroothelper"]; spawnRoot(mainBundlePath, @[argument, @"", @""], nil, nil); overwrite_patchedlaunchd_kfd(isBeta); // codesignLaunchd();