sandbox.m 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. #include "helpers/kmem.h"
  2. #include "kern_utils.h"
  3. #include "sandbox.h"
  4. #include "helpers/patchfinder64.h"
  5. #include "helpers/kexecute.h"
  6. typedef uint64_t extension_hdr_t;
  7. typedef uint64_t extension_t;
  8. struct extension_hdr {
  9. /* 0x00 */ extension_hdr_t next;
  10. /* 0x08 */ uint64_t desc;
  11. /* 0x10 */ extension_t ext_lst;
  12. /* 0x18 */
  13. };
  14. struct extension {
  15. /* 0x00 */ extension_t next;
  16. /* 0x08 */ uint64_t desc; // always 0xffffffffffffffff
  17. /* 0x10 */ uint64_t ext_lst; // zero, since it's extension and not a header
  18. /* 0x18 */ uint8_t something[32]; // zeroed from what I've seen
  19. /* 0x38 */ uint32_t type; // see ext_type enum
  20. /* 0x3c */ uint32_t subtype; // either 0 or 4 (or whatever unhex gave?..)
  21. /* 0x40 */ uint64_t data; // a c string, meaning depends on type and hdr which had this extension
  22. /* 0x48 */ uint64_t data_len; // strlen(data)
  23. /* 0x50 */ uint64_t unk0; // always 0
  24. /* 0x58 */ uint64_t unk1; // always 0xdeadbeefdeadbeef
  25. /* 0x60 */
  26. };
  27. uint64_t _smalloc(uint64_t size) {
  28. return kexecute(find_smalloc(), size, 0, 0, 0, 0, 0, 0);
  29. }
  30. uint64_t smalloc(uint64_t size) {
  31. uint64_t ret = _smalloc(size);
  32. if (ret != 0) {
  33. // IOAlloc's of small size go to zalloc
  34. ret = zm_fix_addr(ret);
  35. }
  36. return ret;
  37. }
  38. uint64_t sstrdup(const char* s) {
  39. size_t slen = strlen(s) + 1;
  40. uint64_t ks = smalloc(slen);
  41. if (ks) {
  42. kwrite(ks, s, slen);
  43. }
  44. return ks;
  45. }
  46. // Notice: path should *not* end with '/' !
  47. uint64_t extension_create_file(const char* path, uint64_t nextptr) {
  48. size_t slen = strlen(path);
  49. if (path[slen - 1] == '/') {
  50. fprintf(stderr, "No traling slash in path pls \n");
  51. return 0;
  52. }
  53. uint64_t ext_p = smalloc(sizeof(struct extension));
  54. uint64_t ks = sstrdup(path);
  55. if (ext_p && ks) {
  56. struct extension ext;
  57. bzero(&ext, sizeof(ext));
  58. ext.next = nextptr;
  59. ext.desc = 0xffffffffffffffff;
  60. ext.data = ks;
  61. ext.data_len = slen;
  62. kwrite(ext_p, &ext, sizeof(ext));
  63. } else {
  64. // XXX oh no a leak
  65. }
  66. return ext_p;
  67. }
  68. // get 64 higher bits of 64bit int multiplication
  69. // https://stackoverflow.com/a/28904636
  70. // ofc in asm it's done with 1 instruction huh
  71. // XXX there has to be a cleaner way utilizing hardware support
  72. uint64_t mulhi(uint64_t a, uint64_t b) {
  73. uint64_t a_lo = (uint32_t)a;
  74. uint64_t a_hi = a >> 32;
  75. uint64_t b_lo = (uint32_t)b;
  76. uint64_t b_hi = b >> 32;
  77. uint64_t a_x_b_hi = a_hi * b_hi;
  78. uint64_t a_x_b_mid = a_hi * b_lo;
  79. uint64_t b_x_a_mid = b_hi * a_lo;
  80. uint64_t a_x_b_lo = a_lo * b_lo;
  81. uint64_t carry_bit = ((uint64_t)(uint32_t)a_x_b_mid +
  82. (uint64_t)(uint32_t)b_x_a_mid +
  83. (a_x_b_lo >> 32) ) >> 32;
  84. uint64_t multhi = a_x_b_hi +
  85. (a_x_b_mid >> 32) + (b_x_a_mid >> 32) +
  86. carry_bit;
  87. return multhi;
  88. }
  89. int hashing_magic(const char *desc) {
  90. // inlined into exception_add
  91. uint64_t hashed = 0x1505;
  92. // if desc == NULL, then returned value would be 8
  93. // APPL optimizes it for some reason
  94. // but meh, desc should never be NULL or you get
  95. // null dereference in exception_add
  96. // if (desc == NULL) return 8;
  97. if (desc != NULL) {
  98. for (const char* dp = desc; *dp != '\0'; ++dp) {
  99. hashed += hashed << 5;
  100. hashed += (int64_t) *dp;
  101. }
  102. }
  103. uint64_t magic = 0xe38e38e38e38e38f;
  104. uint64_t hi = mulhi(hashed, magic);
  105. hi >>= 3;
  106. hi = (hi<<3) + hi;
  107. hashed -= hi;
  108. return hashed;
  109. }
  110. static const char *ent_key = "com.apple.security.exception.files.absolute-path.read-only";
  111. uint64_t make_ext_hdr(const char* key, uint64_t ext_lst) {
  112. struct extension_hdr hdr;
  113. uint64_t khdr = smalloc(sizeof(hdr));
  114. if (khdr) {
  115. // we add headers to end
  116. hdr.next = 0;
  117. hdr.desc = sstrdup(key);
  118. if (hdr.desc == 0) {
  119. // XXX leak
  120. return 0;
  121. }
  122. hdr.ext_lst = ext_lst;
  123. kwrite(khdr, &hdr, sizeof(hdr));
  124. }
  125. return khdr;
  126. }
  127. void extension_add(uint64_t ext, uint64_t sb, const char* desc) {
  128. // XXX patchfinder + kexecute would be way better
  129. int slot = hashing_magic(ent_key);
  130. uint64_t insert_at_p = sb + sizeof(void*) + slot * sizeof(void*);
  131. uint64_t insert_at = rk64(insert_at_p);
  132. while (insert_at != 0) {
  133. uint64_t kdsc = rk64(insert_at + offsetof(struct extension_hdr, desc));
  134. if (kstrcmp(kdsc, desc) == 0) {
  135. break;
  136. }
  137. insert_at_p = insert_at;
  138. insert_at = rk64(insert_at);
  139. }
  140. if (insert_at == 0) {
  141. insert_at = make_ext_hdr(ent_key, ext);
  142. wk64(insert_at_p, insert_at);
  143. } else {
  144. // XXX no duplicate check
  145. uint64_t ext_lst_p = insert_at + offsetof(struct extension_hdr, ext_lst);
  146. uint64_t ext_lst = rk64(ext_lst_p);
  147. while (ext_lst != 0) {
  148. fprintf(stderr, "ext_lst_p = 0x%llx ext_lst = 0x%llx\n", ext_lst_p, ext_lst);
  149. ext_lst_p = ext_lst + offsetof(struct extension, next);
  150. ext_lst = rk64(ext_lst_p);
  151. }
  152. fprintf(stderr, "ext_lst_p = 0x%llx ext_lst = 0x%llx\n", ext_lst_p, ext_lst);
  153. wk64(ext_lst_p, ext);
  154. }
  155. }
  156. // 1 if yes
  157. int has_file_extension(uint64_t sb, const char* path) {
  158. const char* desc = ent_key;
  159. int found = 0;
  160. int slot = hashing_magic(ent_key);
  161. uint64_t insert_at_p = sb + sizeof(void*) + slot * sizeof(void*);
  162. uint64_t insert_at = rk64(insert_at_p);
  163. while (insert_at != 0) {
  164. uint64_t kdsc = rk64(insert_at + offsetof(struct extension_hdr, desc));
  165. if (kstrcmp(kdsc, desc) == 0) {
  166. break;
  167. }
  168. insert_at_p = insert_at;
  169. insert_at = rk64(insert_at);
  170. }
  171. if (insert_at != 0) {
  172. uint64_t ext_lst = rk64(insert_at + offsetof(struct extension_hdr, ext_lst));
  173. uint64_t plen = strlen(path);
  174. char *exist = malloc(plen + 1);
  175. exist[plen] = '\0';
  176. while (ext_lst != 0) {
  177. // XXX no type/subtype check
  178. uint64_t data_len = rk64(ext_lst + offsetof(struct extension, data_len));
  179. if (data_len == plen) {
  180. uint64_t data = rk64(ext_lst + offsetof(struct extension, data));
  181. kread(data, exist, plen);
  182. if (strcmp(path, exist) == 0) {
  183. found = 1;
  184. break;
  185. }
  186. }
  187. ext_lst = rk64(ext_lst);
  188. }
  189. free(exist);
  190. }
  191. return found;
  192. }