123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250 |
- #include "helpers/kmem.h"
- #include "kern_utils.h"
- #include "sandbox.h"
- #include "helpers/patchfinder64.h"
- #include "helpers/kexecute.h"
- typedef uint64_t extension_hdr_t;
- typedef uint64_t extension_t;
- struct extension_hdr {
- /* 0x00 */ extension_hdr_t next;
- /* 0x08 */ uint64_t desc;
- /* 0x10 */ extension_t ext_lst;
- /* 0x18 */
- };
- struct extension {
- /* 0x00 */ extension_t next;
- /* 0x08 */ uint64_t desc; // always 0xffffffffffffffff
- /* 0x10 */ uint64_t ext_lst; // zero, since it's extension and not a header
- /* 0x18 */ uint8_t something[32]; // zeroed from what I've seen
- /* 0x38 */ uint32_t type; // see ext_type enum
- /* 0x3c */ uint32_t subtype; // either 0 or 4 (or whatever unhex gave?..)
- /* 0x40 */ uint64_t data; // a c string, meaning depends on type and hdr which had this extension
- /* 0x48 */ uint64_t data_len; // strlen(data)
- /* 0x50 */ uint64_t unk0; // always 0
- /* 0x58 */ uint64_t unk1; // always 0xdeadbeefdeadbeef
- /* 0x60 */
- };
- uint64_t _smalloc(uint64_t size) {
- return kexecute(find_smalloc(), size, 0, 0, 0, 0, 0, 0);
- }
- uint64_t smalloc(uint64_t size) {
- uint64_t ret = _smalloc(size);
-
- if (ret != 0) {
- // IOAlloc's of small size go to zalloc
- ret = zm_fix_addr(ret);
- }
-
- return ret;
- }
- uint64_t sstrdup(const char* s) {
- size_t slen = strlen(s) + 1;
-
- uint64_t ks = smalloc(slen);
- if (ks) {
- kwrite(ks, s, slen);
- }
-
- return ks;
- }
- // Notice: path should *not* end with '/' !
- uint64_t extension_create_file(const char* path, uint64_t nextptr) {
- size_t slen = strlen(path);
-
- if (path[slen - 1] == '/') {
- fprintf(stderr, "No traling slash in path pls \n");
- return 0;
- }
-
- uint64_t ext_p = smalloc(sizeof(struct extension));
- uint64_t ks = sstrdup(path);
-
- if (ext_p && ks) {
- struct extension ext;
- bzero(&ext, sizeof(ext));
- ext.next = nextptr;
- ext.desc = 0xffffffffffffffff;
-
- ext.data = ks;
- ext.data_len = slen;
-
- kwrite(ext_p, &ext, sizeof(ext));
- } else {
- // XXX oh no a leak
- }
-
- return ext_p;
- }
- // get 64 higher bits of 64bit int multiplication
- // https://stackoverflow.com/a/28904636
- // ofc in asm it's done with 1 instruction huh
- // XXX there has to be a cleaner way utilizing hardware support
- uint64_t mulhi(uint64_t a, uint64_t b) {
- uint64_t a_lo = (uint32_t)a;
- uint64_t a_hi = a >> 32;
- uint64_t b_lo = (uint32_t)b;
- uint64_t b_hi = b >> 32;
-
- uint64_t a_x_b_hi = a_hi * b_hi;
- uint64_t a_x_b_mid = a_hi * b_lo;
- uint64_t b_x_a_mid = b_hi * a_lo;
- uint64_t a_x_b_lo = a_lo * b_lo;
-
- uint64_t carry_bit = ((uint64_t)(uint32_t)a_x_b_mid +
- (uint64_t)(uint32_t)b_x_a_mid +
- (a_x_b_lo >> 32) ) >> 32;
-
- uint64_t multhi = a_x_b_hi +
- (a_x_b_mid >> 32) + (b_x_a_mid >> 32) +
- carry_bit;
-
- return multhi;
- }
- int hashing_magic(const char *desc) {
- // inlined into exception_add
- uint64_t hashed = 0x1505;
-
- // if desc == NULL, then returned value would be 8
- // APPL optimizes it for some reason
- // but meh, desc should never be NULL or you get
- // null dereference in exception_add
- // if (desc == NULL) return 8;
-
- if (desc != NULL) {
- for (const char* dp = desc; *dp != '\0'; ++dp) {
- hashed += hashed << 5;
- hashed += (int64_t) *dp;
- }
- }
-
- uint64_t magic = 0xe38e38e38e38e38f;
-
- uint64_t hi = mulhi(hashed, magic);
- hi >>= 3;
- hi = (hi<<3) + hi;
-
- hashed -= hi;
-
- return hashed;
- }
- static const char *ent_key = "com.apple.security.exception.files.absolute-path.read-only";
- uint64_t make_ext_hdr(const char* key, uint64_t ext_lst) {
- struct extension_hdr hdr;
-
- uint64_t khdr = smalloc(sizeof(hdr));
-
- if (khdr) {
- // we add headers to end
- hdr.next = 0;
- hdr.desc = sstrdup(key);
- if (hdr.desc == 0) {
- // XXX leak
- return 0;
- }
-
- hdr.ext_lst = ext_lst;
- kwrite(khdr, &hdr, sizeof(hdr));
- }
-
- return khdr;
- }
- void extension_add(uint64_t ext, uint64_t sb, const char* desc) {
- // XXX patchfinder + kexecute would be way better
-
- int slot = hashing_magic(ent_key);
- uint64_t insert_at_p = sb + sizeof(void*) + slot * sizeof(void*);
- uint64_t insert_at = rk64(insert_at_p);
-
- while (insert_at != 0) {
- uint64_t kdsc = rk64(insert_at + offsetof(struct extension_hdr, desc));
-
- if (kstrcmp(kdsc, desc) == 0) {
- break;
- }
-
- insert_at_p = insert_at;
- insert_at = rk64(insert_at);
- }
-
- if (insert_at == 0) {
- insert_at = make_ext_hdr(ent_key, ext);
- wk64(insert_at_p, insert_at);
- } else {
- // XXX no duplicate check
- uint64_t ext_lst_p = insert_at + offsetof(struct extension_hdr, ext_lst);
- uint64_t ext_lst = rk64(ext_lst_p);
-
- while (ext_lst != 0) {
- fprintf(stderr, "ext_lst_p = 0x%llx ext_lst = 0x%llx\n", ext_lst_p, ext_lst);
- ext_lst_p = ext_lst + offsetof(struct extension, next);
- ext_lst = rk64(ext_lst_p);
- }
-
- fprintf(stderr, "ext_lst_p = 0x%llx ext_lst = 0x%llx\n", ext_lst_p, ext_lst);
-
- wk64(ext_lst_p, ext);
- }
- }
- // 1 if yes
- int has_file_extension(uint64_t sb, const char* path) {
- const char* desc = ent_key;
- int found = 0;
-
- int slot = hashing_magic(ent_key);
- uint64_t insert_at_p = sb + sizeof(void*) + slot * sizeof(void*);
- uint64_t insert_at = rk64(insert_at_p);
-
- while (insert_at != 0) {
- uint64_t kdsc = rk64(insert_at + offsetof(struct extension_hdr, desc));
-
- if (kstrcmp(kdsc, desc) == 0) {
- break;
- }
-
- insert_at_p = insert_at;
- insert_at = rk64(insert_at);
- }
-
- if (insert_at != 0) {
- uint64_t ext_lst = rk64(insert_at + offsetof(struct extension_hdr, ext_lst));
-
- uint64_t plen = strlen(path);
- char *exist = malloc(plen + 1);
- exist[plen] = '\0';
-
- while (ext_lst != 0) {
- // XXX no type/subtype check
- uint64_t data_len = rk64(ext_lst + offsetof(struct extension, data_len));
- if (data_len == plen) {
- uint64_t data = rk64(ext_lst + offsetof(struct extension, data));
- kread(data, exist, plen);
-
- if (strcmp(path, exist) == 0) {
- found = 1;
- break;
- }
- }
-
- ext_lst = rk64(ext_lst);
- }
-
-
- free(exist);
- }
-
- return found;
- }
|