jailbreak.m 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552
  1. //
  2. // jailbreak.m
  3. // Meridian
  4. //
  5. // Created by Ben Sparkes on 16/02/2018.
  6. // Copyright © 2018 Ben Sparkes. All rights reserved.
  7. //
  8. #include "v0rtex.h"
  9. #include "kernel.h"
  10. #include "helpers.h"
  11. #include "root-rw.h"
  12. #include "amfi.h"
  13. #include "offsetfinder.h"
  14. #include "jailbreak.h"
  15. #include "ViewController.h"
  16. #include "patchfinder64.h"
  17. #include "patchfinders/offsetdump.h"
  18. #include "nvpatch.h"
  19. #include <mach/mach_types.h>
  20. #include <sys/stat.h>
  21. #import <Foundation/Foundation.h>
  22. NSFileManager *fileMgr;
  23. offsets_t offsets;
  24. BOOL great_success = FALSE;
  25. int makeShitHappen(ViewController *view) {
  26. int ret;
  27. fileMgr = [NSFileManager defaultManager];
  28. // run v0rtex
  29. [view writeText:@"running v0rtex..."];
  30. suspend_all_threads();
  31. ret = runV0rtex();
  32. resume_all_threads();
  33. if (ret != 0) {
  34. [view writeText:@"failed!"];
  35. if (ret == -420) {
  36. [view writeTextPlain:@"failed to load offsets!"];
  37. }
  38. return 1;
  39. }
  40. [view writeTextPlain:@"succeeded! praize siguza!"];
  41. // set up stuff
  42. init_patchfinder(NULL);
  43. ret = init_amfi();
  44. if (ret != 0) {
  45. [view writeTextPlain:@"failed to initialize amfi class!"];
  46. return 1;
  47. }
  48. // patch containermanager
  49. [view writeText:@"patching containermanager..."];
  50. ret = patchContainermanagerd();
  51. if (ret != 0) {
  52. [view writeText:@"failed!"];
  53. return 1;
  54. }
  55. [view writeText:@"done!"];
  56. // remount root fs
  57. [view writeText:@"remounting rootfs as r/w..."];
  58. ret = remountRootFs();
  59. if (ret != 0) {
  60. [view writeText:@"failed!"];
  61. return 1;
  62. }
  63. [view writeText:@"done!"];
  64. /* Begin the filesystem fuckery */
  65. [view writeText:@"some filesytem fuckery..."];
  66. // Remove /meridian in the case of PB's
  67. if (file_exists("/meridian") == 0 &&
  68. file_exists("/meridian/.bootstrap") != 0) {
  69. [fileMgr removeItemAtPath:@"/meridian" error:nil];
  70. }
  71. if (file_exists("/meridian") != 0) {
  72. ret = mkdir("/meridian", 0755);
  73. if (ret != 0) {
  74. [view writeText:@"failed!"];
  75. [view writeTextPlain:@"creating /meridian failed with error %d: %s", errno, strerror(errno)];
  76. return 1;
  77. }
  78. }
  79. if (file_exists("/meridian/logs") != 0) {
  80. ret = mkdir("/meridian/logs", 0755);
  81. if (ret != 0) {
  82. [view writeText:@"failed!"];
  83. [view writeTextPlain:@"creating /meridian/logs failed with error %d: %s", errno, strerror(errno)];
  84. return 1;
  85. }
  86. }
  87. if (file_exists("/meridian/tar") == 0) {
  88. ret = unlink("/meridian/tar");
  89. if (ret != 0) {
  90. [view writeText:@"failed!"];
  91. [view writeTextPlain:@"removing /meridian/tar failed with error %d: %s", errno, strerror(errno)];
  92. return 1;
  93. }
  94. }
  95. if (file_exists("/meridian/tar.tar") == 0) {
  96. ret = unlink("/meridian/tar.tar");
  97. if (ret != 0) {
  98. [view writeText:@"failed!"];
  99. [view writeTextPlain:@"deleting /meridian/tar.tar failed with error %d: %s", errno, strerror(errno)];
  100. return 1;
  101. }
  102. }
  103. ret = extract_bundle("tar.tar", "/meridian");
  104. if (ret != 0) {
  105. [view writeText:@"failed!"];
  106. [view writeTextPlain:@"failed to extract tar.tar bundle! ret: %d, errno: %d: %s", ret, errno, strerror(errno)];
  107. return 1;
  108. }
  109. if (file_exists("/meridian/tar") != 0) {
  110. [view writeText:@"failed!"];
  111. [view writeTextPlain:@"/meridian/tar was not found :("];
  112. return 1;
  113. }
  114. ret = chmod("/meridian/tar", 0755);
  115. if (ret != 0) {
  116. [view writeText:@"failed!"];
  117. [view writeTextPlain:@"chmod(755)'ing /meridian/tar failed with error %d: %s", errno, strerror(errno)];
  118. return 1;
  119. }
  120. ret = inject_trust("/meridian/tar");
  121. if (ret != 0) {
  122. [view writeText:@"failed!"];
  123. [view writeTextPlain:@"injecting trust to /meridian/tar failed with retcode %d", ret];
  124. return 1;
  125. }
  126. [view writeText:@"done!"];
  127. // extract meridian-bootstrap
  128. [view writeText:@"extracting meridian files..."];
  129. ret = extractMeridianData();
  130. if (ret != 0) {
  131. [view writeText:@"failed!"];
  132. [view writeTextPlain:[NSString stringWithFormat:@"error code: %d", ret]];
  133. return 1;
  134. }
  135. [view writeText:@"done!"];
  136. // dump offsets to file for later use (/meridian/offsets.plist)
  137. dumpOffsetsToFile(&offsets, kernel_base, kslide);
  138. // patch amfid
  139. [view writeText:@"patching amfid..."];
  140. ret = defecateAmfi();
  141. if (ret != 0) {
  142. [view writeText:@"failed!"];
  143. if (ret > 0) {
  144. [view writeTextPlain:[NSString stringWithFormat:@"failed to patch - %d tries", ret]];
  145. }
  146. return 1;
  147. }
  148. [view writeText:@"done!"];
  149. // touch .cydia_no_stash
  150. touch_file("/.cydia_no_stash");
  151. // symlink /Library/MobileSubstrate/DynamicLibraries -> /usr/lib/tweaks
  152. setUpSymLinks();
  153. // remove Substrate's SafeMode (MobileSafety) if it's installed
  154. // removing from dpkg will be handled by Cydia conflicts later
  155. if (file_exists("/usr/lib/tweaks/MobileSafety.dylib") == 0) {
  156. unlink("/usr/lib/tweaks/MobileSafety.dylib");
  157. }
  158. if (file_exists("/usr/lib/tweaks/MobileSafety.plist") == 0) {
  159. unlink("/usr/lib/tweaks/MobileSafety.plist");
  160. }
  161. // extract bootstrap (if not already extracted)
  162. if (file_exists("/meridian/.bootstrap") != 0) {
  163. [view writeText:@"extracting bootstrap..."];
  164. int exitCode = 0;
  165. ret = extractBootstrap(&exitCode);
  166. if (ret != 0) {
  167. [view writeText:@"failed!"];
  168. switch (ret) {
  169. case 1:
  170. [view writeTextPlain:@"failed to extract system-base.tar"];
  171. break;
  172. case 2:
  173. [view writeTextPlain:@"failed to extract installer-base.tar"];
  174. break;
  175. case 3:
  176. [view writeTextPlain:@"failed to extract dpkgdb-base.tar"];
  177. break;
  178. case 4:
  179. [view writeTextPlain:@"failed to extract cydia-base.tar"];
  180. break;
  181. case 5:
  182. [view writeTextPlain:@"failed to extract optional-base.tar"];
  183. break;
  184. case 6:
  185. [view writeTextPlain:@"failed to run uicache!"];
  186. break;
  187. }
  188. [view writeTextPlain:@"exit code: %d", exitCode];
  189. return 1;
  190. }
  191. [view writeText:@"done!"];
  192. }
  193. // add the midnight repo
  194. if (file_exists("/etc/apt/sources.list.d/meridian.list") != 0) {
  195. FILE *fd = fopen("/etc/apt/sources.list.d/meridian.list", "w+");
  196. const char *text = "deb http://repo.midnight.team ./";
  197. fwrite(text, strlen(text) + 1, 1, fd);
  198. fclose(fd);
  199. }
  200. // launch dropbear
  201. [view writeText:@"launching dropbear..."];
  202. ret = launchDropbear();
  203. if (ret != 0) {
  204. [view writeText:@"failed!"];
  205. [view writeTextPlain:@"exit code: %d", ret];
  206. return 1;
  207. }
  208. [view writeText:@"done!"];
  209. // link substitute stuff
  210. setUpSubstitute();
  211. // start jailbreakd
  212. [view writeText:@"starting jailbreakd..."];
  213. ret = startJailbreakd();
  214. if (ret != 0) {
  215. [view writeText:@"failed"];
  216. if (ret > 1) {
  217. [view writeTextPlain:@"failed to launch - %d tries", ret];
  218. }
  219. return 1;
  220. }
  221. [view writeText:@"done!"];
  222. // patch com.apple.System.boot-nonce
  223. [view writeText:@"patching boot-nonce..."];
  224. ret = nvpatch("com.apple.System.boot-nonce");
  225. if (ret != 0) {
  226. [view writeText:@"failed!"];
  227. return 1;
  228. }
  229. [view writeText:@"done!"];
  230. // load launchdaemons
  231. [view writeText:@"loading launchdaemons..."];
  232. ret = loadLaunchDaemons();
  233. if (ret != 0) {
  234. [view writeText:@"failed!"];
  235. return 1;
  236. }
  237. [view writeText:@"done!"];
  238. great_success = TRUE;
  239. return 0;
  240. }
  241. kern_return_t callback(task_t kern_task, kptr_t kbase, void *cb_data) {
  242. tfp0 = kern_task;
  243. kernel_base = kbase;
  244. kslide = kernel_base - 0xFFFFFFF007004000;
  245. return KERN_SUCCESS;
  246. }
  247. int runV0rtex() {
  248. offsets_t *offs = get_offsets();
  249. if (offs == NULL) {
  250. return -420;
  251. }
  252. offsets = *offs;
  253. int ret = v0rtex(&offsets, &callback, NULL);
  254. uint64_t kernel_task_addr = rk64(offs->kernel_task + kslide);
  255. kernprocaddr = rk64(kernel_task_addr + offs->task_bsd_info);
  256. kern_ucred = rk64(kernprocaddr + offs->proc_ucred);
  257. if (ret == 0) {
  258. NSLog(@"tfp0: 0x%x", tfp0);
  259. NSLog(@"kernel_base: 0x%llx", kernel_base);
  260. NSLog(@"kslide: 0x%llx", kslide);
  261. NSLog(@"kern_ucred: 0x%llx", kern_ucred);
  262. NSLog(@"kernprocaddr: 0x%llx", kernprocaddr);
  263. }
  264. return ret;
  265. }
  266. int patchContainermanagerd() {
  267. uint64_t cmgr = find_proc_by_name("containermanager");
  268. if (cmgr == 0) {
  269. NSLog(@"unable to find containermanager!");
  270. return 1;
  271. }
  272. wk64(cmgr + 0x100, kern_ucred);
  273. return 0;
  274. }
  275. int remountRootFs() {
  276. NSOperatingSystemVersion osVersion = [[NSProcessInfo processInfo] operatingSystemVersion];
  277. int pre130 = osVersion.minorVersion < 2 ? 1 : 0;
  278. int rv = mount_root(kslide, offsets.root_vnode, pre130);
  279. if (rv != 0) {
  280. return 1;
  281. }
  282. return 0;
  283. }
  284. int extractMeridianData() {
  285. return extract_bundle_tar("meridian-bootstrap.tar");
  286. }
  287. void setUpSymLinks() {
  288. struct stat file;
  289. stat("/Library/MobileSubstrate/DynamicLibraries", &file);
  290. if (file_exists("/Library/MobileSubstrate/DynamicLibraries") == 0 &&
  291. file_exists("/usr/lib/tweaks") == 0 &&
  292. S_ISLNK(file.st_mode)) {
  293. return;
  294. }
  295. // By the end of this check, /usr/lib/tweaks should exist containing any
  296. // tweaks (if applicable), and /Lib/MobSub/DynLib should NOT exist
  297. if (file_exists("/Library/MobileSubstrate/DynamicLibraries") == 0 &&
  298. file_exists("/usr/lib/tweaks") != 0) {
  299. // Move existing tweaks folder to /usr/lib/tweaks
  300. [fileMgr moveItemAtPath:@"/Library/MobileSubstrate/DynamicLibraries" toPath:@"/usr/lib/tweaks" error:nil];
  301. } else if (file_exists("/Library/MobileSubstrate/DynamicLibraries") == 0 &&
  302. file_exists("/usr/lib/tweaks") == 0) {
  303. // Move existing tweaks to /usr/lib/tweaks and delete the MobSub folder
  304. NSArray *fileList = [fileMgr contentsOfDirectoryAtPath:@"/Library/MobileSubstrate/DynamicLibraries" error:nil];
  305. for (NSString *item in fileList) {
  306. NSString *fullPath = [NSString stringWithFormat:@"/Library/MobileSubstrate/DynamicLibraries/%@", item];
  307. [fileMgr moveItemAtPath:fullPath toPath:@"/usr/lib/tweaks" error:nil];
  308. }
  309. [fileMgr removeItemAtPath:@"/Library/MobileSubstrate/DynamicLibraries" error:nil];
  310. } else if (file_exists("/Library/MobileSubstrate/DynamicLibraries") != 0 &&
  311. file_exists("/usr/lib/tweaks") != 0) {
  312. // Just create /usr/lib/tweaks - /Lib/MobSub/DynLibs doesn't exist
  313. mkdir("/Library/MobileSubstrate", 0755);
  314. mkdir("/usr/lib/tweaks", 0755);
  315. } else if (file_exists("/Library/MobileSubstrate/DynamicLibraries") != 0 &&
  316. file_exists("/usr/lib/tweaks") == 0) {
  317. // We should be fine in this case
  318. mkdir("/Library/MobileSubstrate", 0755);
  319. }
  320. // Symlink it!
  321. symlink("/usr/lib/tweaks", "/Library/MobileSubstrate/DynamicLibraries");
  322. }
  323. int extractBootstrap(int *exitCode) {
  324. int rv;
  325. // extract system-base.tar
  326. rv = extract_bundle_tar("system-base.tar");
  327. if (rv != 0) {
  328. *exitCode = rv;
  329. return 1;
  330. }
  331. // extract installer-base.tar
  332. rv = extract_bundle_tar("installer-base.tar");
  333. if (rv != 0) {
  334. *exitCode = rv;
  335. return 2;
  336. }
  337. if (file_exists("/private/var/lib/dpkg/status") != 0) {
  338. rv = extract_bundle_tar("dpkgdb-base.tar");
  339. if (rv != 0) {
  340. *exitCode = rv;
  341. return 3;
  342. }
  343. }
  344. // extract cydia-base.tar
  345. rv = extract_bundle_tar("cydia-base.tar");
  346. if (rv != 0) {
  347. *exitCode = rv;
  348. return 4;
  349. }
  350. // extract optional-base.tar
  351. rv = extract_bundle_tar("optional-base.tar");
  352. if (rv != 0) {
  353. *exitCode = rv;
  354. return 5;
  355. }
  356. enableHiddenApps();
  357. touch_file("/meridian/.bootstrap");
  358. rv = uicache();
  359. if (rv != 0) {
  360. *exitCode = rv;
  361. return 6;
  362. }
  363. return 0;
  364. }
  365. int defecateAmfi() {
  366. // write kslide to file
  367. unlink("/meridian/kernel_slide");
  368. FILE *fd = fopen("/meridian/kernel_slide", "w");
  369. fprintf(fd, "%016llx", kslide);
  370. fclose(fd);
  371. // trust our payload
  372. int ret = inject_trust("/meridian/amfid_payload.dylib");
  373. if (ret != 0) return -1;
  374. unlink("/var/tmp/amfid_payload.alive");
  375. pid_t pid = get_pid_for_name("amfid");
  376. if (pid == 0) {
  377. return -2;
  378. }
  379. ret = inject_library(pid, "/meridian/amfid_payload.dylib");
  380. if (ret != 0) return -2;
  381. int tries = 0;
  382. while (file_exists("/var/tmp/amfid_payload.alive") != 0) {
  383. if (tries >= 100) {
  384. NSLog(@"failed to patch amfid (%d tries)", tries);
  385. return tries;
  386. }
  387. NSLog(@"waiting for amfid patch...");
  388. usleep(100000); // 0.1 sec
  389. tries++;
  390. }
  391. return 0;
  392. }
  393. int launchDropbear() {
  394. return start_launchdaemon("/meridian/dropbear/dropbear.plist");
  395. }
  396. void setUpSubstitute() {
  397. // link CydiaSubstrate.framework -> /usr/lib/libsubstrate.dylib
  398. if (file_exists("/Library/Frameworks/CydiaSubstrate.framework") == 0) {
  399. [fileMgr removeItemAtPath:@"/Library/Frameworks/CydiaSubstrate.framework" error:nil];
  400. }
  401. mkdir("/Library/Frameworks", 0755);
  402. mkdir("/Library/Frameworks/CydiaSubstrate.framework", 0755);
  403. symlink("/usr/lib/libsubstrate.dylib", "/Library/Frameworks/CydiaSubstrate.framework/CydiaSubstrate");
  404. }
  405. int startJailbreakd() {
  406. unlink("/var/tmp/jailbreakd.pid");
  407. NSData *blob = [NSData dataWithContentsOfFile:@"/meridian/jailbreakd/jailbreakd.plist"];
  408. NSMutableDictionary *job = [NSPropertyListSerialization propertyListWithData:blob options:NSPropertyListMutableContainers format:nil error:nil];
  409. job[@"EnvironmentVariables"][@"KernelBase"] = [NSString stringWithFormat:@"0x%16llx", kernel_base];
  410. job[@"EnvironmentVariables"][@"KernProcAddr"] = [NSString stringWithFormat:@"0x%16llx", kernprocaddr];
  411. job[@"EnvironmentVariables"][@"ZoneMapOffset"] = [NSString stringWithFormat:@"0x%16llx", offsets.zone_map];
  412. [job writeToFile:@"/meridian/jailbreakd/jailbreakd.plist" atomically:YES];
  413. chmod("/meridian/jailbreakd/jailbreakd.plist", 0600);
  414. chown("/meridian/jailbreakd/jailbreakd.plist", 0, 0);
  415. int rv = start_launchdaemon("/meridian/jailbreakd/jailbreakd.plist");
  416. if (rv != 0) return 1;
  417. int tries = 0;
  418. while (file_exists("/var/tmp/jailbreakd.pid") != 0) {
  419. printf("Waiting for jailbreakd \n");
  420. tries++;
  421. usleep(300000); // 300ms
  422. if (tries >= 100) {
  423. NSLog(@"too many tries for jbd - %d", tries);
  424. return tries;
  425. }
  426. }
  427. usleep(100000);
  428. // tell jailbreakd to platformize launchd
  429. // this adds skip-lib-val to MACF slot and allows us
  430. // to inject pspawn without it being in trust cache
  431. // (plus FAT/multiarch in trust cache is a pain to code, i'm lazy)
  432. rv = call_jailbreakd(JAILBREAKD_COMMAND_ENTITLE, 1);
  433. if (rv != 0) return 2;
  434. // inject pspawn_hook.dylib to launchd
  435. rv = inject_library(1, "/usr/lib/pspawn_hook.dylib");
  436. if (rv != 0) return 3;
  437. return 0;
  438. }
  439. int loadLaunchDaemons() {
  440. NSArray *daemons = [fileMgr contentsOfDirectoryAtPath:@"/Library/LaunchDaemons" error:nil];
  441. for (NSString *file in daemons) {
  442. NSString *path = [NSString stringWithFormat:@"/Library/LaunchDaemons/%@", file];
  443. NSLog(@"found launchdaemon: %@", path);
  444. chmod([path UTF8String], 0755);
  445. chown([path UTF8String], 0, 0);
  446. }
  447. return start_launchdaemon("/Library/LaunchDaemons");
  448. }
  449. void enableHiddenApps() {
  450. // enable showing of system apps on springboard
  451. // this is some funky killall stuff tho
  452. killall("cfprefsd", "-SIGSTOP");
  453. NSMutableDictionary* md = [[NSMutableDictionary alloc] initWithContentsOfFile:@"/var/mobile/Library/Preferences/com.apple.springboard.plist"];
  454. [md setObject:[NSNumber numberWithBool:YES] forKey:@"SBShowNonDefaultSystemApps"];
  455. [md writeToFile:@"/var/mobile/Library/Preferences/com.apple.springboard.plist" atomically:YES];
  456. killall("cfprefsd", "-9");
  457. }