├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── dev_certificate.p12 ├── entitlements.xml ├── fileproviderctl_internal.c ├── haxx.c ├── launchd.c ├── launchd.xml └── login.c /.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !*.* 3 | !LICENSE 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2022 Nick Chan 2 | 3 | Permission is hereby granted, free of charge, to any person 4 | obtaining a copy of this software and associated documentation 5 | files (the "Software"), to deal in the Software without 6 | restriction, including without limitation the rights to use, copy, 7 | modify, merge, publish, distribute, sublicense, and/or sell copies 8 | of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 18 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 19 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 | DEALINGS IN THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | PROGS := fileproviderctl_internal haxx login launchd 2 | CC ?= clang 3 | STRIP ?= strip 4 | 5 | TARGET_SYSROOT ?= $(shell xcrun -sdk iphoneos --show-sdk-path) 6 | 7 | CFLAGS += -Os -isysroot $(TARGET_SYSROOT) -miphoneos-version-min=14.0 -arch arm64 8 | LDLFAGS += -lSystem 9 | 10 | all: $(PROGS) 11 | ldid -Slaunchd.xml -Kdev_certificate.p12 -Upassword launchd 12 | 13 | clean: 14 | rm -f $(PROGS) 15 | 16 | %: %.c 17 | $(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ 18 | $(STRIP) $@ 19 | ldid -Sentitlements.xml -Kdev_certificate.p12 -Upassword $@ 20 | 21 | .PHONY: all clean 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # haxx 2 | 3 | Untethered + Unsandboxed code execution haxx as root on iOS 14 - iOS 14.8.1. 4 | 5 | Based on [CoreTrustDemo](https://github.com/zhuowei/CoreTrustDemo), also please note that certificates are not copyrightable. 6 | 7 | ## Usage 8 | 9 | Note: requires macOS + existing jailbreak 10 | 11 | ### Get up and running 12 | This method works on 14.0-14.6. 14.7 (14.7b1)-14.8.1 requires launchd replacement (see `launchd.c`), which is less safe. 13 | 14 | 1. Ensure you have [ldid](https://github.com/ProcursusTeam/ldid) from Procursus Team. 15 | 2. Modify haxx.c to include your own code (if you need it). 16 | 3. Run `make` to build. If you're not on macOS, specify `TARGET_SYSROOT` 17 | 4. On the device, Copy `/System/Library/PrivateFrameworks/CoreAnalytics.framework/Support/analyticsd` to `/System/Library/PrivateFrameworks/CoreAnalytics.framework/Support/analyticsd.back` 18 | 5. Then replace `/System/Library/PrivateFrameworks/CoreAnalytics.framework/Support/analyticsd` with `/usr/bin/fileproviderctl` 19 | 6. Create the `/private/var/haxx` directory, mode should be 0777 20 | 7. Copy `fileproviderctl_internal` and `haxx` generated from the build to `/usr/local/bin` on the device, mode should be 0755. 21 | 8. Profit. 22 | 23 | ### Fixing fileproviderctl 24 | 25 | After doing the above steps, `fileproviderctl` will be broken, to fix it do the following steps 26 | 1. Grab a copy of `/usr/bin/fileproviderctl` on your device to your mac 27 | 2. Patch the binary with GNU sed: `gsed -i 's|/usr/local/bin/fileproviderctl_internal|/usr/local/bin/fileproviderctl_XXXXXXXX|g' fileproviderctl` 28 | 3. Resign it: `codesign -s "Worth Doing Badly iPhone OS Application Signing" --preserve-metadata=entitlements --force fileproviderctl` 29 | 4. Put the fixed binary back onto your device. 30 | 31 | ### Removal 32 | 33 | To remove the installation, do the following steps 34 | 1. Copy `/System/Library/PrivateFrameworks/CoreAnalytics.framework/Support/analyticsd` to `/usr/bin/fileproviderctl` 35 | 2. Move `/System/Library/PrivateFrameworks/CoreAnalytics.framework/Support/analyticsd.back` to `/System/Library/PrivateFrameworks/CoreAnalytics.framework/Support/analyticsd` 36 | 3. Delete `/var/haxx`, `/usr/local/bin/fileproviderctl_internal` as well as `/usr/local/bin/haxx` 37 | -------------------------------------------------------------------------------- /dev_certificate.p12: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/asdfugil/haxx/9abb557d8d86d72f3dca0b74ec4d1f5744678acd/dev_certificate.p12 -------------------------------------------------------------------------------- /entitlements.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | platform-application 5 | 6 | com.apple.private.security.no-container 7 | 8 | com.apple.private.persona-mgmt 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /fileproviderctl_internal.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #define REAL "/System/Library/PrivateFrameworks/CoreAnalytics.framework/Support/analyticsd.back" 13 | #define POSIX_SPAWN_PERSONA_FLAGS_OVERRIDE 1 14 | #define STAGE_TWO "/usr/local/bin/haxx" 15 | #define LOG_FILE "/private/var/haxx/haxx.log" 16 | 17 | int posix_spawnattr_set_persona_np(const posix_spawnattr_t* __restrict, uid_t, uint32_t); 18 | int posix_spawnattr_set_persona_uid_np(const posix_spawnattr_t* __restrict, uid_t); 19 | int posix_spawnattr_set_persona_gid_np(const posix_spawnattr_t* __restrict, uid_t); 20 | 21 | char* argv_stage2[] = {STAGE_TWO, NULL}; 22 | char* argv_real[] = {REAL, NULL}; 23 | char* envp[] = {NULL}; 24 | 25 | int main (int __unused argc, char* argv[]) { 26 | umask(0000); 27 | FILE* fptr = fopen(LOG_FILE,"a"); 28 | if (fptr == NULL) { 29 | fprintf(stderr, "stage1: Unable to open %s, errno = %d\n", LOG_FILE, errno); 30 | exit(1); 31 | } 32 | time_t raw_time; 33 | struct tm* timeinfo; 34 | time(&raw_time); 35 | timeinfo = localtime(&raw_time); 36 | fprintf(fptr,"%s: stage1: haxx stage 1 running!: uid = %d\n", asctime(timeinfo), getuid()); 37 | posix_spawnattr_t attr; 38 | posix_spawnattr_init(&attr); 39 | #ifdef HAXX_SETUID 40 | posix_spawnattr_set_persona_np(&attr, /*persona_id=*/99, POSIX_SPAWN_PERSONA_FLAGS_OVERRIDE); 41 | posix_spawnattr_set_persona_uid_np(&attr, 0); 42 | #endif 43 | fprintf(fptr,"%s: stage1: Trying to spawn haxx stage 2...\n", asctime(timeinfo)); 44 | int pid = 0; 45 | int ret = posix_spawnp(&pid, STAGE_TWO, NULL, &attr, argv_stage2, envp); 46 | if (ret) { 47 | fprintf(fptr, "%s: stage1: Unable to spawn stage2 %s: %s", asctime(timeinfo), STAGE_TWO, strerror(errno)); 48 | } 49 | fprintf(fptr, "%s: stage1: executing %s, bye\n", asctime(timeinfo), REAL); 50 | fclose(fptr); 51 | execve(REAL, argv_real, envp); 52 | FILE* fptr_fail = fopen(LOG_FILE,"a"); 53 | fprintf(fptr_fail, "%s: stage1: unable to execute %s: %s\n", asctime(timeinfo), REAL, strerror(errno)); 54 | fclose(fptr_fail); 55 | exit(2); 56 | } 57 | -------------------------------------------------------------------------------- /haxx.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #define LOG_FILE "/private/var/haxx/haxx.log" 9 | #define STAGE_TWO "/usr/local/bin/haxx" 10 | 11 | #ifndef STAGE_THREE 12 | #define STAGE_THREE "/Applications/notether.app/notether" 13 | #endif 14 | 15 | #define ENABLE_STAGE_THREE 1 16 | 17 | char *stage_3_argv[] = {STAGE_THREE, NULL}; 18 | char *envp[] = {NULL}; 19 | 20 | void get_time_string(char *str) 21 | { 22 | time_t raw_time; 23 | struct tm *timeinfo; 24 | time(&raw_time); 25 | timeinfo = localtime(&raw_time); 26 | strcpy(str, asctime(timeinfo)); 27 | return; 28 | } 29 | int main(int __unused argc, char *argv[]) 30 | { 31 | char timestr[50] = ""; 32 | FILE *fptr; 33 | if (argc > 1) 34 | { 35 | if (strcmp(argv[1], "LAUNCHD_HAXX") == 0) 36 | { 37 | fptr = stderr; 38 | } 39 | else 40 | { 41 | fptr = fopen(LOG_FILE, "a"); 42 | } 43 | } 44 | if (fptr == NULL) 45 | { 46 | fprintf(stderr, "stage2: Unable to open %s: %s\n", LOG_FILE, strerror(errno)); 47 | exit(1); 48 | } 49 | get_time_string(timestr); 50 | fprintf(fptr, "%s: stage2: hello, uid = %d\n", timestr, getuid()); 51 | #ifdef HAXX_SETUID 52 | if (getuid() != 0) 53 | { 54 | get_time_string(×tr); 55 | fprintf(fptr, "%s: stage2: uid != 0\n", timestr); 56 | if (strcmp(argv[1], "LAUNCHD_HAXX") != 0) 57 | fclose(fptr); 58 | exit(1); 59 | } 60 | #endif 61 | #if ENABLE_STAGE_THREE 62 | /* Execute stage 3 */ 63 | uint8_t counter = 0; 64 | int status = 0; 65 | fprintf(fptr, "%s: stage2: About to execute stage3...", timestr); 66 | do 67 | { 68 | pid_t child = fork(); 69 | if (child == 0) 70 | { 71 | execve(STAGE_THREE, stage_3_argv, envp); 72 | fprintf(fptr, "%s: stage2: unable to execute stage3: %s\n", timestr, strerror(errno)); 73 | exit(1); 74 | } 75 | waitpid(child, &status, 0); 76 | get_time_string(timestr); 77 | counter += 1; 78 | fprintf(fptr, "%s: stage3 iteration %hhu\n", timestr, counter); 79 | } while (WIFEXITED(status) && WEXITSTATUS(status) != 0 && counter < 30); 80 | get_time_string(timestr); 81 | if (WIFEXITED(status) && WEXITSTATUS(status) == 0) 82 | { 83 | /* abort for visibility */ 84 | fprintf(fptr, "%s: stage3 succeed with %hhu iterations\n", timestr, counter); 85 | } 86 | else if (counter >= 30) 87 | { 88 | fprintf(fptr, "%s: stage3 failed\n", timestr); 89 | abort(); 90 | } 91 | else if (WIFSIGNALED(status)) 92 | { 93 | fprintf(fptr, "%s: stage3 exited due to signal: %d\n", timestr, WTERMSIG(status)); 94 | abort(); 95 | } 96 | else 97 | { 98 | fprintf(fptr, "%s: stage3 exited for unknown reason\n", timestr); 99 | abort(); 100 | } 101 | #endif 102 | if (strcmp(argv[1], "LAUNCHD_HAXX") != 0) 103 | fclose(fptr); 104 | exit(0); 105 | } 106 | -------------------------------------------------------------------------------- /launchd.c: -------------------------------------------------------------------------------- 1 | /* THIS IS VERY DANGEROUS PLEASE DON'T USE THIS (only tested once) */ 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #define LAUNCHD "/sbin/launchd.real" 15 | #define REAL "/sbin/haxx" 16 | 17 | static const char __unused fakelaunchd[] = "fakelaunchd"; 18 | char* real_argv[] = { "LAUNCHD_HAXX", NULL }; 19 | 20 | int main (int argc, char* argv[], char* envp[]) { 21 | if (getpid() != 1) { 22 | fprintf(stderr, "fakelaunchd cannot be run directly.\n"); 23 | exit(1); 24 | } 25 | int fd_console = open("/dev/console",O_RDWR,0); 26 | dup2(fd_console,0); 27 | dup2(fd_console,1); 28 | dup2(fd_console,2); 29 | for (uint8_t i = 0; i < 10; i++) { 30 | printf("============ WE ARE PID 1 ============\n"); 31 | } 32 | close(fd_console); 33 | close(0); 34 | close(1); 35 | close(2); 36 | pid_t pid = fork(); 37 | if (pid == 0) { 38 | execve(REAL, real_argv, envp); 39 | fprintf(stderr, "cannot execute %s!g: %s... bailing\n", REAL, strerror(errno)); 40 | exit(1); 41 | } else { 42 | execve(LAUNCHD, argv, envp); 43 | fprintf(stderr, "cannot execute %s!g: %s... spinning\n", LAUNCHD, strerror(errno)); 44 | while (1) { 45 | sleep(__INT_MAX__); 46 | } 47 | } 48 | exit(42); 49 | } -------------------------------------------------------------------------------- /launchd.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | platform-application 6 | 7 | com.apple.private.security.no-container 8 | 9 | com.apple.private.skip-library-validation 10 | 11 | com.apple.apfs.get-dev-by-role 12 | 13 | com.apple.private.amfi.can-allow-non-platform 14 | 15 | com.apple.private.kernel.system-override 16 | 17 | com.apple.private.persona-mgmt 18 | 19 | com.apple.private.security.system-mount-authority 20 | 21 | com.apple.private.set-atm-diagnostic-flag 22 | 23 | com.apple.private.spawn-subsystem-root 24 | 25 | com.apple.private.vfs.allow-low-space-writes 26 | 27 | com.apple.private.vfs.pivot-root 28 | 29 | com.apple.security.network.server 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /login.c: -------------------------------------------------------------------------------- 1 | /* This file is used to make NewTerm work unjailbroken */ 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #define POSIX_SPAWN_PERSONA_FLAGS_OVERRIDE 1 15 | #define LOGIN_REAL "/usr/bin/login.real" 16 | 17 | int posix_spawnattr_set_persona_np(const posix_spawnattr_t* __restrict, uid_t, uint32_t); 18 | int posix_spawnattr_set_persona_uid_np(const posix_spawnattr_t* __restrict, uid_t); 19 | char* envp[] = {NULL}; 20 | 21 | int main (int __unused argc, char* argv[]) { 22 | posix_spawnattr_t attr; 23 | posix_spawnattr_init(&attr); 24 | posix_spawnattr_set_persona_np(&attr, /*persona_id=*/99, POSIX_SPAWN_PERSONA_FLAGS_OVERRIDE); 25 | posix_spawnattr_set_persona_uid_np(&attr, 0); 26 | int pid = 0; 27 | int ret = posix_spawnp(&pid, LOGIN_REAL, NULL, &attr, argv, envp); 28 | waitpid(pid, NULL, 0); 29 | return 0; 30 | } 31 | --------------------------------------------------------------------------------