helpers.m 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545
  1. //
  2. // helpers.m
  3. // Meridian
  4. //
  5. // Created by Ben Sparkes on 30/12/2017.
  6. // Copyright © 2017 Ben Sparkes. All rights reserved.
  7. //
  8. #include "helpers.h"
  9. #include "ViewController.h"
  10. #include "kernel.h"
  11. #include "untar.h"
  12. #include "amfi.h"
  13. #include "jailbreak_daemonUser.h"
  14. #include <dirent.h>
  15. #include <unistd.h>
  16. #include <dlfcn.h>
  17. #include <sys/fcntl.h>
  18. #include <sys/spawn.h>
  19. #include <sys/stat.h>
  20. #include <sys/sysctl.h>
  21. #import <Foundation/Foundation.h>
  22. int call_jailbreakd(int command, pid_t pid) {
  23. mach_port_t jbd_port;
  24. if (bootstrap_look_up(bootstrap_port, "zone.sparkes.jailbreakd", &jbd_port) != 0) {
  25. return -1;
  26. }
  27. return jbd_call(jbd_port, command, pid);
  28. }
  29. uint64_t find_proc_by_name(char* name) {
  30. uint64_t proc = rk64(kernprocaddr + 0x08);
  31. while (proc) {
  32. char proc_name[40] = { 0 };
  33. kread(proc + 0x26c, proc_name, 40);
  34. if (!strcmp(name, proc_name)) {
  35. return proc;
  36. }
  37. proc = rk64(proc + 0x08);
  38. }
  39. return 0;
  40. }
  41. uint64_t find_proc_by_pid(uint32_t pid) {
  42. uint64_t proc = rk64(kernprocaddr + 0x08);
  43. while (proc) {
  44. uint32_t proc_pid = rk32(proc + 0x10);
  45. if (pid == proc_pid) {
  46. return proc;
  47. }
  48. proc = rk64(proc + 0x08);
  49. }
  50. return 0;
  51. }
  52. uint32_t get_pid_for_name(char* name) {
  53. uint64_t proc = find_proc_by_name(name);
  54. if (proc == 0) {
  55. return 0;
  56. }
  57. return rk32(proc + 0x10);
  58. }
  59. int uicache() {
  60. return execprog("/bin/uicache", NULL);
  61. }
  62. int start_launchdaemon(const char *path) {
  63. int ret = inject_trust("/bin/launchctl");
  64. if (ret != 0) {
  65. NSLog(@"Failed to inject trust to /bin/launchctl: %d", ret);
  66. return -30;
  67. }
  68. chmod(path, 0755);
  69. chown(path, 0, 0);
  70. return execprog("/bin/launchctl", (const char **)&(const char*[]) {
  71. "/bin/launchctl",
  72. "load",
  73. "-w",
  74. path,
  75. NULL
  76. });
  77. }
  78. int respring() {
  79. pid_t springBoard = get_pid_for_name("backboardd");
  80. if (springBoard == 0) {
  81. return 1;
  82. }
  83. kill(springBoard, 9);
  84. return 0;
  85. }
  86. int inject_library(pid_t pid, const char *path) {
  87. mach_port_t task_port;
  88. kern_return_t ret = task_for_pid(mach_task_self(), pid, &task_port);
  89. if (ret != KERN_SUCCESS || task_port == MACH_PORT_NULL) {
  90. task_port = task_for_pid_workaround(pid);
  91. if (task_port == MACH_PORT_NULL) {
  92. NSLog(@"[injector] failed to get task for pid %d", pid);
  93. return ret;
  94. }
  95. }
  96. NSLog(@"[injector] got task port: %x", task_port);
  97. call_remote(task_port, dlopen, 2, REMOTE_CSTRING(path), REMOTE_LITERAL(RTLD_NOW));
  98. uint64_t error = call_remote(task_port, dlerror, 0);
  99. if (error != 0) {
  100. uint64_t len = call_remote(task_port, strlen, 1, REMOTE_LITERAL(error));
  101. char* local_cstring = malloc(len + 1);
  102. remote_read_overwrite(task_port, error, (uint64_t)local_cstring, len + 1);
  103. NSLog(@"[injector] error: %s", local_cstring);
  104. return -1;
  105. }
  106. return 0;
  107. }
  108. int killall(const char *procname, const char *kill) {
  109. return execprog("/usr/bin/killall", (const char **)&(const char *[]) {
  110. "/usr/bin/killall",
  111. kill,
  112. procname,
  113. NULL
  114. });
  115. }
  116. int check_for_jailbreak() {
  117. int csops(pid_t pid, unsigned int ops, void *useraddr, size_t usersize);
  118. uint32_t flags;
  119. csops(getpid(), 0, &flags, 0);
  120. return flags & CS_PLATFORM_BINARY;
  121. }
  122. char *itoa(long n) {
  123. int len = n==0 ? 1 : floor(log10l(labs(n)))+1;
  124. if (n<0) len++; // room for negative sign '-'
  125. char *buf = calloc(sizeof(char), len+1); // +1 for null
  126. snprintf(buf, len+1, "%ld", n);
  127. return buf;
  128. }
  129. // remember: returns 0 if file exists
  130. int file_exists(const char *path) {
  131. return access(path, F_OK);
  132. }
  133. void read_file(const char *path) {
  134. char buf[65] = {0};
  135. int fd = open(path, O_RDONLY);
  136. if (fd == -1) {
  137. perror("open path");
  138. return;
  139. }
  140. printf("contents of %s: \n ------------------------- \n", path);
  141. while(read(fd, buf, sizeof(buf) - 1) == sizeof(buf) - 1) {
  142. printf("%s", buf);
  143. }
  144. printf("%s", buf);
  145. printf("\n-------------------------\n");
  146. close(fd);
  147. }
  148. int cp(const char *from, const char *to) {
  149. int fd_to, fd_from;
  150. char buf[4096];
  151. ssize_t nread;
  152. int saved_errno;
  153. fd_from = open(from, O_RDONLY);
  154. if (fd_from < 0)
  155. return -1;
  156. fd_to = open(to, O_WRONLY | O_CREAT | O_EXCL, 0666);
  157. if (fd_to < 0)
  158. goto out_error;
  159. while ((nread = read(fd_from, buf, sizeof buf)) > 0)
  160. {
  161. char *out_ptr = buf;
  162. ssize_t nwritten;
  163. do {
  164. nwritten = write(fd_to, out_ptr, nread);
  165. if (nwritten >= 0)
  166. {
  167. nread -= nwritten;
  168. out_ptr += nwritten;
  169. }
  170. else if (errno != EINTR)
  171. {
  172. goto out_error;
  173. }
  174. } while (nread > 0);
  175. }
  176. if (nread == 0)
  177. {
  178. if (close(fd_to) < 0)
  179. {
  180. fd_to = -1;
  181. goto out_error;
  182. }
  183. close(fd_from);
  184. /* Success! */
  185. return 0;
  186. }
  187. out_error:
  188. saved_errno = errno;
  189. close(fd_from);
  190. if (fd_to >= 0)
  191. close(fd_to);
  192. errno = saved_errno;
  193. return -1;
  194. }
  195. // https://stackoverflow.com/questions/1121383/counting-the-number-of-files-in-a-directory-using-c
  196. int num_files(const char *path) {
  197. if (file_exists(path) != 0) {
  198. return -1;
  199. }
  200. int file_count = 0;
  201. DIR * dirp;
  202. struct dirent * entry;
  203. dirp = opendir(path);
  204. while ((entry = readdir(dirp)) != NULL) {
  205. if (entry->d_type == DT_REG) {
  206. file_count++;
  207. }
  208. }
  209. closedir(dirp);
  210. return file_count;
  211. }
  212. char* bundled_file(const char *filename) {
  213. return concat(bundle_path(), filename);
  214. }
  215. char* bundle_path() {
  216. CFBundleRef mainBundle = CFBundleGetMainBundle();
  217. CFURLRef resourcesURL = CFBundleCopyResourcesDirectoryURL(mainBundle);
  218. int len = 4096;
  219. char* path = malloc(len);
  220. CFURLGetFileSystemRepresentation(resourcesURL, TRUE, (UInt8*)path, len);
  221. return concat(path, "/");
  222. }
  223. int extract_bundle(const char* bundle_name, const char* directory) {
  224. int ret;
  225. char *tarFile = NULL;
  226. asprintf(&tarFile, "%s/%s", directory, bundle_name);
  227. ret = file_exists(bundled_file(bundle_name));
  228. if (ret != 0) {
  229. NSLog(@"file does not exist: %s", bundled_file(bundle_name));
  230. return -1;
  231. }
  232. ret = file_exists(directory);
  233. if (file_exists(directory) != 0) {
  234. NSLog(@"directory does not exist: %s", directory);
  235. return -2;
  236. }
  237. ret = cp(bundled_file(bundle_name), tarFile);
  238. if (ret != 0) {
  239. NSLog(@"cp has failed: %d", ret);
  240. return -3;
  241. }
  242. ret = chdir(directory);
  243. if (ret != 0) {
  244. NSLog(@"failed to chdir *rolls eyes* code %d", ret);
  245. return -4;
  246. }
  247. ret = untar(fopen(tarFile, "r"), bundle_name);
  248. NSLog(@"untar returned: %d", ret);
  249. if (ret != 0) {
  250. return -5;
  251. }
  252. ret = unlink(tarFile);
  253. if (ret != 0) {
  254. NSLog(@"now fucking `unlink` is failing tooo? %d", ret);
  255. return -6;
  256. }
  257. free(tarFile);
  258. return 0;
  259. }
  260. int extract_bundle_tar(const char *bundle_name) {
  261. const char *file_path = bundled_file(bundle_name);
  262. if (file_exists(file_path) != 0) {
  263. log_message([NSString stringWithFormat:@"Error, bundle file %s was not found at path %s!",
  264. bundle_name, file_path]);
  265. return -1;
  266. }
  267. return execprog("/meridian/tar", (const char **)&(const char*[]) {
  268. "/meridian/tar",
  269. "--preserve-permissions",
  270. "--no-overwrite-dir",
  271. "-C",
  272. "/",
  273. "-xvf",
  274. file_path,
  275. NULL
  276. });
  277. }
  278. void touch_file(char *path) {
  279. fclose(fopen(path, "w+"));
  280. }
  281. // https://stackoverflow.com/questions/8465006/how-do-i-concatenate-two-strings-in-c
  282. char* concat(const char *s1, const char *s2) {
  283. char *result = malloc(strlen(s1)+strlen(s2)+1);
  284. strcpy(result, s1);
  285. strcat(result, s2);
  286. return result;
  287. }
  288. void grant_csflags(pid_t pid) {
  289. int tries = 3;
  290. while (tries-- > 0) {
  291. uint64_t proc = find_proc_by_pid(pid);
  292. if (proc == 0) {
  293. sleep(1);
  294. continue;
  295. }
  296. uint32_t csflags = rk32(proc + 0x2a8);
  297. csflags = (csflags |
  298. CS_PLATFORM_BINARY |
  299. CS_INSTALLER |
  300. CS_GET_TASK_ALLOW)
  301. & ~(CS_RESTRICT | CS_HARD);
  302. wk32(proc + 0x2a8, csflags);
  303. break;
  304. }
  305. }
  306. // creds to stek29 on this one
  307. int execprog(const char *prog, const char* args[]) {
  308. if (args == NULL) {
  309. args = (const char **)&(const char*[]){ prog, NULL };
  310. }
  311. if (file_exists("/meridian") != 0) {
  312. mkdir("/meridian", 0755);
  313. }
  314. if (file_exists("/meridian/logs") != 0) {
  315. mkdir("/meridian/logs", 0755);
  316. }
  317. const char *logfile = [NSString stringWithFormat:@"/meridian/logs/%@-%lu",
  318. [[NSMutableString stringWithUTF8String:prog] stringByReplacingOccurrencesOfString:@"/" withString:@"_"],
  319. time(NULL)].UTF8String;
  320. NSString *prog_args = @"";
  321. for (const char **arg = args; *arg != NULL; ++arg) {
  322. prog_args = [prog_args stringByAppendingString:[NSString stringWithFormat:@"%s ", *arg]];
  323. }
  324. NSLog(@"[execprog] Spawning [ %@ ] to logfile [ %s ]", prog_args, logfile);
  325. int rv;
  326. posix_spawn_file_actions_t child_fd_actions;
  327. if ((rv = posix_spawn_file_actions_init (&child_fd_actions))) {
  328. perror ("posix_spawn_file_actions_init");
  329. return rv;
  330. }
  331. if ((rv = posix_spawn_file_actions_addopen (&child_fd_actions, STDOUT_FILENO, logfile,
  332. O_WRONLY | O_CREAT | O_TRUNC, 0666))) {
  333. perror ("posix_spawn_file_actions_addopen");
  334. return rv;
  335. }
  336. if ((rv = posix_spawn_file_actions_adddup2 (&child_fd_actions, STDOUT_FILENO, STDERR_FILENO))) {
  337. perror ("posix_spawn_file_actions_adddup2");
  338. return rv;
  339. }
  340. pid_t pd;
  341. if ((rv = posix_spawn(&pd, prog, &child_fd_actions, NULL, (char**)args, NULL))) {
  342. printf("posix_spawn error: %d (%s)\n", rv, strerror(rv));
  343. return rv;
  344. }
  345. NSLog(@"[execprog] Process spawned with pid %d", pd);
  346. grant_csflags(pd);
  347. int ret, status;
  348. do {
  349. ret = waitpid(pd, &status, 0);
  350. if (ret > 0) {
  351. NSLog(@"'%s' exited with %d (sig %d)\n", prog, WEXITSTATUS(status), WTERMSIG(status));
  352. } else if (errno != EINTR) {
  353. NSLog(@"waitpid error %d: %s\n", ret, strerror(errno));
  354. }
  355. } while (ret < 0 && errno == EINTR);
  356. char buf[65] = {0};
  357. int fd = open(logfile, O_RDONLY);
  358. if (fd == -1) {
  359. perror("open logfile");
  360. return 1;
  361. }
  362. NSLog(@"contents of %s:", logfile);
  363. NSLog(@"-------------------------");
  364. NSString *outputString = @"";
  365. while(read(fd, buf, sizeof(buf) - 1) == sizeof(buf) - 1) {
  366. outputString = [outputString stringByAppendingString:[NSString stringWithFormat:@"%s", buf]];
  367. }
  368. NSLog(@"%@", outputString);
  369. NSLog(@"-------------------------");
  370. close(fd);
  371. remove(logfile);
  372. return (int8_t)WEXITSTATUS(status);
  373. }
  374. // too lazy to find & add IOKit headers so here we are
  375. typedef mach_port_t io_service_t;
  376. typedef mach_port_t io_connect_t;
  377. extern const mach_port_t kIOMasterPortDefault;
  378. CFMutableDictionaryRef IOServiceMatching(const char *name) CF_RETURNS_RETAINED;
  379. io_service_t IOServiceGetMatchingService(mach_port_t masterPort, CFDictionaryRef matching CF_RELEASES_ARGUMENT);
  380. kern_return_t IOServiceOpen(io_service_t service, task_port_t owningTask, uint32_t type, io_connect_t *client);
  381. kern_return_t IOConnectCallAsyncStructMethod(mach_port_t connection, uint32_t selector, mach_port_t wake_port, uint64_t *reference, uint32_t referenceCnt, const void *inputStruct, size_t inputStructCnt, void *outputStruct, size_t *outputStructCnt);
  382. // credits to tihmstar
  383. void restart_device() {
  384. // open user client
  385. CFMutableDictionaryRef matching = IOServiceMatching("IOSurfaceRoot");
  386. io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, matching);
  387. io_connect_t connect = 0;
  388. IOServiceOpen(service, mach_task_self(), 0, &connect);
  389. // add notification port with same refcon multiple times
  390. mach_port_t port = 0;
  391. mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &port);
  392. uint64_t references;
  393. uint64_t input[3] = {0};
  394. input[1] = 1234; // keep refcon the same value
  395. while (1) {
  396. IOConnectCallAsyncStructMethod(connect, 17, port, &references, 1, input, sizeof(input), NULL, NULL);
  397. }
  398. }
  399. // credits to tihmstar
  400. double uptime() {
  401. struct timeval boottime;
  402. size_t len = sizeof(boottime);
  403. int mib[2] = { CTL_KERN, KERN_BOOTTIME };
  404. if (sysctl(mib, 2, &boottime, &len, NULL, 0) < 0) {
  405. return -1.0;
  406. }
  407. time_t bsec = boottime.tv_sec, csec = time(NULL);
  408. return difftime(csec, bsec);
  409. }
  410. // credits to tihmstar
  411. void suspend_all_threads() {
  412. thread_act_t other_thread, current_thread;
  413. unsigned int thread_count;
  414. thread_act_array_t thread_list;
  415. current_thread = mach_thread_self();
  416. int result = task_threads(mach_task_self(), &thread_list, &thread_count);
  417. if (result == -1) {
  418. exit(1);
  419. }
  420. if (!result && thread_count) {
  421. for (unsigned int i = 0; i < thread_count; ++i) {
  422. other_thread = thread_list[i];
  423. if (other_thread != current_thread) {
  424. int kr = thread_suspend(other_thread);
  425. if (kr != KERN_SUCCESS) {
  426. mach_error("thread_suspend:", kr);
  427. exit(1);
  428. }
  429. }
  430. }
  431. }
  432. }
  433. // credits to tihmstar
  434. void resume_all_threads() {
  435. thread_act_t other_thread, current_thread;
  436. unsigned int thread_count;
  437. thread_act_array_t thread_list;
  438. current_thread = mach_thread_self();
  439. int result = task_threads(mach_task_self(), &thread_list, &thread_count);
  440. if (!result && thread_count) {
  441. for (unsigned int i = 0; i < thread_count; ++i) {
  442. other_thread = thread_list[i];
  443. if (other_thread != current_thread) {
  444. int kr = thread_resume(other_thread);
  445. if (kr != KERN_SUCCESS) {
  446. mach_error("thread_suspend:", kr);
  447. }
  448. }
  449. }
  450. }
  451. }