pspawn_payload.m 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. #include <dlfcn.h>
  2. #include <stdio.h>
  3. #include <mach/mach.h>
  4. #include <mach/error.h>
  5. #include <mach/message.h>
  6. #include <string.h>
  7. #include <unistd.h>
  8. #include <spawn.h>
  9. #include <sys/types.h>
  10. #include <errno.h>
  11. #include <stdlib.h>
  12. #include <sys/sysctl.h>
  13. #include <dlfcn.h>
  14. #include <sys/mman.h>
  15. #include <sys/stat.h>
  16. #include <pthread.h>
  17. #include <Foundation/Foundation.h>
  18. #include "fishhook.h"
  19. #include "mach/jailbreak_daemonUser.h"
  20. int file_exist(const char *filename) {
  21. struct stat buffer;
  22. int r = stat(filename, &buffer);
  23. return (r == 0);
  24. }
  25. #define PSPAWN_PAYLOAD_DEBUG 1
  26. //#ifdef PSPAWN_PAYLOAD_DEBUG
  27. #define LAUNCHD_LOG_PATH "/var/log/pspawn_payload_launchd.log"
  28. // XXX multiple xpcproxies opening same file
  29. // XXX not closing logfile before spawn
  30. #define XPCPROXY_LOG_PATH "/var/log//pspawn_payload_xpcproxy.log"
  31. FILE *log_file;
  32. #define DEBUGLOG(fmt, args...)\
  33. do {\
  34. if (log_file == NULL) {\
  35. log_file = fopen((current_process == PROCESS_LAUNCHD) ? LAUNCHD_LOG_PATH : XPCPROXY_LOG_PATH, "a"); \
  36. if (log_file == NULL) break; \
  37. } \
  38. fprintf(log_file, fmt "\n", ##args); \
  39. fflush(log_file); \
  40. } while(0)
  41. /*
  42. #else
  43. #define DEBUGLOG(fmt, args...)
  44. #endif
  45. */
  46. #define PSPAWN_PAYLOAD_DYLIB "/electra/pspawn_payload.dylib"
  47. #define AMFID_PAYLOAD_DYLIB "/electra/amfid_payload.dylib"
  48. #define SBINJECT_PAYLOAD_DYLIB "/usr/lib/TweakInject.dylib"
  49. // since this dylib should only be loaded into launchd and xpcproxy
  50. // it's safe to assume that we're in xpcproxy if getpid() != 1
  51. enum currentprocess {
  52. PROCESS_LAUNCHD,
  53. PROCESS_XPCPROXY,
  54. };
  55. int current_process = PROCESS_XPCPROXY;
  56. #define JAILBREAKD_COMMAND_ENTITLE_AND_SIGCONT 2
  57. #define JAILBREAKD_COMMAND_ENTITLE_AND_SIGCONT_FROM_XPCPROXY 3
  58. kern_return_t bootstrap_look_up(mach_port_t port, const char *service, mach_port_t *server_port);
  59. mach_port_t jbd_port;
  60. const char* xpcproxy_blacklist[] = {
  61. "com.apple.diagnosticd", // syslog
  62. "MTLCompilerService", // ?_?
  63. "mapspushd", // stupid Apple Maps
  64. "OTAPKIAssetTool", // h_h
  65. "cfprefsd", // o_o
  66. "jailbreakd", // don't inject into jbd since we'd have to call to it
  67. "mediaremoted", // keeps remote app from working
  68. "debugserver", // keeps xcode debugging from working
  69. "reboot",
  70. //"com.nito.nitoTV4",
  71. //"com.nito.nitoTV4.nitoTVTopShelf",
  72. /*
  73. "PineBoard", // for now
  74. "com.apple.PineBoard",
  75. "com.apple.HeadBoard",
  76. "HeadBoard",
  77. "com.firecore.infuse.pro",
  78. "com.apple.accessibility.AccessibilityUIServer",
  79. "com.apple.TVAirPlay",
  80. "com.apple.mediaserverd",
  81. "com.apple.SiriViewService",
  82. "com.apple.syncdefaultsd",
  83. "com.apple.TVWatchList",
  84. "com.apple.TVAppStore",
  85. "com.apple.TVIdleScreen",
  86. "com.apple.TVSettings",
  87. */
  88. NULL
  89. };
  90. typedef int (*pspawn_t)(pid_t * pid, const char* path, const posix_spawn_file_actions_t *file_actions, posix_spawnattr_t *attrp, char const* argv[], const char* envp[]);
  91. pspawn_t old_pspawn, old_pspawnp;
  92. int fake_posix_spawn_common(pid_t * pid, const char* path, const posix_spawn_file_actions_t *file_actions, posix_spawnattr_t *attrp, char const* argv[], const char* envp[], pspawn_t old) {
  93. DEBUGLOG("We got called (fake_posix_spawn)! %s", path);
  94. const char *inject_me = NULL;
  95. if (current_process == PROCESS_LAUNCHD) {
  96. if (strcmp(path, "/usr/libexec/xpcproxy") == 0) {
  97. inject_me = PSPAWN_PAYLOAD_DYLIB;
  98. const char* startd = argv[1];
  99. if (startd != NULL) {
  100. const char **blacklist = xpcproxy_blacklist;
  101. while (*blacklist) {
  102. if (strstr(startd, *blacklist)) {
  103. DEBUGLOG("xpcproxy for '%s' which is in blacklist, not injecting", startd);
  104. inject_me = NULL;
  105. break;
  106. }
  107. ++blacklist;
  108. }
  109. }
  110. }
  111. } else if (current_process == PROCESS_XPCPROXY) {
  112. // XXX inject both SBInject & amfid payload into amfid?
  113. // note: DYLD_INSERT_LIBRARIES=libfoo1.dylib:libfoo2.dylib
  114. if (strcmp(path, "/usr/libexec/amfid") == 0) {
  115. DEBUGLOG("Starting amfid -- special handling");
  116. inject_me = AMFID_PAYLOAD_DYLIB;
  117. } else {
  118. inject_me = SBINJECT_PAYLOAD_DYLIB;
  119. }
  120. }
  121. // XXX log different err on inject_me == NULL and nonexistent inject_me
  122. if (inject_me == NULL || !file_exist(inject_me)) {
  123. DEBUGLOG("Nothing to inject");
  124. return old(pid, path, file_actions, attrp, argv, envp);
  125. }
  126. DEBUGLOG("Injecting %s into %s", inject_me, path);
  127. #ifdef PSPAWN_PAYLOAD_DEBUG
  128. if (argv != NULL){
  129. DEBUGLOG("Args: ");
  130. const char** currentarg = argv;
  131. while (*currentarg != NULL){
  132. DEBUGLOG("\t%s", *currentarg);
  133. currentarg++;
  134. }
  135. }
  136. #endif
  137. int envcount = 0;
  138. if (envp != NULL){
  139. DEBUGLOG("Env: ");
  140. const char** currentenv = envp;
  141. while (*currentenv != NULL){
  142. DEBUGLOG("\t%s", *currentenv);
  143. if (strstr(*currentenv, "DYLD_INSERT_LIBRARIES") == NULL) {
  144. envcount++;
  145. }
  146. currentenv++;
  147. }
  148. }
  149. char const** newenvp = malloc((envcount+2) * sizeof(char **));
  150. int j = 0;
  151. for (int i = 0; i < envcount; i++){
  152. if (strstr(envp[j], "DYLD_INSERT_LIBRARIES") != NULL){
  153. continue;
  154. }
  155. newenvp[i] = envp[j];
  156. j++;
  157. }
  158. char *envp_inject = malloc(strlen("DYLD_INSERT_LIBRARIES=") + strlen(inject_me) + 1);
  159. envp_inject[0] = '\0';
  160. strcat(envp_inject, "DYLD_INSERT_LIBRARIES=");
  161. strcat(envp_inject, inject_me);
  162. newenvp[j] = envp_inject;
  163. newenvp[j+1] = NULL;
  164. #if PSPAWN_PAYLOAD_DEBUG
  165. DEBUGLOG("New Env:");
  166. const char** currentenv = newenvp;
  167. while (*currentenv != NULL){
  168. DEBUGLOG("\t%s", *currentenv);
  169. currentenv++;
  170. }
  171. #endif
  172. posix_spawnattr_t attr;
  173. posix_spawnattr_t *newattrp = &attr;
  174. if (attrp) {
  175. DEBUGLOG("attrp!\n");
  176. newattrp = attrp;
  177. short flags;
  178. posix_spawnattr_getflags(attrp, &flags);
  179. flags |= POSIX_SPAWN_START_SUSPENDED;
  180. posix_spawnattr_setflags(attrp, flags);
  181. } else {
  182. DEBUGLOG("attrp else\n");
  183. posix_spawnattr_init(&attr);
  184. posix_spawnattr_setflags(&attr, POSIX_SPAWN_START_SUSPENDED);
  185. }
  186. int origret;
  187. #define FLAG_ATTRIBUTE_XPCPROXY (1 << 17)
  188. if (current_process == PROCESS_XPCPROXY) {
  189. // dont leak logging fd into execd process
  190. DEBUGLOG("dont leak logging fd into execd process\n");
  191. #ifdef PSPAWN_PAYLOAD_DEBUG
  192. if (log_file != NULL) {
  193. fclose(log_file);
  194. log_file = NULL;
  195. }
  196. #endif
  197. jbd_call(jbd_port, JAILBREAKD_COMMAND_ENTITLE_AND_SIGCONT_FROM_XPCPROXY, getpid());
  198. // dont leak jbd fd into execd process
  199. origret = old(pid, path, file_actions, newattrp, argv, newenvp);
  200. DEBUGLOG("origret %i for xpcproxy\n", origret);
  201. } else {
  202. int gotpid;
  203. origret = old(&gotpid, path, file_actions, newattrp, argv, newenvp);
  204. DEBUGLOG("origret %i for not xpcproxy\n", origret);
  205. if (origret == 0) {
  206. if (pid != NULL) *pid = gotpid;
  207. DEBUGLOG("we in here\n");
  208. jbd_call(jbd_port, JAILBREAKD_COMMAND_ENTITLE_AND_SIGCONT, gotpid);
  209. }
  210. }
  211. return origret;
  212. }
  213. int fake_posix_spawn(pid_t * pid, const char* file, const posix_spawn_file_actions_t *file_actions, posix_spawnattr_t *attrp, const char* argv[], const char* envp[]) {
  214. return fake_posix_spawn_common(pid, file, file_actions, attrp, argv, envp, old_pspawn);
  215. }
  216. int fake_posix_spawnp(pid_t * pid, const char* file, const posix_spawn_file_actions_t *file_actions, posix_spawnattr_t *attrp, const char* argv[], const char* envp[]) {
  217. return fake_posix_spawn_common(pid, file, file_actions, attrp, argv, envp, old_pspawnp);
  218. }
  219. void rebind_pspawns(void) {
  220. struct rebinding rebindings[] = {
  221. {"posix_spawn", (void *)fake_posix_spawn, (void **)&old_pspawn},
  222. {"posix_spawnp", (void *)fake_posix_spawnp, (void **)&old_pspawnp},
  223. };
  224. rebind_symbols(rebindings, 2);
  225. }
  226. void* thd_func(void* arg){
  227. NSLog(@"In a new thread!");
  228. rebind_pspawns();
  229. return NULL;
  230. }
  231. __attribute__ ((constructor))
  232. static void ctor(void) {
  233. if (getpid() == 1) {
  234. if (host_get_special_port(mach_host_self(), HOST_LOCAL_NODE, 15, &jbd_port)) {
  235. DEBUGLOG("Can't get hgsp15 :(");
  236. return;
  237. }
  238. DEBUGLOG("Got jbd port: %llx", jbd_port);
  239. current_process = PROCESS_LAUNCHD;
  240. pthread_t thd;
  241. pthread_create(&thd, NULL, thd_func, NULL);
  242. } else {
  243. if (bootstrap_look_up(bootstrap_port, "org.coolstar.jailbreakd", &jbd_port)) {
  244. DEBUGLOG("Can't get bootstrap port :(");
  245. return;
  246. }
  247. DEBUGLOG("Got jbd port: %llx", jbd_port);
  248. current_process = PROCESS_XPCPROXY;
  249. rebind_pspawns();
  250. }
  251. }