From d054008b17aa81e45bbc5094de0a2bd8aed1e59a Mon Sep 17 00:00:00 2001 From: pancake Date: Mon, 6 Jul 2015 02:38:54 +0200 Subject: [PATCH] Implement class methods for DEX and make `icj` --- libr/bin/bin.c | 13 +- libr/bin/filter.c | 11 +- libr/bin/format/mach0/mach0.c | 4 +- libr/bin/p/bin_dex.c | 288 ++++++++++++++++++---------------- libr/core/bin.c | 20 ++- libr/core/cmd_info.c | 46 +++++- 6 files changed, 226 insertions(+), 156 deletions(-) diff --git a/libr/bin/bin.c b/libr/bin/bin.c index e4f8cdeaac..e1623fdb5e 100644 --- a/libr/bin/bin.c +++ b/libr/bin/bin.c @@ -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 { diff --git a/libr/bin/filter.c b/libr/bin/filter.c index 67e465dd4e..4d95b699c1 100644 --- a/libr/bin/filter.c +++ b/libr/bin/filter.c @@ -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); diff --git a/libr/bin/format/mach0/mach0.c b/libr/bin/format/mach0/mach0.c index d60b59fa49..a2edb7a9c1 100644 --- a/libr/bin/format/mach0/mach0.c +++ b/libr/bin/format/mach0/mach0.c @@ -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; diff --git a/libr/bin/p/bin_dex.c b/libr/bin/p/bin_dex.c index 602593b843..c696d9a03a 100644 --- a/libr/bin/p/bin_dex.c +++ b/libr/bin/p/bin_dex.c @@ -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=0xffff) { + DM = 0xFFFF; + } +#endif + ut64 omi = 0; + for (j=0; jheader.method_size) methods[MI] = 1; + if (MC>0 && bin->code_from>MC) bin->code_from = MC; + if (MC>0 && bin->code_tocode_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; jheader.method_size) methods[MI] = 1; + if (MC>0 && bin->code_from>MC) bin->code_from = MC; + if (MC>0 && bin->code_tocode_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=0xffff) { - DM = 0xFFFF; - } -#endif - ut64 omi = 0; - for (j=0; jheader.method_size) methods[MI] = 1; - if (MC>0 && bin->code_from>MC) bin->code_from = MC; - if (MC>0 && bin->code_tocode_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; jheader.method_size) methods[MI] = 1; - if (MC>0 && bin->code_from>MC) bin->code_from = MC; - if (MC>0 && bin->code_tocode_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); diff --git a/libr/core/bin.c b/libr/core/bin.c index 368012134e..22eed01f2b 100644 --- a/libr/core/bin.c +++ b/libr/core/bin.c @@ -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); diff --git a/libr/core/cmd_info.c b/libr/core/cmd_info.c index 5724e84ee7..3bca322da3 100644 --- a/libr/core/cmd_info.c +++ b/libr/core/cmd_info.c @@ -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");