Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 | #include <TargetConditionals.h> #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #if __has_include(<ptrauth.h>) #include <ptrauth.h> #endif #include <sys/mman.h> #include <sys/syslimits.h> char *cmdname; int main( int argc, char *argv[]) { uint32_t page_size; void *page; int ch; int opt_interactive; cmdname = argv[0]; opt_interactive = 0; while ((ch = getopt(argc, argv, "i")) != -1) { switch (ch) { case 'i': opt_interactive = 1; break; case '?': default: fprintf(stdout, "Usage: %s [-i]\n" "\t-i: interactive\n", cmdname); exit(1); } } page_size = getpagesize(); page = mmap(NULL, page_size, PROT_READ | PROT_EXEC, MAP_ANON | MAP_SHARED, -1, 0); if (!page) { fprintf(stderr, "%s:%d mmap() error %d (%s)\n", cmdname, __LINE__, errno, strerror(errno)); exit(1); } if (opt_interactive) { fprintf(stdout, "allocated page at %p\n", page); } if (mprotect(page, page_size, PROT_READ | PROT_WRITE) != 0) { fprintf(stderr, "%s:%d mprotect(RW) error %d (%s)\n", cmdname, __LINE__, errno, strerror(errno)); exit(1); } #if __arm64__ // arm64 chdir() syscall char chdir_code[] = { 0x90, 0x01, 0x80, 0xd2, // movz x16, #0xc 0x01, 0x10, 0x00, 0xd4, // svc #0x80 0xc0, 0x03, 0x5f, 0xd6, // ret }; #elif __arm__ // armv7 chdir() syscall char chdir_code[] = { 0x0c, 0xc0, 0xa0, 0xe3, // mov r12 #0xc 0x80, 0x00, 0x00, 0xef, // svc #0x80 0x1e, 0xff, 0x2f, 0xe1, // bx lr }; #elif __x86_64__ // x86_64 chdir() syscall char chdir_code[] = { 0xb8, 0x0c, 0x00, 0x00, 0x02, // movl $0x200000c, %eax 0x49, 0x89, 0xca, // movq %rcx, %r10 0x0f, 0x05, // syscall 0xc3, // retq }; #elif __i386__ // i386 chdir() syscall char chdir_code[] = { 0x90, // nop 0xc3, // retq }; #endif memcpy(page, chdir_code, sizeof chdir_code); if (opt_interactive) { fprintf(stdout, "changed page protection to r/w and copied code at %p\n", page); fprintf(stdout, "pausing...\n"); fflush(stdout); getchar(); } if (mprotect(page, page_size, PROT_READ | PROT_EXEC) != 0) { fprintf(stderr, "%s:%d mprotect(RX) error %d (%s)\n", cmdname, __LINE__, errno, strerror(errno)); exit(1); } if (opt_interactive) { fprintf(stdout, "changed page protection to r/x at %p\n", page); fprintf(stdout, "pausing...\n"); fflush(stdout); getchar(); } char origdir[PATH_MAX]; getcwd(origdir, sizeof(origdir) - 1); chdir("/"); if (opt_interactive) { fprintf(stdout, "cwd before = %s\n", getwd(NULL)); } void (*mychdir)(char *) = page; #if __has_feature(ptrauth_calls) mychdir = ptrauth_sign_unauthenticated(mychdir, ptrauth_key_function_pointer, 0); #endif mychdir(getenv("HOME")); if (opt_interactive) { fprintf(stdout, "cwd after = %s\n", getwd(NULL)); fprintf(stdout, "pausing...\n"); fflush(stdout); getchar(); } fprintf(stdout, "%s: WARNING: unsigned code was executed\n", cmdname); /* fail: unsigned code was executed */ fprintf(stdout, "%s: FAIL\n", cmdname); exit(1); } |