├── .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 |
--------------------------------------------------------------------------------