Initial implementation of the dyldcache symbols parsing

- Inspired by dsc_syms.c
This commit is contained in:
pancake 2018-01-08 03:05:43 +01:00
parent 7866fca330
commit 48896bdfb7
7 changed files with 256 additions and 45 deletions

View File

@ -936,7 +936,8 @@ static int init_items(struct MACH0_(obj_t)* bin) {
lc.cmdsize = r_read_ble32 (&loadc[4], bin->big_endian);
if (lc.cmdsize < 1 || off + lc.cmdsize > bin->size) {
bprintf ("Warning: mach0_header %d = cmdsize<1.\n", i);
bprintf ("Warning: mach0_header %d = cmdsize<1. (0x%llx vs 0x%llx)\n", i,
(ut64)(off + lc.cmdsize), (ut64)(bin->size));
break;
}
@ -1245,16 +1246,17 @@ struct MACH0_(obj_t)* MACH0_(mach0_new)(const char* file, bool verbose) {
memset (bin, 0, sizeof (struct MACH0_(obj_t)));
bin->verbose = verbose;
bin->file = file;
if (!(buf = (ut8*)r_file_slurp(file, &bin->size)))
if (!(buf = (ut8*)r_file_slurp (file, &bin->size))) {
return MACH0_(mach0_free)(bin);
}
bin->b = r_buf_new ();
if (!r_buf_set_bytes(bin->b, buf, bin->size)) {
if (!r_buf_set_bytes (bin->b, buf, bin->size)) {
free (buf);
return MACH0_(mach0_free)(bin);
}
free (buf);
bin->dyld_info = NULL;
if (!init(bin)) {
if (!init (bin)) {
return MACH0_(mach0_free)(bin);
}
bin->imports_by_ord_size = 0;
@ -1268,12 +1270,15 @@ struct MACH0_(obj_t)* MACH0_(new_buf)(RBuffer *buf, bool verbose) {
return NULL;
}
bin->kv = sdb_new (NULL, "bin.mach0", 0);
bin->b = r_buf_new ();
bin->size = buf->length;
bin->verbose = verbose;
if (!r_buf_set_bytes (bin->b, buf->buf, bin->size)){
// bin->b = r_buf_ref (buf);
#if 1
bin->b = r_buf_new ();
if (!r_buf_set_bytes (bin->b, buf->buf, bin->size)) {
return MACH0_(mach0_free) (bin);
}
#endif
if (!init (bin)) {
return MACH0_(mach0_free)(bin);
}
@ -1399,7 +1404,7 @@ static int parse_import_stub(struct MACH0_(obj_t)* bin, struct symbol_t *symbol,
symbol->size = 0;
stridx = bin->symtab[idx].n_strx;
if (stridx >= 0 && stridx < bin->symstrlen) {
symstr = (char *)bin->symstr+stridx;
symstr = (char *)bin->symstr + stridx;
} else {
symstr = "???";
}
@ -1521,7 +1526,7 @@ struct symbol_t* MACH0_(get_symbols)(struct MACH0_(obj_t)* bin) {
}
stridx = bin->symtab[i].n_strx;
if (stridx >= 0 && stridx < bin->symstrlen) {
symstr = (char*)bin->symstr+stridx;
symstr = (char*)bin->symstr + stridx;
} else {
symstr = "???";
}
@ -1669,7 +1674,7 @@ struct import_t* MACH0_(get_imports)(struct MACH0_(obj_t)* bin) {
return NULL;
}
for (i = j = 0; i < bin->dysymtab.nundefsym; i++) {
idx = bin->dysymtab.iundefsym +i;
idx = bin->dysymtab.iundefsym + i;
if (idx < 0 || idx >= bin->nsymtab) {
bprintf ("WARNING: Imports index out of bounds. Ignoring relocs\n");
free (imports);

View File

@ -203,4 +203,44 @@ struct cache_header {
ut64 localSymbolsSize;
};
// dupe?
typedef struct {
char magic[16];
uint32_t mappingOffset;
uint32_t mappingCount;
uint32_t imagesOffset;
uint32_t imagesCount;
uint64_t dyldBaseAddress;
uint64_t codeSignatureOffset;
uint64_t codeSignatureSize;
uint64_t slideInfoOffset;
uint64_t slideInfoSize;
uint64_t localSymbolsOffset;
uint64_t localSymbolsSize;
uint8_t uuid[16];
uint64_t cacheType;
uint32_t branchPoolsOffset;
uint32_t branchPoolsCount;
uint64_t accelerateInfoAddr;
uint64_t accelerateInfoSize;
uint64_t imagesTextOffset;
uint64_t imagesTextCount;
} cache_hdr_t;
typedef struct {
uint64_t address;
uint64_t size;
uint64_t fileOffset;
uint32_t maxProt;
uint32_t initProt;
} cache_map_t;
typedef struct {
uint64_t address;
uint64_t modTime;
uint64_t inode;
uint32_t pathFileOffset;
uint32_t pad;
} cache_img_t;
#endif

View File

@ -1,9 +1,34 @@
/* radare2 - LGPL - Copyright 2009-2017 - nibble, pancake */
/* radare2 - LGPL - Copyright 2018 - pancake */
#include <r_types.h>
#include <r_util.h>
#include <r_lib.h>
#include <r_bin.h>
// #include "../format/mach0/mach0_defines.h"
#define R_BIN_MACH064 1
#include "../format/mach0/mach0.h"
static void* addr2ptr(uint64_t addr, cache_hdr_t *hdr) {
cache_map_t *map = (cache_map_t*)((const ut8*)hdr + hdr->mappingOffset);
for(uint32_t i = 0; i < hdr->mappingCount; ++i) {
if (addr >= map[i].address && addr < map[i].address + map[i].size) {
return (void*)((const ut8*)hdr + map[i].fileOffset + (addr - map[i].address));
}
}
return NULL;
}
static ut64 va2pa(uint64_t addr, void *cache) {
cache_hdr_t *hdr = (cache_hdr_t*)cache;
cache_map_t *map = (cache_map_t*)((uintptr_t)cache + hdr->mappingOffset);
for(uint32_t i = 0; i < hdr->mappingCount; ++i) {
if (addr >= map[i].address && addr < map[i].address + map[i].size) {
return map[i].fileOffset + addr - map[i].address;
// (void*)((uintptr_t)cache + map[i].fileOffset + (addr - map[i].address));
}
}
return UT64_MAX;
}
static bool dyld64 = false;
@ -12,7 +37,7 @@ static bool check_bytes(const ut8 *buf, ut64 length) {
if (buf && length >= 32) {
char arch[9] = { 0 };
strncpy (arch, (const char *) buf + 9, R_MIN (length, sizeof (arch) - 1));
rc = !memcmp (buf, "\x64\x79\x6c\x64", 4);
rc = !memcmp (buf, "dyld", 4);
if (rc) {
dyld64 = strstr (arch, "64") != NULL;
if (*arch) {
@ -56,10 +81,10 @@ static RBinInfo *info(RBinFile *bf) {
ret->bclass = strdup ("dyldcache");
ret->rclass = strdup ("ios");
ret->os = strdup ("iOS");
ret->arch = strdup ("arm");
ret->arch = strdup ("arm"); // XXX
ret->machine = strdup (ret->arch);
ret->subsystem = strdup ("xnu");
ret->type = strdup ("LIBRARY CACHE");
ret->type = strdup ("library-cache");
ret->bits = dyld64? 64: 32;
ret->has_va = true;
ret->big_endian = big_endian;
@ -67,35 +92,157 @@ static RBinInfo *info(RBinFile *bf) {
return ret;
}
#if 0
static ut64 size(RBinFile *bf) {
ut64 text, data, syms, spsz;
int big_endian;
if (!bf->o->info) {
bf->o->info = info (bf);
}
if (!bf->o->info) {
return 0;
}
big_endian = bf->o->info->big_endian;
// TODO: reuse section list
text = r_mem_get_num (bf->buf->buf + 4, 4, big_endian);
data = r_mem_get_num (bf->buf->buf + 8, 4, big_endian);
syms = r_mem_get_num (bf->buf->buf + 16, 4, big_endian);
spsz = r_mem_get_num (bf->buf->buf + 24, 4, big_endian);
return text + data + syms + spsz + (6 * 4);
static void parse_mach0 (RList *ret, ut64 paddr, RBinFile *bf) {
// TODO
}
static ut64 baddr(RBinFile *bf) {
// XXX hardcoded
return 0x180000000;
}
#define USE_R2_API 0
void parse_mach064 (RList *ret, ut64 paddr, RBinFile *bf) {
// eprintf ("MACH0 AT 0x%"PFMT64x"\n", paddr);
int sz = 0;
void *ptr = r_buf_get_at (bf->buf, paddr, &sz);
#if USE_R2_API
// XXX r2 api cannot load those mach0s because addresses are messed up
sz = 1024*1024*1; // 1MB limit file size to 1MB to avoid slow copies.. this is a nice place to optimize unnecessary r_buf_new_from_bytes
RBuffer *buf = r_buf_new_with_pointers (ptr, sz);
struct MACH0_(obj_t) *res = MACH0_(new_buf) (buf, bf->rbin->verbose);
if (!res) {
return;
}
struct symbol_t *symbols = MACH0_(get_symbols) (res);
eprintf ("mach0-64: b:%p r:%p s:%p\n", buf, res, symbols);
if (!symbols) {
return;
}
for (i = 0; !symbols[i].last; i++) {
if (!symbols[i].name[0] || symbols[i].addr < 100) {
continue;
}
RBinSymbol *sym = R_NEW0 (RBinSymbol);
if (!sym) {
break;
}
sym->name = strdup (symbols[i].name);
eprintf ("-> %s\n", sym->name);
sym->vaddr = symbols[i].addr;
sym->paddr = symbols[i].offset + bf->o->boffset;
sym->size = symbols[i].size;
sym->ordinal = i;
r_list_append (ret, sym);
}
free (symbols);
r_buf_free (buf);
MACH0_(free)(res);
#else
const ut8 * root = r_buf_get_at (bf->buf, 0, NULL);
//printf("f sym.imp.%s 0 0x%llx\n", &strs[syms[n].n_un.n_strx + 1], syms[n].n_value);
struct MACH0_(mach_header) *h64 = ptr;
struct load_command *cmd = (struct load_command*)((const ut8*)ptr + 0x20);
struct load_command *end = (struct load_command*)((const ut8*)cmd + h64->sizeofcmds);
for (; cmd < end; cmd = (void *)((const ut8*)cmd + cmd->cmdsize)) {
// eprintf ("%p 0x%x (%02x)\n", (void*)cmd - (void*)ptr + (void*)(size_t)paddr, cmd->cmd, LC_SYMTAB);
if (cmd->cmd == LC_SYMTAB) {
struct symtab_command *stab = (struct symtab_command*)(cmd);
struct MACH0_(nlist) *syms = (struct MACH0_(nlist)*)((uintptr_t)root + stab->symoff);
char *strs = (char*)((uintptr_t)root + stab->stroff);
size_t n;
for (n = 0; n < stab->nsyms; n++) {
if ((syms[n].n_type & N_TYPE) != N_UNDF && (syms[n].n_type & N_EXT)) {
if (false) { // strs[syms[n].n_un.n_strx] != '_')
// LOG("Not a C symbol: %s", &strs[syms[n].n_un.n_strx]);
} else {
RBinSymbol *sym = R_NEW0 (RBinSymbol);
if (sym) {
sym->name = strdup (&strs [ syms[n].n_strx + 1]);
// eprintf ("Sym 0x%llx %s\n", (ut64)(syms[n].n_value), sym->name);
sym->vaddr = syms[n].n_value;
sym->paddr = syms[n].n_value;
// XXX THIs is unnecessarily slow! must be enums
sym->bind = "PUBLIC";
sym->type = "SYM";
r_list_append (ret, sym);
}
//printf("f sym.imp.%s 0 0x%llx\n", &strs[syms[n].n_un.n_strx + 1], syms[n].n_value);
}
}
}
}
if ((int)cmd->cmdsize < 1) {
eprintf ("CMD Size FAIL %d\n", cmd->cmdsize);
break;
}
}
#endif
}
static RList* sections(RBinFile *bf) {
RList *ret = NULL;
RBinSection *ptr = NULL;
RBinObject *obj = bf ? bf->o : NULL;
ut64 vaddr = 0x180000000;
if (!obj || !obj->bin_obj || !(ret = r_list_newf ((RListFree)free))) {
return NULL;
}
if (!(ptr = R_NEW0 (RBinSection))) {
return NULL;
}
r_str_ncpy (ptr->name, (char*)"text", R_BIN_SIZEOF_STRINGS);
ptr->size = r_buf_size (bf->buf);
ptr->vsize = ptr->size;
ptr->paddr = 0;
ptr->vaddr = vaddr;
ptr->add = true;
if (!ptr->vaddr) {
ptr->vaddr = ptr->paddr;
}
ut32 srwx = 1 | 2 | 4;
ptr->srwx = srwx | R_BIN_SCN_MAP;
r_list_append (ret, ptr);
return ret;
}
static RList* symbols(RBinFile *bf) {
RList *ret = r_list_newf (free);
int cache_size = 0;
const ut8 *cache = r_buf_get_at (bf->buf, 0, &cache_size);
cache_hdr_t *hdr = (cache_hdr_t *)cache;
cache_img_t *img = (cache_img_t*)((uintptr_t)cache + hdr->imagesOffset);
int i;
for (i = 0; i < hdr->imagesCount; i++) {
ut32 *ptr = addr2ptr (img[i].address, (cache_hdr_t*)cache);
ut64 pa = va2pa (img[i].address, (cache_hdr_t*)cache);
switch (*(uint32_t*)ptr) {
case MH_MAGIC:
// parse_mach0 (ret, *ptr, bf);
break;
case MH_MAGIC_64:
parse_mach064 (ret, pa, bf);
break;
default:
eprintf ("Unknown sub-bin\n");
break;
}
}
return ret;
}
RBinPlugin r_bin_plugin_dyldcache = {
.name = "dyldcache",
.desc = "dyldcache bin plugin",
.license = "LGPL3",
// .get_sdb = &get_sdb,
.load = &load,
.load_bytes = &load_bytes,
// .size = &size,
.entries = &entries,
.baddr = &baddr,
.symbols = &symbols,
.sections = &sections,
.check_bytes = &check_bytes,
.info = &info,
};

View File

@ -111,7 +111,7 @@ static RList* sections(RBinFile *bf) {
if (!(ptr = R_NEW0 (RBinSection))) {
break;
}
strncpy (ptr->name, (char*)sections[i].name, R_BIN_SIZEOF_STRINGS);
r_str_ncpy (ptr->name, (char*)sections[i].name, R_BIN_SIZEOF_STRINGS);
if (strstr (ptr->name, "la_symbol_ptr")) {
#ifndef R_BIN_MACH064
const int sz = 4;

View File

@ -212,7 +212,7 @@ static const char *help_msg_pf[] = {
"pfo", " fdf_name", "Load a Format Definition File (fdf)",
"pf.", "fmt_name.field_name=33", "Set new value for the specified field in named format",
"pfv.", "fmt_name[.field]", "Print value(s) only for named format. Useful for one-liners",
"pfs", " fmt_name|fmt", "Print the size of (named) format in bytes",
"pfs", "[.fmt_name| fmt]", "Print the size of (named) format in bytes",
NULL
};
@ -975,8 +975,8 @@ static void cmd_print_format(RCore *core, const char *_input, int len) {
if (*_input == '.') {
_input++;
val = sdb_get (core->print->formats, _input, NULL);
if (val != NULL) {
r_cons_printf ("%d byte(s)\n", r_print_format_struct_size (val, core->print, mode, 0));
if (val) {
r_cons_printf ("%d\n", r_print_format_struct_size (val, core->print, mode, 0));
} else {
eprintf ("Struct %s not defined\nUsage: pfs.struct_name | pfs format\n", _input);
}
@ -985,7 +985,7 @@ static void cmd_print_format(RCore *core, const char *_input, int len) {
_input++;
}
if (*_input) {
r_cons_printf ("%d byte(s)\n", r_print_format_struct_size (_input, core->print, mode, 0));
r_cons_printf ("%d\n", r_print_format_struct_size (_input, core->print, mode, 0));
} else {
eprintf ("Struct %s not defined\nUsage: pfs.struct_name | pfs format\n", _input);
}
@ -1128,7 +1128,7 @@ static void cmd_print_format(RCore *core, const char *_input, int len) {
// char *fields = NULL;
*space++ = 0;
// fields = strchr (space, ' ');
if (strchr (name, '.') != NULL) {// || (fields != NULL && strchr(fields, '.') != NULL)) // if anon struct, then field can have '.'
if (strchr (name, '.')) {// || (fields != NULL && strchr(fields, '.') != NULL)) // if anon struct, then field can have '.'
eprintf ("Struct or fields name can not contain dot symbol (.)\n");
} else {
sdb_set (core->print->formats, name, space, 0);
@ -1150,7 +1150,7 @@ static void cmd_print_format(RCore *core, const char *_input, int len) {
/* This make sure the whole structure will be printed */
const char *fmt = NULL;
fmt = sdb_get (core->print->formats, name, NULL);
if (fmt != NULL) {
if (fmt) {
int size = r_print_format_struct_size (fmt, core->print, mode, 0) + 10;
if (size > core->blocksize) {
r_core_block_size (core, size);
@ -2962,7 +2962,7 @@ static void pr_bb(RCore *core, RAnalFunction *fcn, RAnalBlock *b, bool emu, ut64
if (b->jump > b->addr) {
RAnalBlock *jumpbb = r_anal_bb_get_jumpbb (fcn, b);
if (jumpbb) {
if (emu && core->anal->last_disasm_reg != NULL && !jumpbb->parent_reg_arena) {
if (emu && core->anal->last_disasm_reg && !jumpbb->parent_reg_arena) {
jumpbb->parent_reg_arena = r_reg_arena_dup (core->anal->reg, core->anal->last_disasm_reg);
}
if (jumpbb->parent_stackptr == INT_MAX) {
@ -2978,7 +2978,7 @@ static void pr_bb(RCore *core, RAnalFunction *fcn, RAnalBlock *b, bool emu, ut64
if (b->fail > b->addr) {
RAnalBlock *failbb = r_anal_bb_get_failbb (fcn, b);
if (failbb) {
if (emu && core->anal->last_disasm_reg != NULL && !failbb->parent_reg_arena) {
if (emu && core->anal->last_disasm_reg && !failbb->parent_reg_arena) {
failbb->parent_reg_arena = r_reg_arena_dup (core->anal->reg, core->anal->last_disasm_reg);
}
if (failbb->parent_stackptr == INT_MAX) {

View File

@ -19,6 +19,7 @@ typedef struct r_buf_t {
int fd;
int Oxff;
RList *sparse;
int refctr;
} RBuffer;
typedef struct r_buf_cache_t {
@ -42,6 +43,7 @@ R_API RBuffer *r_buf_new_empty (ut64 len);
R_API RBuffer *r_buf_mmap(const char *file, int flags);
R_API RBuffer *r_buf_new_sparse(ut8 Oxff);
R_API bool r_buf_dump (RBuffer *buf, const char *file);
R_API RBuffer *r_buf_ref(RBuffer *b);
/* methods */
R_API bool r_buf_set_bits(RBuffer *b, ut64 at, const ut8* buf, int bitoff, int count);
R_API int r_buf_set_bytes(RBuffer *b, const ut8 *buf, ut64 length);

View File

@ -1,4 +1,4 @@
/* radare - LGPL - Copyright 2009-2016 - pancake */
/* radare - LGPL - Copyright 2009-2018 - pancake */
#include <r_types.h>
#include <r_util.h>
@ -143,6 +143,12 @@ R_API RBuffer *r_buf_new_with_string (const char *msg) {
return r_buf_new_with_bytes ((const ut8*)msg, (ut64) strlen (msg));
}
R_API RBuffer *r_buf_new_with_bufref(RBuffer *b) {
RBuffer *buf = r_buf_new_with_pointers (b->buf, b->length);
r_buf_ref (buf);
return buf;
}
R_API RBuffer *r_buf_new_with_buf(RBuffer *b) {
return r_buf_new_with_bytes (b->buf, b->length);
}
@ -596,11 +602,11 @@ static int r_buf_fcpy_at (RBuffer *b, ut64 addr, ut8 *buf, const char *fmt, int
R_API ut8 *r_buf_get_at (RBuffer *b, ut64 addr, int *left) {
if (b->empty) {
return 0;
return NULL;
}
if (b->fd != -1) {
eprintf ("r_buf_get_at not supported for r_buf_new_file\n");
return 0;
return NULL;
}
if (addr == R_BUF_CUR) {
addr = b->cur;
@ -613,7 +619,7 @@ R_API ut8 *r_buf_get_at (RBuffer *b, ut64 addr, int *left) {
if (left) {
*left = b->length - addr;
}
return b->buf+addr;
return b->buf + addr;
}
//ret 0 if failed; ret copied length if successful
@ -712,6 +718,10 @@ R_API void r_buf_free(RBuffer *b) {
if (!b) {
return;
}
if (b->refctr > 0) {
b->refctr--;
return;
}
if (!b->ro) {
r_buf_deinit (b);
}
@ -778,3 +788,10 @@ R_API bool r_buf_resize (RBuffer *b, ut64 newsize) {
}
return false;
}
R_API RBuffer *r_buf_ref(RBuffer *b) {
if (b) {
b->refctr++;
}
return b;
}