Implement class methods for DEX and make icj

This commit is contained in:
pancake 2015-07-06 02:38:54 +02:00
parent 406000688d
commit d054008b17
6 changed files with 226 additions and 156 deletions

View file

@ -396,13 +396,18 @@ static void r_bin_object_free (void /*RBinObject*/ *o_) {
// makes no sense to pass in a binfile and set the RBinObject
// kinda a clunky functions
static int r_bin_object_set_items(RBinFile *binfile, RBinObject *o) {
RBin *bin = binfile->rbin;
RBinObject *old_o = binfile ? binfile->o : NULL;
RBinObject *old_o;
RBinPlugin *cp;
int i, minlen;
RBinPlugin *cp = NULL;
if (!binfile || !o || !o->plugin) return R_FALSE;
RBin *bin;
if (!binfile || !o || !o->plugin)
return R_FALSE;
bin = binfile->rbin;
old_o = binfile->o;
cp = o->plugin;
if (binfile->rbin->minstrlen>0) {
minlen = binfile->rbin->minstrlen;
} else {

View file

@ -9,7 +9,7 @@ static void hashify(char *s, ut64 vaddr) {
while (*s) {
if (!IS_PRINTABLE(*s)) {
if (vaddr && vaddr != UT64_MAX) {
sprintf (s, "%"PFMT64d, vaddr);
sprintf (s, "_%"PFMT64d, vaddr);
} else {
ut32 hash = sdb_hash (s);
sprintf (s, "%x", hash);
@ -62,17 +62,20 @@ R_API void r_bin_filter_sections (RList *list) {
R_API void r_bin_filter_classes (RList *list) {
Sdb *db = sdb_new0 ();
RListIter *iter;
RListIter *iter, *iter2;
RBinClass *cls;
RBinSymbol *sym;
r_list_foreach (list, iter, cls) {
int namepad_len = strlen (cls->name)+10;
int namepad_len = strlen (cls->name)+32;
char *namepad = malloc (namepad_len);
if (namepad) {
strcpy (namepad, cls->name);
r_bin_filter_name (db, cls->index, namepad, namepad_len);
//hashify (namepad, (ut64)cls->index);
free (cls->name);
cls->name = namepad;
r_list_foreach (cls->methods, iter2, sym) {
r_bin_filter_name (db, sym->vaddr, sym->name, sizeof (sym->name));
}
} else eprintf ("Cannot alloc %d bytes\n", namepad_len);
}
sdb_free (db);

View file

@ -858,6 +858,7 @@ static int parse_import_stub(struct MACH0_(obj_t)* bin, struct symbol_t *symbol,
return R_FALSE;
}
#if 0
static ut64 get_text_base(struct MACH0_(obj_t)* bin) {
ut64 ret = 0LL;
struct section_t *sections;
@ -873,6 +874,7 @@ static ut64 get_text_base(struct MACH0_(obj_t)* bin) {
}
return ret;
}
#endif
static int inSymtab (struct symbol_t *symbols, int last, const char *name, ut64 addr) {
int i;
@ -890,7 +892,7 @@ struct symbol_t* MACH0_(get_symbols)(struct MACH0_(obj_t)* bin) {
const char *symstr;
struct symbol_t *symbols;
int from, to, i, j, s, stridx, symbols_size, symbols_count;
ut64 text_base = get_text_base (bin);
//ut64 text_base = get_text_base (bin);
if (!bin || !bin->symtab || !bin->symstr)
return NULL;

View file

@ -334,11 +334,156 @@ static char *dex_class_super_name (RBinDexObj *bin, RBinDexClass *c) {
return get_string (bin, cid, tid);
}
static int dex_loadcode(RBinFile *arch, RBinDexObj *bin) {
static int *parse_class (RBinFile *binfile, struct r_bin_dex_obj_t *bin, struct dex_class_t *c, RBinClass *cls) {
int *methods;
int i, j;
char *name;
ut64 SF, IF, DM, VM;
int i, j;
const ut8 *p, *p_end;
char *class_name = dex_class_name (bin, c);
if (c->class_data_offset==0) {
// no method here, just class definition
//free (class_name);
//free (super_name);
return NULL;
}
methods = calloc (sizeof (ut32), bin->header.method_size);
if (!methods)
return R_FALSE;
dprintf (" class_data_offset: %d\n", c->class_data_offset);
p = r_buf_get_at (binfile->buf, c->class_data_offset, NULL);
p_end = p + (binfile->buf->length - c->class_data_offset);
/* data header */
/* walk over class data items */
p = r_uleb128 (p, p_end-p, &SF);
p = r_uleb128 (p, p_end-p, &IF);
p = r_uleb128 (p, p_end-p, &DM);
p = r_uleb128 (p, p_end-p, &VM);
//eprintf ("METHODS %s %d\n", class_name, DM);
//eprintf ("SF %d IF %d DM %d VM %d\n", SF, IF, DM, VM);
dprintf (" static fields: %u\n", (ut32)SF);
/* static fields */
for (j=0; j<SF; j++) {
ut64 FI, FA;
p = r_uleb128 (p, p_end-p, &FI);
p = r_uleb128 (p, p_end-p, &FA);
dprintf (" field_idx: %u\n", (ut32)FI);
// TODO: retrieve name of field here
// TODO: add comment or store that fcn var info in sdb directly
dprintf (" field access_flags: 0x%x\n", (ut32)FA);
}
/* instance fields */
dprintf (" instance fields: %u\n", (ut32)IF);
for (j=0; j<IF; j++) {
ut64 FI, FA;
p = r_uleb128 (p, p_end-p, &FI);
p = r_uleb128 (p, p_end-p, &FA);
dprintf (" field_idx: %u,\n", (ut32)FI);
dprintf (" field access_flags: %u,\n", (ut32)FA);
}
/* direct methods */
dprintf (" direct methods: %u\n", (ut32)DM);
#if 0
// hardcoded DEX limit
if (DM>=0xffff) {
DM = 0xFFFF;
}
#endif
ut64 omi = 0;
for (j=0; j<DM; j++) {
char *method_name, *flag_name;
ut64 MI, MA, MC;
p = r_uleb128 (p, p_end-p, &MI);
MI += omi;
omi = MI;
// the mi is diff
#if 0
index into the method_ids list for the identity of this method (includes the name and descriptor), represented as a difference from the index of previous element in the list. The index of the first element in a list is represented directly.
#endif
p = r_uleb128 (p, p_end-p, &MA);
p = r_uleb128 (p, p_end-p, &MC);
if (MI<bin->header.method_size) methods[MI] = 1;
if (MC>0 && bin->code_from>MC) bin->code_from = MC;
if (MC>0 && bin->code_to<MC) bin->code_to = MC;
method_name = dex_method_name (bin, MI);
dprintf ("METHOD NAME %u\n", (ut32)MI);
if (!method_name) method_name = strdup ("unknown");
flag_name = flagname (class_name, method_name);
dprintf ("f %s @ 0x%x\n", flag_name, (ut32)MC);
dprintf (" { name: %d %d %s,\n", (ut32)MC, (ut32)MI, method_name);
dprintf (" idx: %u,\n", (ut32)MI);
dprintf (" access_flags: 0x%x,\n", (ut32)MA);
dprintf (" code_offset: 0x%x },\n", (ut32)MC);
/* add symbol */
if (flag_name && *flag_name) {
RBinSymbol *sym = R_NEW0 (RBinSymbol);
strncpy (sym->name, flag_name, sizeof (sym->name)-1);
strcpy (sym->type, "FUNC");
sym->paddr = sym->vaddr = MC;
if (MC>0) { /* avoid methods at 0 paddr */
#if 0
// TODO: use sdb+pf to show method header
ut16 regsz;
ut16 ins_size
ut16 outs_size
ut16 tries_size
ut32 debug_info_off
ut32 insns_size
ut16[insn_size] insns;
ut16 padding = 0
try_item[tries_size] tries
encoded_catch_handler_list handlers
#endif
sym->paddr += 0x10;
r_list_append (bin->methods_list, sym);
if (cls) {
if (!cls->methods) {
cls->methods = r_list_new ();
}
r_list_append (cls->methods, sym);
}
/* cache in sdb */
if (!mdb) {
mdb = sdb_new0 ();
}
sdb_num_set (mdb, sdb_fmt(0, "method.%d", MI), sym->paddr, 0);
} else {
//r_list_append (bin->methods_list, sym);
// XXX memleak sym
free (sym);
}
}
free (method_name);
free (flag_name);
}
/* virtual methods */
dprintf (" virtual methods: %u\n", (ut32)VM);
for (j=0; j<VM; j++) {
ut64 MI, MA, MC;
p = r_uleb128 (p, p_end-p, &MI);
p = r_uleb128 (p, p_end-p, &MA);
p = r_uleb128 (p, p_end-p, &MC);
if (MI<bin->header.method_size) methods[MI] = 1;
if (MC>0 && bin->code_from>MC) bin->code_from = MC;
if (MC>0 && bin->code_to<MC) bin->code_to = MC;
name = dex_method_name (bin, MI);
dprintf (" method name: %s\n", name);
dprintf (" method_idx: %u\n", (ut32)MI);
dprintf (" method access_flags: %u\n", (ut32)MA);
dprintf (" method code_offset: %u\n", (ut32)MC);
free (name);
}
return methods;
}
static int dex_loadcode(RBinFile *arch, RBinDexObj *bin) {
int i, j;
const ut8 *p, *p_end;
int *methods = NULL;
// doublecheck??
if (!bin || bin->methods_list)
@ -354,9 +499,6 @@ static int dex_loadcode(RBinFile *arch, RBinDexObj *bin) {
bin->header.method_size = 0;
return R_FALSE;
}
methods = calloc (sizeof (ut32), bin->header.method_size);
if (!methods)
return R_FALSE;
/* WrapDown the header sizes to avoid huge allocations */
bin->header.method_size = R_MIN (bin->header.method_size, bin->size);
@ -364,7 +506,6 @@ static int dex_loadcode(RBinFile *arch, RBinDexObj *bin) {
bin->header.strings_size = R_MIN (bin->header.strings_size, bin->size);
if (bin->header.strings_size > bin->size) {
free (methods);
eprintf ("Invalid strings size\n");
return R_FALSE;
}
@ -391,136 +532,7 @@ static int dex_loadcode(RBinFile *arch, RBinDexObj *bin) {
continue;
}
#endif
if (c->class_data_offset==0) {
// no method here, just class definition
free (class_name);
free (super_name);
continue;
}
dprintf (" class_data_offset: %d\n", c->class_data_offset);
p = r_buf_get_at (arch->buf, c->class_data_offset, NULL);
p_end = p + (arch->buf->length - c->class_data_offset);
/* data header */
/* walk over class data items */
{
ut64 SF, IF, DM, VM;
p = r_uleb128 (p, p_end-p, &SF);
p = r_uleb128 (p, p_end-p, &IF);
p = r_uleb128 (p, p_end-p, &DM);
p = r_uleb128 (p, p_end-p, &VM);
//eprintf ("METHODS %s %d\n", class_name, DM);
//eprintf ("SF %d IF %d DM %d VM %d\n", SF, IF, DM, VM);
dprintf (" static fields: %u\n", (ut32)SF);
/* static fields */
for (j=0; j<SF; j++) {
ut64 FI, FA;
p = r_uleb128 (p, p_end-p, &FI);
p = r_uleb128 (p, p_end-p, &FA);
dprintf (" field_idx: %u\n", (ut32)FI);
// TODO: retrieve name of field here
// TODO: add comment or store that fcn var info in sdb directly
dprintf (" field access_flags: 0x%x\n", (ut32)FA);
}
/* instance fields */
dprintf (" instance fields: %u\n", (ut32)IF);
for (j=0; j<IF; j++) {
ut64 FI, FA;
p = r_uleb128 (p, p_end-p, &FI);
p = r_uleb128 (p, p_end-p, &FA);
dprintf (" field_idx: %u,\n", (ut32)FI);
dprintf (" field access_flags: %u,\n", (ut32)FA);
}
/* direct methods */
dprintf (" direct methods: %u\n", (ut32)DM);
#if 0
// hardcoded DEX limit
if (DM>=0xffff) {
DM = 0xFFFF;
}
#endif
ut64 omi = 0;
for (j=0; j<DM; j++) {
char *method_name, *flag_name;
ut64 MI, MA, MC;
p = r_uleb128 (p, p_end-p, &MI);
MI += omi;
omi = MI;
// the mi is diff
#if 0
index into the method_ids list for the identity of this method (includes the name and descriptor), represented as a difference from the index of previous element in the list. The index of the first element in a list is represented directly.
#endif
p = r_uleb128 (p, p_end-p, &MA);
p = r_uleb128 (p, p_end-p, &MC);
if (MI<bin->header.method_size) methods[MI] = 1;
if (MC>0 && bin->code_from>MC) bin->code_from = MC;
if (MC>0 && bin->code_to<MC) bin->code_to = MC;
method_name = dex_method_name (bin, MI);
dprintf ("METHOD NAME %u\n", (ut32)MI);
if (!method_name) method_name = strdup ("unknown");
flag_name = flagname (class_name, method_name);
dprintf ("f %s @ 0x%x\n", flag_name, (ut32)MC);
dprintf (" { name: %d %d %s,\n", (ut32)MC, (ut32)MI, method_name);
dprintf (" idx: %u,\n", (ut32)MI);
dprintf (" access_flags: 0x%x,\n", (ut32)MA);
dprintf (" code_offset: 0x%x },\n", (ut32)MC);
/* add symbol */
if (flag_name && *flag_name) {
RBinSymbol *sym = R_NEW0 (RBinSymbol);
strncpy (sym->name, flag_name, sizeof (sym->name)-1);
strcpy (sym->type, "FUNC");
sym->paddr = sym->vaddr = MC;
if (MC>0) { /* avoid methods at 0 paddr */
#if 0
// TODO: use sdb+pf to show method header
ut16 regsz;
ut16 ins_size
ut16 outs_size
ut16 tries_size
ut32 debug_info_off
ut32 insns_size
ut16[insn_size] insns;
ut16 padding = 0
try_item[tries_size] tries
encoded_catch_handler_list handlers
#endif
sym->paddr += 0x10;
r_list_append (bin->methods_list, sym);
/* cache in sdb */
if (!mdb) {
mdb = sdb_new0 ();
}
sdb_num_set (mdb, sdb_fmt(0, "method.%d", MI), sym->paddr, 0);
} else {
//r_list_append (bin->methods_list, sym);
// XXX memleak sym
free (sym);
}
}
free (method_name);
free (flag_name);
}
/* virtual methods */
dprintf (" virtual methods: %u\n", (ut32)VM);
for (j=0; j<VM; j++) {
ut64 MI, MA, MC;
p = r_uleb128 (p, p_end-p, &MI);
p = r_uleb128 (p, p_end-p, &MA);
p = r_uleb128 (p, p_end-p, &MC);
if (MI<bin->header.method_size) methods[MI] = 1;
if (MC>0 && bin->code_from>MC) bin->code_from = MC;
if (MC>0 && bin->code_to<MC) bin->code_to = MC;
name = dex_method_name (bin, MI);
dprintf (" method name: %s\n", name);
dprintf (" method_idx: %u\n", (ut32)MI);
dprintf (" method access_flags: %u\n", (ut32)MA);
dprintf (" method code_offset: %u\n", (ut32)MC);
free (name);
}
}
methods = parse_class (arch, bin, c, NULL);
dprintf (" ],\n");
dprintf ("},");
free (class_name);
@ -677,6 +689,10 @@ static RList* classes (RBinFile *arch) {
class->addr = entry.class_id + bin->header.class_offset;
class->name = cn;
//class->addr = class_addr;
int *methods = parse_class (arch, bin, &entry, class);
free (methods);
r_list_append (ret, class);
dprintf ("class.%s=%d\n", name[0]==12?name+1:name, entry.class_id);
dprintf ("# access_flags = %x;\n", entry.access_flags);

View file

@ -1511,9 +1511,9 @@ static int bin_fields (RCore *r, int mode, ut64 baddr, int va) {
static int bin_classes (RCore *r, int mode) {
RListIter *iter, *iter2;
RBinSymbol *sym;
RBinClass *c;
RList *cs = r_bin_get_classes (r->bin);
const char *methname;
if (!cs) return R_FALSE;
// XXX: support for classes is broken and needs more love
@ -1557,17 +1557,21 @@ static int bin_classes (RCore *r, int mode) {
r_cons_printf ("f class.%s @ 0x%"PFMT64x"\n", name, c->addr);
if (c->super)
r_cons_printf ("f super.%s.%s @ %d\n", c->name, c->super, c->index);
r_list_foreach (c->methods, iter2, methname) {
r_cons_printf ("f method.%s.%s\n", c->name, methname);
r_list_foreach (c->methods, iter2, sym) {
r_cons_printf ("f method.%s.%s\n", c->name, sym->name);
}
} else {
r_cons_printf ("class %d @ 0x%"PFMT64x" = %s\n",
c->index, c->addr, c->name);
r_cons_printf ("0x%08"PFMT64x" class %d %s ",
c->addr, c->index, c->name);
if (c->super)
r_cons_printf (" super = %s\n", c->super);
r_list_foreach (c->methods, iter2, methname) {
r_cons_printf (" method %s\n", methname);
r_cons_printf (" super: %s\n", c->super);
r_cons_newline();
int m = 0;
r_list_foreach (c->methods, iter2, sym) {
r_cons_printf ("0x%08"PFMT64x" method %d %s\n", sym->vaddr, m, sym->name);
m++;
}
r_cons_newline ();
}
// TODO: show belonging methods and fields
free (name);

View file

@ -311,11 +311,51 @@ static int cmd_info(void *data, const char *input) {
}
break;
case 'c': // for r2 `ic`
if (input[1]== ' ') {
eprintf ("TODO: list methods\n");
if (input[1]== '?') {
eprintf("Usage: ic[jq*] [class-index]\n");
} else if (input[1]== ' ' || input[1] == 'q' || input[1] == 'j') {
RBinClass *cls;
RBinSymbol *sym;
RListIter *iter;
RBinObject *obj = r_bin_cur_object (core->bin);
int idx = r_num_math (core->num, input +2);
int count = 0;
if (input[2]) {
r_list_foreach (obj->classes, iter, cls) {
if (idx != count++)
continue;
switch (input[1]) {
case '*':
r_list_foreach (cls->methods, iter, sym) {
r_cons_printf ("f sym.%s @ 0x%"PFMT64x"\n", sym->name, sym->vaddr);
}
break;
case 'j':
r_cons_printf ("\"class\":\"%s\"", cls->name);
r_cons_printf (",\"methods\":[");
r_list_foreach (cls->methods, iter, sym) {
const char *comma = iter->p? ",": "";
r_cons_printf ("%s{\"name\":\"%s\",\"vaddr\":%"PFMT64d"}",
comma, sym->name, sym->vaddr);
}
r_cons_printf ("]");
break;
default:
r_cons_printf ("class %s\n", cls->name);
r_list_foreach (cls->methods, iter, sym) {
r_cons_printf ("method %s\n", sym->name);
}
break;
}
goto done;
}
} else {
RBININFO ("classes", R_CORE_BIN_ACC_CLASSES);
}
} else {
RBININFO ("classes", R_CORE_BIN_ACC_CLASSES); break;
RBININFO ("classes", R_CORE_BIN_ACC_CLASSES);
}
break;
case 'D':
if (input[1]!=' ' || !demangle (core, input+2)) {
eprintf ("|Usage: iD lang symbolname\n");