757 lines
21 KiB
C
757 lines
21 KiB
C
// SPDX-FileCopyrightText: 2018 pancake <pancake@nopcode.org>
|
|
// SPDX-FileCopyrightText: 2021 keegan
|
|
// SPDX-License-Identifier: LGPL-3.0-only
|
|
|
|
#include <rz_types.h>
|
|
#include <rz_util.h>
|
|
#include <rz_lib.h>
|
|
#include <rz_bin.h>
|
|
#include <rz_core.h>
|
|
#include <rz_io.h>
|
|
#include "../format/mach0/dyldcache.h"
|
|
#include "objc/mach0_classes.h"
|
|
|
|
#define RZ_DYLDCACHE_VFILE_NAME_REBASED "rebased"
|
|
|
|
static ut64 bin_obj_va2pa(ut64 p, ut32 *offset, ut32 *left, RzBinFile *bf) {
|
|
if (!bf || !bf->o || !bf->o->bin_obj) {
|
|
return 0;
|
|
}
|
|
RzDyldCache *cache = (RzDyldCache *)((struct MACH0_(obj_t) *)bf->o->bin_obj)->user;
|
|
if (!cache) {
|
|
return 0;
|
|
}
|
|
return rz_dyldcache_va2pa(cache, p, offset, left);
|
|
}
|
|
|
|
static struct MACH0_(obj_t) * bin_to_mach0(RzBinFile *bf, RzDyldBinImage *bin) {
|
|
if (!bin || !bf) {
|
|
return NULL;
|
|
}
|
|
|
|
RzDyldCache *cache = (RzDyldCache *)bf->o->bin_obj;
|
|
if (!cache) {
|
|
return NULL;
|
|
}
|
|
|
|
RzBuffer *buf = rz_buf_new_slice(cache->buf, bin->hdr_offset, rz_buf_size(cache->buf) - bin->hdr_offset);
|
|
if (!buf) {
|
|
return NULL;
|
|
}
|
|
|
|
struct MACH0_(opts_t) opts;
|
|
MACH0_(opts_set_default)
|
|
(&opts, bf);
|
|
opts.header_at = bin->header_at - bin->hdr_offset;
|
|
opts.symbols_off = bin->symbols_off;
|
|
|
|
struct MACH0_(obj_t) *mach0 = MACH0_(new_buf)(buf, &opts);
|
|
if (!mach0) {
|
|
return NULL;
|
|
}
|
|
|
|
mach0->user = cache;
|
|
mach0->va2pa = &bin_obj_va2pa;
|
|
|
|
rz_buf_free(buf);
|
|
|
|
return mach0;
|
|
}
|
|
|
|
static bool check_buffer(RzBuffer *buf) {
|
|
if (rz_buf_size(buf) < 32) {
|
|
return false;
|
|
}
|
|
|
|
char hdr[17] = { 0 };
|
|
int rzhdr = rz_buf_read_at(buf, 0, (ut8 *)&hdr, sizeof(hdr) - 1);
|
|
if (rzhdr != sizeof(hdr) - 1) {
|
|
return false;
|
|
}
|
|
|
|
return rz_dyldcache_check_magic(hdr);
|
|
}
|
|
|
|
static bool load_buffer(RzBinFile *bf, RzBinObject *obj, RzBuffer *buf, Sdb *sdb) {
|
|
RzDyldCache *cache = rz_dyldcache_new_buf(buf);
|
|
if (!cache) {
|
|
return false;
|
|
}
|
|
obj->bin_obj = cache;
|
|
return true;
|
|
}
|
|
|
|
static RzPVector /*<RzBinAddr *>*/ *entries(RzBinFile *bf) {
|
|
RzBinAddr *ptr = NULL;
|
|
RzPVector *ret = rz_pvector_new(free);
|
|
if (!ret) {
|
|
return NULL;
|
|
}
|
|
if ((ptr = RZ_NEW0(RzBinAddr))) {
|
|
rz_pvector_push(ret, ptr);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static RzBinInfo *info(RzBinFile *bf) {
|
|
RzBinInfo *ret = NULL;
|
|
|
|
if (!bf || !bf->o) {
|
|
return NULL;
|
|
}
|
|
|
|
RzDyldCache *cache = (RzDyldCache *)bf->o->bin_obj;
|
|
if (!cache) {
|
|
return NULL;
|
|
}
|
|
|
|
bool big_endian = 0;
|
|
if (!(ret = RZ_NEW0(RzBinInfo))) {
|
|
return NULL;
|
|
}
|
|
ret->file = strdup(bf->file);
|
|
ret->bclass = strdup("dyldcache");
|
|
ret->os = strdup(rz_dyldcache_get_platform_str(cache));
|
|
if (strstr(cache->hdr->magic, "x86_64")) {
|
|
ret->arch = strdup("x86");
|
|
ret->bits = 64;
|
|
} else {
|
|
ret->arch = strdup("arm");
|
|
ret->bits = strstr(cache->hdr->magic, "arm64") ? 64 : 32;
|
|
}
|
|
ret->machine = strdup(ret->arch);
|
|
ret->subsystem = strdup("xnu");
|
|
ret->guid = rz_hex_bin2strdup((ut8 *)cache->hdr->uuid, sizeof(cache->hdr->uuid));
|
|
ret->type = strdup(rz_dyldcache_get_type_str(cache));
|
|
ret->has_va = true;
|
|
ret->big_endian = big_endian;
|
|
ret->dbg_info = 0;
|
|
return ret;
|
|
}
|
|
|
|
static ut64 baddr(RzBinFile *bf) {
|
|
// XXX hardcoded
|
|
return 0x180000000;
|
|
}
|
|
|
|
void symbols_from_bin(RzDyldCache *cache, RzPVector /*<RzBinSymbol *>*/ *ret, RzBinFile *bf, RzDyldBinImage *bin, SetU *hash) {
|
|
struct MACH0_(obj_t) *mach0 = bin_to_mach0(bf, bin);
|
|
if (!mach0) {
|
|
return;
|
|
}
|
|
|
|
const struct symbol_t *symbols = MACH0_(get_symbols)(mach0);
|
|
if (!symbols) {
|
|
return;
|
|
}
|
|
int i;
|
|
for (i = 0; !symbols[i].last; i++) {
|
|
if (!symbols[i].name || !symbols[i].name[0] || symbols[i].addr < 100) {
|
|
continue;
|
|
}
|
|
if (strstr(symbols[i].name, "<redacted>")) {
|
|
continue;
|
|
}
|
|
RzBinSymbol *sym = RZ_NEW0(RzBinSymbol);
|
|
if (!sym) {
|
|
break;
|
|
}
|
|
sym->name = strdup(symbols[i].name);
|
|
sym->vaddr = symbols[i].addr;
|
|
sym->forwarder = "NONE";
|
|
sym->bind = (symbols[i].type == RZ_BIN_MACH0_SYMBOL_TYPE_LOCAL) ? RZ_BIN_BIND_LOCAL_STR : RZ_BIN_BIND_GLOBAL_STR;
|
|
sym->type = RZ_BIN_TYPE_FUNC_STR;
|
|
sym->paddr = symbols[i].offset + bf->o->boffset;
|
|
sym->size = symbols[i].size;
|
|
sym->ordinal = i;
|
|
|
|
set_u_add(hash, sym->vaddr);
|
|
rz_pvector_push(ret, sym);
|
|
}
|
|
MACH0_(mach0_free)
|
|
(mach0);
|
|
}
|
|
|
|
static bool __is_data_section(const char *name) {
|
|
if (strstr(name, "_cstring")) {
|
|
return true;
|
|
}
|
|
if (strstr(name, "_os_log")) {
|
|
return true;
|
|
}
|
|
if (strstr(name, "_objc_methname")) {
|
|
return true;
|
|
}
|
|
if (strstr(name, "_objc_classname")) {
|
|
return true;
|
|
}
|
|
if (strstr(name, "_objc_methtype")) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static void sections_from_bin(RzPVector /*<RzBinSection *>*/ *ret, RzBinFile *bf, RzDyldBinImage *bin) {
|
|
RzDyldCache *cache = (RzDyldCache *)bf->o->bin_obj;
|
|
if (!cache) {
|
|
return;
|
|
}
|
|
|
|
struct MACH0_(obj_t) *mach0 = bin_to_mach0(bf, bin);
|
|
if (!mach0) {
|
|
return;
|
|
}
|
|
|
|
struct section_t *sections = NULL;
|
|
if (!(sections = MACH0_(get_sections)(mach0))) {
|
|
return;
|
|
}
|
|
|
|
int i;
|
|
for (i = 0; !sections[i].last; i++) {
|
|
RzBinSection *ptr = RZ_NEW0(RzBinSection);
|
|
if (!ptr) {
|
|
break;
|
|
}
|
|
if (bin->file) {
|
|
ptr->name = rz_str_newf("%s.%s", bin->file, (char *)sections[i].name);
|
|
} else {
|
|
ptr->name = rz_str_newf("%s", (char *)sections[i].name);
|
|
}
|
|
if (strstr(ptr->name, "la_symbol_ptr")) {
|
|
int len = sections[i].size / 8;
|
|
ptr->format = rz_str_newf("Cd %d %d", 8, len);
|
|
}
|
|
ptr->is_data = __is_data_section(ptr->name);
|
|
ptr->size = sections[i].size;
|
|
ptr->vsize = sections[i].vsize;
|
|
ptr->vaddr = sections[i].addr;
|
|
ptr->paddr = rz_dyldcache_va2pa(cache, sections[i].addr, NULL, NULL);
|
|
if (!ptr->vaddr) {
|
|
ptr->vaddr = ptr->paddr;
|
|
}
|
|
ptr->perm = sections[i].perm;
|
|
rz_pvector_push(ret, ptr);
|
|
}
|
|
free(sections);
|
|
MACH0_(mach0_free)
|
|
(mach0);
|
|
}
|
|
|
|
static RzPVector /*<RzBinVirtualFile *>*/ *virtual_files(RzBinFile *bf) {
|
|
RzPVector *ret = rz_pvector_new((RzPVectorFree)rz_bin_virtual_file_free);
|
|
if (!ret) {
|
|
return NULL;
|
|
}
|
|
RzDyldCache *cache = (RzDyldCache *)bf->o->bin_obj;
|
|
if (rz_dyldcache_needs_rebasing(cache)) {
|
|
RzBinVirtualFile *vf = RZ_NEW0(RzBinVirtualFile);
|
|
if (!vf) {
|
|
return ret;
|
|
}
|
|
vf->buf = rz_dyldcache_new_rebasing_buf(cache);
|
|
vf->buf_owned = true;
|
|
vf->name = strdup(RZ_DYLDCACHE_VFILE_NAME_REBASED);
|
|
rz_pvector_push(ret, vf);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static int prot2perm(int x) {
|
|
int r = 0;
|
|
if (x & 1) {
|
|
r |= 4;
|
|
}
|
|
if (x & 2) {
|
|
r |= 2;
|
|
}
|
|
if (x & 4) {
|
|
r |= 1;
|
|
}
|
|
return r;
|
|
}
|
|
|
|
static RzPVector /*<RzBinMap *>*/ *maps(RzBinFile *bf) {
|
|
RzDyldCache *cache = (RzDyldCache *)bf->o->bin_obj;
|
|
if (!cache) {
|
|
return NULL;
|
|
}
|
|
RzPVector *ret = rz_pvector_new((RzPVectorFree)rz_bin_map_free);
|
|
if (!ret) {
|
|
return NULL;
|
|
}
|
|
ut64 slide = rz_dyldcache_get_slide(cache);
|
|
for (ut32 i = 0; i < cache->n_maps; i++) {
|
|
RzBinMap *map = RZ_NEW0(RzBinMap);
|
|
if (!map) {
|
|
rz_pvector_free(ret);
|
|
return NULL;
|
|
}
|
|
map->name = rz_str_newf("cache_map.%d", i);
|
|
map->paddr = cache->maps[i].fileOffset;
|
|
map->psize = cache->maps[i].size;
|
|
map->vsize = map->psize;
|
|
map->vaddr = cache->maps[i].address + slide;
|
|
map->perm = prot2perm(cache->maps[i].initProt);
|
|
if (rz_dyldcache_range_needs_rebasing(cache, map->paddr, map->psize)) {
|
|
map->vfile_name = strdup(RZ_DYLDCACHE_VFILE_NAME_REBASED);
|
|
}
|
|
rz_pvector_push(ret, map);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static RzPVector /*<RzBinSection *>*/ *sections(RzBinFile *bf) {
|
|
RzDyldCache *cache = (RzDyldCache *)bf->o->bin_obj;
|
|
if (!cache) {
|
|
return NULL;
|
|
}
|
|
RzPVector *ret = rz_pvector_new((RzPVectorFree)rz_bin_section_free);
|
|
if (!ret) {
|
|
return NULL;
|
|
}
|
|
RzListIter *iter;
|
|
RzDyldBinImage *bin;
|
|
rz_list_foreach (cache->bins, iter, bin) {
|
|
sections_from_bin(ret, bf, bin);
|
|
}
|
|
ut64 slide = rz_dyldcache_get_slide(cache);
|
|
if (slide) {
|
|
RzBinSection *section;
|
|
void **it;
|
|
rz_pvector_foreach (ret, it) {
|
|
section = *it;
|
|
section->vaddr += slide;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static RzPVector /*<RzBinSymbol *>*/ *symbols(RzBinFile *bf) {
|
|
RzDyldCache *cache = (RzDyldCache *)bf->o->bin_obj;
|
|
if (!cache) {
|
|
return NULL;
|
|
}
|
|
|
|
RzPVector *ret = rz_pvector_new((RzPVectorFree)rz_bin_symbol_free);
|
|
if (!ret) {
|
|
return NULL;
|
|
}
|
|
|
|
RzListIter *iter;
|
|
RzDyldBinImage *bin;
|
|
rz_list_foreach (cache->bins, iter, bin) {
|
|
SetU *hash = set_u_new();
|
|
if (!hash) {
|
|
rz_pvector_free(ret);
|
|
return NULL;
|
|
}
|
|
symbols_from_bin(cache, ret, bf, bin, hash);
|
|
rz_dyldcache_symbols_from_locsym(cache, bin, ret, hash);
|
|
set_u_free(hash);
|
|
}
|
|
|
|
ut64 slide = rz_dyldcache_get_slide(cache);
|
|
if (slide) {
|
|
RzBinSymbol *sym;
|
|
void **it;
|
|
rz_pvector_foreach (ret, it) {
|
|
sym = *it;
|
|
sym->vaddr += slide;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void destroy(RzBinFile *bf) {
|
|
RzDyldCache *cache = (RzDyldCache *)bf->o->bin_obj;
|
|
rz_dyldcache_free(cache);
|
|
}
|
|
|
|
static RzPVector /*<RzBinClass *>*/ *classes(RzBinFile *bf) {
|
|
RzDyldCache *cache = (RzDyldCache *)bf->o->bin_obj;
|
|
if (!cache) {
|
|
return NULL;
|
|
}
|
|
|
|
RzPVector *ret = rz_pvector_new(free);
|
|
if (!ret) {
|
|
return NULL;
|
|
}
|
|
|
|
if (!cache->objc_opt_info_loaded) {
|
|
cache->oi = rz_dyldcache_get_objc_opt_info(bf, cache);
|
|
cache->objc_opt_info_loaded = true;
|
|
}
|
|
|
|
RzListIter *iter;
|
|
RzDyldBinImage *bin;
|
|
|
|
RzBuffer *buf = bf->buf;
|
|
RzBuffer *owned_buf = NULL;
|
|
if (rz_dyldcache_needs_rebasing(cache)) {
|
|
owned_buf = rz_dyldcache_new_rebasing_buf(cache);
|
|
if (!owned_buf) {
|
|
goto beach;
|
|
}
|
|
buf = owned_buf;
|
|
}
|
|
|
|
ut32 num_of_unnamed_class = 0;
|
|
rz_list_foreach (cache->bins, iter, bin) {
|
|
struct MACH0_(obj_t) *mach0 = bin_to_mach0(bf, bin);
|
|
if (!mach0) {
|
|
goto beach;
|
|
}
|
|
|
|
struct section_t *sections = NULL;
|
|
if (!(sections = MACH0_(get_sections)(mach0))) {
|
|
MACH0_(mach0_free)
|
|
(mach0);
|
|
goto beach;
|
|
}
|
|
|
|
int i;
|
|
for (i = 0; !sections[i].last; i++) {
|
|
if (sections[i].size == 0) {
|
|
continue;
|
|
}
|
|
|
|
bool is_classlist = strstr(sections[i].name, "__objc_classlist");
|
|
bool is_catlist = strstr(sections[i].name, "__objc_catlist");
|
|
|
|
if (!is_classlist && !is_catlist) {
|
|
continue;
|
|
}
|
|
|
|
ut8 *pointers = malloc(sections[i].size);
|
|
if (!pointers) {
|
|
continue;
|
|
}
|
|
|
|
ut64 offset = rz_dyldcache_va2pa(cache, sections[i].addr, NULL, NULL);
|
|
if (rz_buf_read_at(buf, offset, pointers, sections[i].size) < sections[i].size) {
|
|
RZ_FREE(pointers);
|
|
continue;
|
|
}
|
|
ut8 *cursor = pointers;
|
|
ut8 *pointers_end = pointers + sections[i].size;
|
|
|
|
for (; cursor < pointers_end; cursor += 8) {
|
|
if ((cursor + 8) > pointers_end) {
|
|
MACH0_(mach0_free)
|
|
(mach0);
|
|
goto beach;
|
|
}
|
|
ut64 pointer_to_class = rz_read_le64(cursor);
|
|
|
|
RzBinClass *klass;
|
|
if (!(klass = RZ_NEW0(RzBinClass)) ||
|
|
!(klass->methods = rz_list_new()) ||
|
|
!(klass->fields = rz_list_new())) {
|
|
RZ_FREE(klass);
|
|
RZ_FREE(pointers);
|
|
RZ_FREE(sections);
|
|
MACH0_(mach0_free)
|
|
(mach0);
|
|
goto beach;
|
|
}
|
|
|
|
bf->o->bin_obj = mach0;
|
|
if (is_classlist) {
|
|
MACH0_(get_class_t)
|
|
(pointer_to_class, bf, buf, klass, false, NULL, cache->oi);
|
|
} else {
|
|
MACH0_(get_category_t)
|
|
(pointer_to_class, bf, buf, klass, NULL, cache->oi);
|
|
}
|
|
bf->o->bin_obj = cache;
|
|
|
|
if (!klass->name) {
|
|
RZ_LOG_ERROR("CLASS ERROR AT 0x%llx, is_classlist %d\n", pointer_to_class, is_classlist);
|
|
klass->name = rz_str_newf("UnnamedClass%u", num_of_unnamed_class);
|
|
if (!klass->name) {
|
|
RZ_FREE(klass);
|
|
RZ_FREE(pointers);
|
|
RZ_FREE(sections);
|
|
MACH0_(mach0_free)
|
|
(mach0);
|
|
goto beach;
|
|
}
|
|
num_of_unnamed_class++;
|
|
}
|
|
rz_pvector_push(ret, klass);
|
|
}
|
|
|
|
RZ_FREE(pointers);
|
|
}
|
|
|
|
RZ_FREE(sections);
|
|
MACH0_(mach0_free)
|
|
(mach0);
|
|
}
|
|
|
|
return ret;
|
|
|
|
beach:
|
|
rz_pvector_free(ret);
|
|
rz_buf_free(owned_buf);
|
|
return NULL;
|
|
}
|
|
|
|
static void header(RzBinFile *bf) {
|
|
if (!bf || !bf->o) {
|
|
return;
|
|
}
|
|
|
|
RzDyldCache *cache = (RzDyldCache *)bf->o->bin_obj;
|
|
if (!cache) {
|
|
return;
|
|
}
|
|
|
|
RzBin *bin = bf->rbin;
|
|
ut64 slide = rz_dyldcache_get_slide(cache);
|
|
PrintfCallback p = bin->cb_printf;
|
|
|
|
PJ *pj = pj_new();
|
|
if (!pj) {
|
|
return;
|
|
}
|
|
|
|
pj_o(pj);
|
|
|
|
pj_k(pj, "version");
|
|
RzDyldCacheHeaderVersion ver = rz_dyldcache_header_version(cache->hdr);
|
|
switch (ver) {
|
|
case RZ_DYLD_CACHE_HEADER_BEFORE_940:
|
|
pj_s(pj, "<940");
|
|
break;
|
|
case RZ_DYLD_CACHE_HEADER_940_OR_AFTER:
|
|
pj_s(pj, "940");
|
|
break;
|
|
case RZ_DYLD_CACHE_HEADER_1042_1_OR_AFTER:
|
|
pj_s(pj, "1042.1");
|
|
break;
|
|
}
|
|
|
|
pj_k(pj, "header");
|
|
pj_o(pj);
|
|
pj_ks(pj, "magic", cache->hdr->magic);
|
|
pj_kn(pj, "mappingOffset", cache->hdr->mappingOffset);
|
|
pj_kn(pj, "mappingCount", cache->hdr->mappingCount);
|
|
pj_kn(pj, "imagesOffset", cache->hdr->imagesOffset);
|
|
pj_kn(pj, "imagesCount", cache->hdr->imagesCount);
|
|
pj_kn(pj, "dyldBaseAddress", cache->hdr->dyldBaseAddress);
|
|
pj_kn(pj, "codeSignatureOffset", cache->hdr->codeSignatureOffset);
|
|
pj_kn(pj, "codeSignatureSize", cache->hdr->codeSignatureSize);
|
|
pj_kn(pj, "slideInfoOffset", cache->hdr->slideInfoOffset);
|
|
pj_kn(pj, "slideInfoSize", cache->hdr->slideInfoSize);
|
|
pj_kn(pj, "localSymbolsOffset", cache->hdr->localSymbolsOffset);
|
|
pj_kn(pj, "localSymbolsSize", cache->hdr->localSymbolsSize);
|
|
char uuidstr[128];
|
|
rz_hex_bin2str((ut8 *)cache->hdr->uuid, 16, uuidstr);
|
|
pj_ks(pj, "uuid", uuidstr);
|
|
pj_ks(pj, "cacheType", (cache->hdr->cacheType == 0) ? "development" : "production");
|
|
pj_kn(pj, "branchPoolsOffset", cache->hdr->branchPoolsOffset);
|
|
pj_kn(pj, "branchPoolsCount", cache->hdr->branchPoolsCount);
|
|
if (rz_dyldcache_header_may_have_accel(cache->hdr)) {
|
|
pj_kn(pj, "accelerateInfoAddr", cache->hdr->accelerateInfoAddr + slide);
|
|
pj_kn(pj, "accelerateInfoSize", cache->hdr->accelerateInfoSize);
|
|
} else {
|
|
pj_kn(pj, "dyldInCacheMH", cache->hdr->dyldInCacheMH);
|
|
pj_kn(pj, "dyldInCacheEntry", cache->hdr->dyldInCacheEntry);
|
|
}
|
|
pj_kn(pj, "imagesTextOffset", cache->hdr->imagesTextOffset);
|
|
pj_kn(pj, "imagesTextCount", cache->hdr->imagesTextCount);
|
|
pj_kn(pj, "patchInfoAddr", cache->hdr->patchInfoAddr);
|
|
pj_kn(pj, "patchInfoSize", cache->hdr->patchInfoSize);
|
|
pj_kn(pj, "otherImageGroupAddrUnused", cache->hdr->otherImageGroupAddrUnused);
|
|
pj_kn(pj, "otherImageGroupSizeUnused", cache->hdr->otherImageGroupSizeUnused);
|
|
pj_kn(pj, "progClosuresAddr", cache->hdr->progClosuresAddr);
|
|
pj_kn(pj, "progClosuresSize", cache->hdr->progClosuresSize);
|
|
pj_kn(pj, "progClosuresTrieAddr", cache->hdr->progClosuresTrieAddr);
|
|
pj_kn(pj, "progClosuresTrieSize", cache->hdr->progClosuresTrieSize);
|
|
pj_kn(pj, "platform", cache->hdr->platform);
|
|
pj_kn(pj, "formatVersion", cache->hdr->formatVersion);
|
|
pj_kn(pj, "dylibsExpectedOnDisk", cache->hdr->dylibsExpectedOnDisk);
|
|
pj_kn(pj, "simulator", cache->hdr->simulator);
|
|
pj_kn(pj, "locallyBuiltCache", cache->hdr->locallyBuiltCache);
|
|
pj_kn(pj, "builtFromChainedFixups", cache->hdr->builtFromChainedFixups);
|
|
pj_kn(pj, "padding", cache->hdr->padding);
|
|
pj_kn(pj, "sharedRegionStart", cache->hdr->sharedRegionStart);
|
|
pj_kn(pj, "sharedRegionSize", cache->hdr->sharedRegionSize);
|
|
pj_kn(pj, "maxSlide", cache->hdr->maxSlide);
|
|
pj_kn(pj, "dylibsImageArrayAddr", cache->hdr->dylibsImageArrayAddr);
|
|
pj_kn(pj, "dylibsImageArraySize", cache->hdr->dylibsImageArraySize);
|
|
pj_kn(pj, "dylibsTrieAddr", cache->hdr->dylibsTrieAddr);
|
|
pj_kn(pj, "dylibsTrieSize", cache->hdr->dylibsTrieSize);
|
|
pj_kn(pj, "otherImageArrayAddr", cache->hdr->otherImageArrayAddr);
|
|
pj_kn(pj, "otherImageArraySize", cache->hdr->otherImageArraySize);
|
|
pj_kn(pj, "otherTrieAddr", cache->hdr->otherTrieAddr);
|
|
pj_kn(pj, "otherTrieSize", cache->hdr->otherTrieSize);
|
|
pj_kn(pj, "mappingWithSlideOffset", cache->hdr->mappingWithSlideOffset);
|
|
pj_kn(pj, "mappingWithSlideCount", cache->hdr->mappingWithSlideCount);
|
|
if (ver >= RZ_DYLD_CACHE_HEADER_940_OR_AFTER) {
|
|
pj_kn(pj, "dylibsPBLStateArrayAddrUnused", cache->hdr->dylibsPBLStateArrayAddrUnused);
|
|
pj_kn(pj, "dylibsPBLSetAddr", cache->hdr->dylibsPBLSetAddr);
|
|
pj_kn(pj, "programsPBLSetPoolAddr", cache->hdr->programsPBLSetPoolAddr);
|
|
pj_kn(pj, "programsPBLSetPoolSize", cache->hdr->programsPBLSetPoolSize);
|
|
pj_kn(pj, "programTrieAddr", cache->hdr->programTrieAddr);
|
|
pj_kn(pj, "programTrieSize", cache->hdr->programTrieSize);
|
|
pj_kn(pj, "osVersion", cache->hdr->osVersion);
|
|
pj_kn(pj, "altPlatform", cache->hdr->altPlatform);
|
|
pj_kn(pj, "altOsVersion", cache->hdr->altOsVersion);
|
|
pj_kn(pj, "swiftOptsOffset", cache->hdr->swiftOptsOffset);
|
|
pj_kn(pj, "swiftOptsSize", cache->hdr->swiftOptsSize);
|
|
pj_kn(pj, "subCacheArrayOffset", cache->hdr->subCacheArrayOffset);
|
|
pj_kn(pj, "subCacheArrayCount", cache->hdr->subCacheArrayCount);
|
|
rz_hex_bin2str(cache->hdr->symbolFileUUID, sizeof(cache->hdr->symbolFileUUID), uuidstr);
|
|
pj_ks(pj, "symbolFileUUID", uuidstr);
|
|
pj_kn(pj, "rosettaReadOnlyAddr", cache->hdr->rosettaReadOnlyAddr);
|
|
pj_kn(pj, "rosettaReadOnlySize", cache->hdr->rosettaReadOnlySize);
|
|
pj_kn(pj, "rosettaReadWriteAddr", cache->hdr->rosettaReadWriteAddr);
|
|
pj_kn(pj, "rosettaReadWriteSize", cache->hdr->rosettaReadWriteSize);
|
|
}
|
|
if (ver >= RZ_DYLD_CACHE_HEADER_1042_1_OR_AFTER) {
|
|
pj_kn(pj, "cacheSubType", cache->hdr->cacheSubType);
|
|
pj_kn(pj, "objcOptsOffset", cache->hdr->objcOptsOffset);
|
|
pj_kn(pj, "objcOptsSize", cache->hdr->objcOptsSize);
|
|
pj_kn(pj, "cacheAtlasOffset", cache->hdr->cacheAtlasOffset);
|
|
pj_kn(pj, "cacheAtlasSize", cache->hdr->cacheAtlasSize);
|
|
pj_kn(pj, "dynamicDataOffset", cache->hdr->dynamicDataOffset);
|
|
pj_kn(pj, "dynamicDataMaxSize", cache->hdr->dynamicDataMaxSize);
|
|
}
|
|
pj_end(pj);
|
|
|
|
if (cache->accel) {
|
|
pj_k(pj, "accelerator");
|
|
pj_o(pj);
|
|
pj_kn(pj, "version", cache->accel->version);
|
|
pj_kn(pj, "imageExtrasCount", cache->accel->imageExtrasCount);
|
|
pj_kn(pj, "imagesExtrasOffset", cache->accel->imagesExtrasOffset);
|
|
pj_kn(pj, "bottomUpListOffset", cache->accel->bottomUpListOffset);
|
|
pj_kn(pj, "dylibTrieOffset", cache->accel->dylibTrieOffset);
|
|
pj_kn(pj, "dylibTrieSize", cache->accel->dylibTrieSize);
|
|
pj_kn(pj, "initializersOffset", cache->accel->initializersOffset);
|
|
pj_kn(pj, "initializersCount", cache->accel->initializersCount);
|
|
pj_kn(pj, "dofSectionsOffset", cache->accel->dofSectionsOffset);
|
|
pj_kn(pj, "dofSectionsCount", cache->accel->dofSectionsCount);
|
|
pj_kn(pj, "reExportListOffset", cache->accel->reExportListOffset);
|
|
pj_kn(pj, "reExportCount", cache->accel->reExportCount);
|
|
pj_kn(pj, "depListOffset", cache->accel->depListOffset);
|
|
pj_kn(pj, "depListCount", cache->accel->depListCount);
|
|
pj_kn(pj, "rangeTableOffset", cache->accel->rangeTableOffset);
|
|
pj_kn(pj, "rangeTableCount", cache->accel->rangeTableCount);
|
|
pj_kn(pj, "dyldSectionAddr", cache->accel->dyldSectionAddr + slide);
|
|
pj_end(pj);
|
|
}
|
|
|
|
if (cache->rebase_infos) {
|
|
size_t i;
|
|
pj_k(pj, "slideInfo");
|
|
pj_a(pj);
|
|
for (i = 0; i < cache->rebase_infos->length; i++) {
|
|
RzDyldRebaseInfo *rebase_info = cache->rebase_infos->entries[i].info;
|
|
pj_o(pj);
|
|
pj_kn(pj, "start", cache->rebase_infos->entries[i].start);
|
|
pj_kn(pj, "end", cache->rebase_infos->entries[i].end);
|
|
if (rebase_info) {
|
|
ut8 version = rebase_info->version;
|
|
pj_kn(pj, "version", version);
|
|
pj_kn(pj, "slide", slide);
|
|
if (version == 3) {
|
|
RzDyldRebaseInfo3 *info3 = (RzDyldRebaseInfo3 *)rebase_info;
|
|
pj_kn(pj, "page_starts_count", info3->page_starts_count);
|
|
pj_kn(pj, "page_size", info3->page_size);
|
|
pj_kn(pj, "auth_value_add", info3->auth_value_add);
|
|
} else if (version == 2 || version == 4) {
|
|
RzDyldRebaseInfo2 *info2 = (RzDyldRebaseInfo2 *)rebase_info;
|
|
pj_kn(pj, "page_starts_count", info2->page_starts_count);
|
|
pj_kn(pj, "page_extras_count", info2->page_extras_count);
|
|
pj_kn(pj, "delta_mask", info2->delta_mask);
|
|
pj_kn(pj, "value_mask", info2->value_mask);
|
|
pj_kn(pj, "value_add", info2->value_add);
|
|
pj_kn(pj, "delta_shift", info2->delta_shift);
|
|
pj_kn(pj, "page_size", info2->page_size);
|
|
} else if (version == 1) {
|
|
RzDyldRebaseInfo1 *info1 = (RzDyldRebaseInfo1 *)rebase_info;
|
|
pj_kn(pj, "toc_count", info1->toc_count);
|
|
pj_kn(pj, "entries_size", info1->entries_size);
|
|
pj_kn(pj, "page_size", 4096);
|
|
}
|
|
}
|
|
pj_end(pj);
|
|
}
|
|
pj_end(pj);
|
|
}
|
|
|
|
if (cache->hdr->imagesTextCount) {
|
|
pj_k(pj, "images");
|
|
pj_a(pj);
|
|
ut64 total_size = cache->hdr->imagesTextCount * sizeof(cache_text_info_t);
|
|
cache_text_info_t *text_infos = malloc(total_size);
|
|
if (!text_infos) {
|
|
goto beach;
|
|
}
|
|
if (rz_buf_fread_at(cache->buf, cache->hdr->imagesTextOffset, (ut8 *)text_infos, "16clii", cache->hdr->imagesTextCount) != total_size) {
|
|
free(text_infos);
|
|
goto beach;
|
|
}
|
|
size_t i;
|
|
for (i = 0; i != cache->hdr->imagesTextCount; i++) {
|
|
cache_text_info_t *text_info = &text_infos[i];
|
|
rz_hex_bin2str((ut8 *)text_info->uuid, 16, uuidstr);
|
|
pj_o(pj);
|
|
pj_ks(pj, "uuid", uuidstr);
|
|
pj_kn(pj, "address", text_info->loadAddress + slide);
|
|
pj_kn(pj, "textSegmentSize", text_info->textSegmentSize);
|
|
char file[256];
|
|
if (rz_buf_read_at(cache->buf, text_info->pathOffset, (ut8 *)&file, sizeof(file)) == sizeof(file)) {
|
|
file[255] = 0;
|
|
pj_ks(pj, "path", file);
|
|
char *last_slash = strrchr(file, '/');
|
|
if (last_slash && *last_slash) {
|
|
pj_ks(pj, "name", last_slash + 1);
|
|
} else {
|
|
pj_ks(pj, "name", file);
|
|
}
|
|
}
|
|
pj_end(pj);
|
|
}
|
|
pj_end(pj);
|
|
free(text_infos);
|
|
}
|
|
|
|
pj_end(pj);
|
|
p("%s\n", pj_string(pj));
|
|
|
|
beach:
|
|
pj_free(pj);
|
|
}
|
|
|
|
RzBinPlugin rz_bin_plugin_dyldcache = {
|
|
.name = "dyldcache",
|
|
.desc = "dyldcache bin plugin",
|
|
.license = "LGPL3",
|
|
.load_buffer = &load_buffer,
|
|
.entries = &entries,
|
|
.baddr = &baddr,
|
|
.symbols = &symbols,
|
|
.virtual_files = &virtual_files,
|
|
.maps = &maps,
|
|
.sections = §ions,
|
|
.check_buffer = &check_buffer,
|
|
.destroy = &destroy,
|
|
.classes = &classes,
|
|
.header = &header,
|
|
.info = &info,
|
|
};
|
|
|
|
#ifndef RZ_PLUGIN_INCORE
|
|
RZ_API RzLibStruct rizin_plugin = {
|
|
.type = RZ_LIB_TYPE_BIN,
|
|
.data = &rz_bin_plugin_dyldcache,
|
|
.version = RZ_VERSION
|
|
};
|
|
#endif
|