Enhance DEX parser

This commit is contained in:
Marc 2016-09-09 19:27:36 +02:00 committed by radare
parent 9fdc110816
commit a76977a895
3 changed files with 387 additions and 202 deletions

View File

@ -4,6 +4,14 @@
#include <r_util.h>
#include "dex.h"
#define DEBUG_PRINTF 0
#if DEBUG_PRINTF
#define dprintf eprintf
#else
#define dprintf if (0)eprintf
#endif
char* r_bin_dex_get_version(RBinDexObj *bin) {
if (bin) {
ut8* version = calloc (1, 8);
@ -58,8 +66,32 @@ RBinDexObj *r_bin_dex_new_buf(RBuffer *buf) {
dexhdr->data_size = r_read_le32 (bufptr + 104);
dexhdr->data_offset = r_read_le32 (bufptr + 108);
#if DEBUG_PRINTF
dprintf ("DEX file header:\n");
dprintf ("magic : 'dex\\n035\\0'\n");
dprintf ("checksum : %x\n", dexhdr->checksum);
dprintf ("signature : %02x%02x...%02x%02x\n", dexhdr->signature[0], dexhdr->signature[1], dexhdr->signature[18], dexhdr->signature[19]);
dprintf ("file_size : %d\n", dexhdr->size);
dprintf ("header_size : %d\n", dexhdr->header_size);
dprintf ("link_size : %d\n", dexhdr->linksection_size);
dprintf ("link_off : %d (0x%06x)\n", dexhdr->linksection_offset, dexhdr->linksection_offset);
dprintf ("string_ids_size : %d\n", dexhdr->strings_size);
dprintf ("string_ids_off : %d (0x%06x)\n", dexhdr->strings_offset, dexhdr->strings_offset);
dprintf ("type_ids_size : %d\n", dexhdr->types_size);
dprintf ("type_ids_off : %d (0x%06x)\n", dexhdr->types_offset, dexhdr->types_offset);
dprintf ("proto_ids_size : %d\n", dexhdr->prototypes_size);
dprintf ("proto_ids_off : %d (0x%06x)\n", dexhdr->prototypes_offset, dexhdr->prototypes_offset);
dprintf ("field_ids_size : %d\n", dexhdr->fields_size);
dprintf ("field_ids_off : %d (0x%06x)\n", dexhdr->fields_offset, dexhdr->fields_offset);
dprintf ("method_ids_size : %d\n", dexhdr->method_size);
dprintf ("method_ids_off : %d (0x%06x)\n", dexhdr->method_offset, dexhdr->method_offset);
dprintf ("class_defs_size : %d\n", dexhdr->class_size);
dprintf ("class_defs_off : %d (0x%06x)\n", dexhdr->class_offset, dexhdr->class_offset);
dprintf ("data_size : %d\n", dexhdr->data_size);
dprintf ("data_off : %d (0x%06x)\n\n", dexhdr->data_offset, dexhdr->data_offset);
#endif
/* strings */
//eprintf ("strings size: %d\n", dexhdr->strings_size);
#define STRINGS_SIZE ((dexhdr->strings_size+1)*sizeof(ut32))
bin->strings = (ut32 *) calloc (dexhdr->strings_size + 1, sizeof (ut32));
if (!bin->strings) {
@ -94,7 +126,6 @@ RBinDexObj *r_bin_dex_new_buf(RBuffer *buf) {
bin->classes[i].class_data_offset = r_read_le32 (bufptr + offset + 24);
bin->classes[i].static_values_offset = r_read_le32 (bufptr + offset + 28);
}
//{ ut8 *b = (ut8*)&bin->methods; eprintf ("CLASS %02x %02x %02x %02x\n", b[0], b[1], b[2], b[3]); }
/* methods */
int methods_size = dexhdr->method_size * sizeof (struct dex_method_t);
@ -144,7 +175,26 @@ RBinDexObj *r_bin_dex_new_buf(RBuffer *buf) {
bin->fields[i].type_id = r_read_le16 (bufptr + offset + 2);
bin->fields[i].name_id = r_read_le32 (bufptr + offset + 4);
}
/* proto */
int protos_size = dexhdr->prototypes_size * sizeof (struct dex_proto_t);
if (dexhdr->prototypes_offset + protos_size >= bin->size) {
protos_size = bin->size - dexhdr->prototypes_offset;
}
if (protos_size < 0) {
protos_size = 0;
}
dexhdr->prototypes_size = protos_size / sizeof (struct dex_proto_t);
bin->protos = (struct dex_proto_t *) calloc (protos_size, 1);
for (i = 0; i < dexhdr->prototypes_size; i++) {
ut64 offset = dexhdr->prototypes_offset + i * sizeof (struct dex_proto_t);
bin->protos[i].shorty_id = r_read_le32 (bufptr + offset + 0);
bin->protos[i].return_type_id = r_read_le32 (bufptr + offset + 4);
bin->protos[i].parameters_off = r_read_le32 (bufptr + offset + 8);
}
return bin;
fail:
if (bin) {
r_buf_free (bin->b);

View File

@ -36,7 +36,7 @@ typedef struct dex_header_t {
typedef struct dex_proto_t {
ut32 shorty_id;
ut32 return_type_id;
ut32 params_id;
ut32 parameters_off;
} DexProto;
typedef struct dex_type_t {
@ -75,10 +75,11 @@ typedef struct r_bin_dex_obj_t {
RBuffer *b;
struct dex_header_t header;
ut32 *strings;
struct dex_class_t *classes;
struct dex_method_t *methods;
struct dex_type_t *types;
struct dex_proto_t *protos;
struct dex_field_t *fields;
struct dex_method_t *methods;
struct dex_class_t *classes;
RList *methods_list;
RList *imports_list;
ut64 code_from;

View File

@ -18,6 +18,207 @@
static Sdb *mdb = NULL;
static char *getstr(RBinDexObj *bin, int idx) {
ut8 buf[6];
ut64 len;
int uleblen;
if (idx < 0 || idx >= bin->header.strings_size || !bin->strings) {
return NULL;
}
r_buf_read_at (bin->b, bin->strings[idx], buf, sizeof (buf));
uleblen = r_uleb128 (buf, sizeof (buf), &len) - buf;
// TODO: improve this ugly fix
char c = 'a';
while (c) {
r_buf_read_at (bin->b, (bin->strings[idx]) + uleblen + len, (ut8*)&c, 1);
len++;
}
if ((int)len > 0 && len < R_BIN_SIZEOF_STRINGS) {
char *str = calloc (1, len + 1);
if (str) {
r_buf_read_at (bin->b, (bin->strings[idx]) + uleblen, (ut8*)str, len);
str[len] = 0;
return str;
}
}
return NULL;
}
/*
* Count the number of '1' bits in a word.
*/
static int countOnes(ut32 val) {
int count = 0;
val = val - ((val >> 1) & 0x55555555);
val = (val & 0x33333333) + ((val >> 2) & 0x33333333);
count = (((val + (val >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24;
return count;
}
/*
* Flag for use with createAccessFlagStr().
*/
typedef enum {
kAccessForClass = 0, kAccessForMethod = 1, kAccessForField = 2,
kAccessForMAX
} AccessFor;
/*
* Create a new string with human-readable access flags.
*
* In the base language the access_flags fields are type u2; in Dalvik
* they're u4.
*/
static char* createAccessFlagStr(ut32 flags, AccessFor forWhat)
{
#define NUM_FLAGS 18
static const char* kAccessStrings[kAccessForMAX][NUM_FLAGS] = {
{
/* class, inner class */
"PUBLIC", /* 0x0001 */
"PRIVATE", /* 0x0002 */
"PROTECTED", /* 0x0004 */
"STATIC", /* 0x0008 */
"FINAL", /* 0x0010 */
"?", /* 0x0020 */
"?", /* 0x0040 */
"?", /* 0x0080 */
"?", /* 0x0100 */
"INTERFACE", /* 0x0200 */
"ABSTRACT", /* 0x0400 */
"?", /* 0x0800 */
"SYNTHETIC", /* 0x1000 */
"ANNOTATION", /* 0x2000 */
"ENUM", /* 0x4000 */
"?", /* 0x8000 */
"VERIFIED", /* 0x10000 */
"OPTIMIZED", /* 0x20000 */
},
{
/* method */
"PUBLIC", /* 0x0001 */
"PRIVATE", /* 0x0002 */
"PROTECTED", /* 0x0004 */
"STATIC", /* 0x0008 */
"FINAL", /* 0x0010 */
"SYNCHRONIZED", /* 0x0020 */
"BRIDGE", /* 0x0040 */
"VARARGS", /* 0x0080 */
"NATIVE", /* 0x0100 */
"?", /* 0x0200 */
"ABSTRACT", /* 0x0400 */
"STRICT", /* 0x0800 */
"SYNTHETIC", /* 0x1000 */
"?", /* 0x2000 */
"?", /* 0x4000 */
"MIRANDA", /* 0x8000 */
"CONSTRUCTOR", /* 0x10000 */
"DECLARED_SYNCHRONIZED", /* 0x20000 */
},
{
/* field */
"PUBLIC", /* 0x0001 */
"PRIVATE", /* 0x0002 */
"PROTECTED", /* 0x0004 */
"STATIC", /* 0x0008 */
"FINAL", /* 0x0010 */
"?", /* 0x0020 */
"VOLATILE", /* 0x0040 */
"TRANSIENT", /* 0x0080 */
"?", /* 0x0100 */
"?", /* 0x0200 */
"?", /* 0x0400 */
"?", /* 0x0800 */
"SYNTHETIC", /* 0x1000 */
"?", /* 0x2000 */
"ENUM", /* 0x4000 */
"?", /* 0x8000 */
"?", /* 0x10000 */
"?", /* 0x20000 */
},
};
const int kLongest = 21; /* strlen of longest string above */
int i, count;
char* str;
char* cp;
/*
* Allocate enough storage to hold the expected number of strings,
* plus a space between each. We over-allocate, using the longest
* string above as the base metric.
*/
count = countOnes(flags);
cp = str = (char*) malloc(count * (kLongest+1) +1);
for (i = 0; i < NUM_FLAGS; i++) {
if (flags & 0x01) {
const char* accessStr = kAccessStrings[forWhat][i];
int len = strlen(accessStr);
if (cp != str)
*cp++ = ' ';
memcpy(cp, accessStr, len);
cp += len;
}
flags >>= 1;
}
*cp = '\0';
return str;
}
static char* dex_method_signature(RBinDexObj *bin, int method_idx) {
if(method_idx >= bin->header.method_size) {
return NULL;
}
ut32 params_off = bin->protos[bin->methods[method_idx].proto_id].parameters_off;
char* return_type = getstr(bin, bin->types[bin->protos[bin->methods[method_idx].proto_id].return_type_id].descriptor_id);
if (params_off == 0) {
return r_str_newf("()%s", return_type);;
}
ut8 *bufptr;
bufptr = bin->b->buf;
ut32 list_size = r_read_le32 (bufptr + params_off); // size of the list, in entries
char *signature = calloc(0, sizeof(char));
// TODO: improve performance on this fucking shit
// TODO: r_strbuf_append
//dprintf("Parsing Signature List with %d items\n", list_size);
ut16 type_idx;
char * buff;
int size = 1; // TODO: NOT_SURE_ABOUT_IT
int i;
for (i = 0; i < list_size; i++) {
type_idx = r_read_le16 (bufptr + params_off + 4 + (i*2));
buff = getstr(bin, bin->types[type_idx].descriptor_id);
size += strlen(buff) * sizeof(char);
signature = realloc(signature, size);
signature = strcat(signature, buff);
}
// TODO: check that
//free(bufptr);
free(buff);
char* r = r_str_newf("(%s)%s", signature, return_type);
free(signature);
return r;
}
static int check(RBinFile *arch);
static int check_bytes(const ut8 *buf, ut64 length);
@ -52,16 +253,6 @@ static ut64 baddr(RBinFile *arch) {
return 0;
}
static char *flagname (const char *class, const char *method) {
if (method) {
if (class) {
return r_str_newf ("%s.%s", class, method);
}
return r_str_newf ("static.method.%s", method);
}
return NULL;
}
static int check(RBinFile *arch) {
const ut8 *bytes = arch ? r_buf_buffer (arch->buf) : NULL;
ut64 sz = arch ? r_buf_size (arch->buf): 0;
@ -73,23 +264,23 @@ static int check_bytes(const ut8 *buf, ut64 length) {
return false;
// Non-extended opcode dex file
if (!memcmp (buf, "dex\n035\0", 8)) {
return true;
return true;
}
// Extended (jumnbo) opcode dex file, ICS+ only (sdk level 14+)
if (!memcmp (buf, "dex\n036\0", 8)) {
return true;
return true;
}
// M3 (Nov-Dec 07)
if (!memcmp (buf, "dex\n009\0", 8)) {
return true;
return true;
}
// M5 (Feb-Mar 08)
if (!memcmp (buf, "dex\n009\0", 8)) {
return true;
if (!memcmp (buf, "dex\n009\0", 8)) {
return true;
}
// Default fall through, should still be a dex file
if (!memcmp (buf, "dex\n", 4)) {
return true;
return true;
}
return false;
}
@ -127,17 +318,18 @@ static RBinInfo *info(RBinFile *arch) {
memcpy (h->buf, arch->buf->buf + 8, 4);
{
ut32 *fc = (ut32 *)(arch->buf->buf + 8);
ut32 cc = __adler32 (arch->buf->buf + h->from, h->to);
//ut8 *fb = (ut8*)fc, *cb = (ut8*)&cc;
ut32 cc = __adler32 (arch->buf->buf + 12, arch->buf->length - 12);
if (*fc != cc) {
dprintf ("# adler32 checksum doesn't match. Type this to fix it:\n");
dprintf ("wx `#sha1 $s-32 @32` @12 ; wx `#adler32 $s-12 @12` @8\n");
eprintf ("# adler32 checksum doesn't match. Type this to fix it:\n");
eprintf ("wx `#sha1 $s-32 @32` @12 ; wx `#adler32 $s-12 @12` @8\n");
}
}
ret->arch = strdup ("dalvik");
ret->lang = "java";
ret->lang = "dalvik";
ret->bits = 32;
ret->big_endian = 0;
ret->dbg_info = 0; //1 | 4 | 8; /* Stripped | LineNums | Syms */
@ -173,6 +365,7 @@ static RList* strings (RBinFile *arch) {
}
r_buf_read_at (bin->b, bin->strings[i], (ut8*)&buf, 6);
len = dex_read_uleb128 (buf);
if (len > 1 && len < R_BIN_SIZEOF_STRINGS) {
ptr->string = malloc (len + 1);
if (!ptr->string)
@ -190,7 +383,6 @@ static RList* strings (RBinFile *arch) {
ptr->ordinal = i+1;
r_list_append (ret, ptr);
} else {
dprintf ("dex_read_uleb128: invalid read\n");
free (ptr);
}
}
@ -201,50 +393,7 @@ out_error:
return NULL;
}
#if 0
static inline ut32 getmethodoffset (struct r_bin_dex_obj_t *bin, int n, ut32 *size) {
ut8 *buf, *map_end, *map;
ut32 mapsz, off = 0L;
int left;
*size = 0;
map = buf = r_buf_get_at (bin->b, bin->header.data_offset, &left);
if (!map) return 0;
for (map_end = map+bin->header.data_size; map<map_end;) {
int num = map[0] + (map[1]<<8);
int ninsn = map[12] + (map[13]<<8);
map += 16; // skip header
mapsz = ninsn%2? (ninsn+1)*2: ninsn*2;
if (n == num) {
*size = mapsz;
off = bin->header.data_offset + (size_t)(map - buf);
break;
}
map += mapsz;
}
return off;
}
#endif
static char *getstr (RBinDexObj *bin, int idx) {
ut8 buf[6];
ut64 len;
int uleblen;
if (idx < 0 || idx >= bin->header.strings_size || !bin->strings) {
return NULL;
}
r_buf_read_at (bin->b, bin->strings[idx], buf, sizeof (buf));
uleblen = r_uleb128 (buf, sizeof (buf), &len) - buf;
if ((int)len > 0 && len < R_BIN_SIZEOF_STRINGS) {
char *str = calloc (1, len + 1);
if (str) {
r_buf_read_at (bin->b, (bin->strings[idx]) + uleblen, (ut8*)str, len);
str[len] = 0;
return str;
}
}
return NULL;
}
/*
static char *get_string(RBinDexObj *bin, int cid, int idx) {
char *c_name, *m_name, *res;
if (idx < 0 || idx >= bin->header.strings_size) {
@ -259,7 +408,7 @@ static char *get_string(RBinDexObj *bin, int cid, int idx) {
res = r_str_newf ("%s", m_name);
} else {
if (c_name && m_name) {
res = r_str_newf ("method.%s", m_name);
res = r_str_newf ("%s", m_name);
} else {
if (c_name && m_name) {
res = r_str_newf ("unk.%s", c_name);
@ -272,6 +421,7 @@ static char *get_string(RBinDexObj *bin, int cid, int idx) {
free (m_name);
return res;
}
*/
/* TODO: check boundaries */
static char *dex_method_name (RBinDexObj *bin, int idx) {
@ -286,7 +436,7 @@ static char *dex_method_name (RBinDexObj *bin, int idx) {
if (tid < 0 || tid >= bin->header.strings_size) {
return NULL;
}
return get_string (bin, cid, tid);
return getstr(bin, tid);
}
static char *dex_class_name_byid (RBinDexObj *bin, int cid) {
@ -294,15 +444,14 @@ static char *dex_class_name_byid (RBinDexObj *bin, int cid) {
if (!bin || !bin->types) {
return NULL;
}
//cid = c->super_class;
if (cid < 0 || cid >= bin->header.types_size) {
return NULL;
}
tid = bin->types [cid].descriptor_id;
//int sid = bin->strings[tid];
return get_string (bin, cid, tid);
return getstr(bin, tid);
}
/*
static char *getClassName(const char *name) {
const char *p;
if (!name) {
@ -317,50 +466,7 @@ static char *getClassName(const char *name) {
}
return NULL;
}
#if DEX_UNUSED
static char *dexFieldName(RBinDexObj *dex, RBinDexClass *c, int fn) {
DexField field = { 0 };
ut8 ff[sizeof (DexField)] = {0};
ut32 off = dex->header.fields_offset;
int delta = fn * sizeof (DexField);
if (delta > dex->header.fields_size) {
return NULL;
}
r_buf_read_at (dex->b, off + delta, ff, sizeof (DexField));
field.name_id = r_read_le32 (ff + 4);
eprintf ("NAME = %d\n", field.name_id);
return getstr (dex, field.name_id);
}
static char *dexFieldType(RBinDexObj *dex, RBinDexClass *c, int fn) {
DexField field = { 0 };
ut8 ff[sizeof (DexField)] = {0};
ut32 off = dex->header.fields_offset;
int delta = fn * sizeof (DexField);
if (delta > dex->header.fields_size) {
return NULL;
}
r_buf_read_at (dex->b, off + delta, ff, sizeof (DexField));
field.type_id = r_read_le16 (ff + 2);
eprintf ("TYPE = %d\n", field.type_id);
return getstr (dex, field.type_id);
}
static char *dex_type_name (RBinDexObj *bin, int id) {
int cid, tid;
if (!bin || !bin->types) {
return NULL;
}
cid = id;
if (cid < 0 || cid >= bin->header.types_size) {
return NULL;
}
tid = bin->types [cid].descriptor_id;
//int sid = bin->strings[tid];
return get_string (bin, cid, tid);// cid, tid);
}
#endif
*/
static char *dex_class_name (RBinDexObj *bin, RBinDexClass *c) {
int cid, tid;
@ -368,13 +474,11 @@ static char *dex_class_name (RBinDexObj *bin, RBinDexClass *c) {
return NULL;
}
cid = c->class_id;
//cid = c->super_class;
if (cid < 0 || cid >= bin->header.types_size) {
return NULL;
}
tid = bin->types [cid].descriptor_id;
//int sid = bin->strings[tid];
return get_string (bin, cid, tid);
return getstr(bin, tid);
}
static char *dex_class_super_name (RBinDexObj *bin, RBinDexClass *c) {
@ -387,14 +491,13 @@ static char *dex_class_super_name (RBinDexObj *bin, RBinDexClass *c) {
return NULL;
}
tid = bin->types [cid].descriptor_id;
//int sid = bin->strings[tid];
return get_string (bin, cid, tid);
return getstr(bin, tid);
}
static int *parse_class(RBinFile *binfile, RBinDexObj *bin, RBinDexClass *c, RBinClass *cls) {
ut64 SF, IF, DM, VM, lastIndex;
ut8 ff[sizeof (DexField)] = {0};
char *class_name; // , *cln = NULL;
char *class_name, *cln = NULL;
int total, i, *methods;
const ut8 *p, *p_end;
DexField field;
@ -404,6 +507,8 @@ static int *parse_class(RBinFile *binfile, RBinDexObj *bin, RBinDexClass *c, RBi
}
// TODO: do not call twice
class_name = dex_class_name (bin, c);
class_name = r_str_replace (class_name, ";", "", 0); //TODO: move to func
if (!class_name || !*class_name) {
return NULL;
}
@ -412,16 +517,21 @@ static int *parse_class(RBinFile *binfile, RBinDexObj *bin, RBinDexClass *c, RBi
free (class_name);
return false;
}
dprintf (" class_data_offset: %d\n", c->class_data_offset);
dprintf(" Class descriptor : '%s'\n", dex_class_name (bin, c));
dprintf(" Access flags : 0x%04x (%s)\n", c->access_flags, createAccessFlagStr(c->access_flags, kAccessForClass));
dprintf(" Superclass : '%s'\n", dex_class_super_name (bin, c));
dprintf(" Interfaces -\n");
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);
dprintf (" static fields: %u\n", (ut32)SF);
/* parsing static and instance fields is known to be:
* - slow
@ -429,12 +539,13 @@ static int *parse_class(RBinFile *binfile, RBinDexObj *bin, RBinDexClass *c, RBi
* - i miss some fields.. maybe we need more testing
*/
dprintf(" Static fields -\n");
/* static fields */
const ut8 *op = p;
lastIndex = 0;
for (i = 0; i < SF; i++) {
ut64 fieldIndex, accessFlags;
// int fieldOffset = bin->header.fields_offset + (p - op);
p = r_uleb128 (p, p_end - p, &fieldIndex); // fieldIndex
p = r_uleb128 (p, p_end - p, &accessFlags); // accessFlags
fieldIndex += lastIndex;
@ -446,20 +557,32 @@ static int *parse_class(RBinFile *binfile, RBinDexObj *bin, RBinDexClass *c, RBi
field.type_id = r_read_le16 (ff + 2);
field.name_id = r_read_le32 (ff + 4);
char *fieldName = getstr (bin, field.name_id);
const char* accessStr = createAccessFlagStr(accessFlags, kAccessForField);
int tid = bin->types[field.type_id].descriptor_id;
const char* type_str = getstr(bin, tid);//get_string(bin, field.type_id, tid);
if (1) {
RBinSymbol *sym = R_NEW0 (RBinSymbol);
/* index matters because two fields can have the same name */
sym->name = r_str_newf ("%s.sfield_%d_%s", class_name, i, fieldName);
sym->name = r_str_newf ("%s.sfield_%s:%s", class_name, fieldName, type_str);
sym->name = r_str_replace (sym->name, "method.", "", 0);
sym->name = r_str_replace (sym->name, ";", "", 0);
sym->type = r_str_const ("STATIC");
sym->paddr = sym->vaddr = total;
dprintf(" #%d : (in %s)\n", i, class_name);
dprintf(" name : '%s'\n", fieldName);
dprintf(" type : '%s'\n", type_str);
dprintf(" access : 0x%04x (%s)\n", accessFlags, accessStr);
r_list_append (bin->methods_list, sym);
}
lastIndex = fieldIndex;
}
dprintf(" Instance fields -\n");
/* instance fields */
//eprintf (" instance fields: %u\n", (ut32)IF);
lastIndex = 0;
op = p;
for (i = 0; i < IF; i++) {
@ -482,30 +605,34 @@ static int *parse_class(RBinFile *binfile, RBinDexObj *bin, RBinDexClass *c, RBi
field.type_id = r_read_le16 (ff + 2);
field.name_id = r_read_le32 (ff + 4);
char *name = getstr (bin, field.name_id);
#if 0
cln = r_str_replace (strdup (class_name), "method.", "", 0);
cln = r_str_replace (cln, ";", "_", 0);
#endif
if (accessFlags == 0) {
// eprintf ("PUBLIC\n");
}
//eprintf ("f sym.%s.field.%d_%s = %d\n", class_name, i, name, fieldOffset);
const char* accessStr = createAccessFlagStr(accessFlags, kAccessForField);
int tid = bin->types[field.type_id].descriptor_id;
const char* type_str = getstr(bin, tid);
if (1) {
RBinSymbol *sym = R_NEW0 (RBinSymbol);
//sym->name = r_str_newf ("ifield.%s.%d_%s", class_name, i, name);
sym->name = r_str_newf ("%s.ifield_%d_%s", class_name, i, name);
sym->name = r_str_newf ("%s.ifield_%s:%s", class_name, name, type_str);
sym->name = r_str_replace (sym->name, "method.", "", 0);
sym->name = r_str_replace (sym->name, ";", "", 0);
sym->type = r_str_const ("FIELD");
sym->paddr = sym->vaddr = total;
// eprintf ("0x%x %s\n", fieldIndex + bin->header.fields_offset, sym->name);
dprintf(" #%d : (in %s)\n", i, class_name);
dprintf(" name : '%s'\n", name);
dprintf(" type : '%s'\n", type_str);
dprintf(" access : 0x%04x (%s)\n", accessFlags, accessStr);
r_list_append (bin->methods_list, sym);
}
lastIndex = fieldIndex;
}
dprintf (" Direct methods -\n");
/* direct methods (aka static) */
dprintf (" direct methods: %u\n", (ut32)DM);
ut64 omi = 0;
for (i = 0; i < DM; i++) {
char *method_name, *flag_name;
@ -529,27 +656,32 @@ static int *parse_class(RBinFile *binfile, RBinDexObj *bin, RBinDexClass *c, RBi
}
method_name = dex_method_name (bin, MI);
dprintf ("METHOD NAME %u\n", (ut32)MI);
char *signature = dex_method_signature(bin, MI);
if (!method_name) {
method_name = strdup ("unknown");
}
flag_name = flagname (class_name, method_name);
flag_name = r_str_replace (flag_name, "method.", "", 0);
flag_name = r_str_replace (flag_name, ";", "", 0);
flag_name = r_str_newf ("%s.method.%s%s", class_name, method_name, signature);
if (!flag_name) {
continue;
}
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);
const char* accessStr = createAccessFlagStr(MA, kAccessForMethod);
dprintf(" #%d : (in %s)\n", i, class_name);
dprintf(" name : '%s'\n", method_name);
dprintf(" type : '%s'\n", signature);
dprintf(" access : 0x%04x (%s)\n", MA, accessStr);
/* add symbol */
if (*flag_name) {
RBinSymbol *sym = R_NEW0 (RBinSymbol);
sym->name = flag_name;
sym->type = r_str_const ("FUNC");
sym->paddr = sym->vaddr = MC;
sym->paddr = MC + 0x10;
sym->vaddr = MC + 0x10;
if (MC > 0) { /* avoid methods at 0 paddr */
#if 0
// TODO: use sdb+pf to show method header
@ -564,9 +696,8 @@ static int *parse_class(RBinFile *binfile, RBinDexObj *bin, RBinDexClass *c, RBi
try_item[tries_size] tries
encoded_catch_handler_list handlers
#endif
sym->paddr += 0x10;
r_list_append (bin->methods_list, sym);
// this causes an invalid flag name issue
// this causes an invalid flag name issue
if (cls) {
if (!cls->methods) {
/* probably unnecessary for */
@ -589,14 +720,19 @@ static int *parse_class(RBinFile *binfile, RBinDexObj *bin, RBinDexClass *c, RBi
}
free (method_name);
}
/* virtual methods */
dprintf (" virtual methods: %u\n", (ut32)VM);
dprintf (" Virtual methods -\n");
omi = 0;
for (i = 0; i < VM; i++) {
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);
MI += omi;
omi = MI;
if ((int)MI >= 0 && MI < bin->header.method_size) {
methods[MI] = 1;
}
@ -607,26 +743,34 @@ static int *parse_class(RBinFile *binfile, RBinDexObj *bin, RBinDexClass *c, RBi
bin->code_to = MC;
}
char *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);
char *signature = dex_method_signature(bin, MI);
const char* accessStr = createAccessFlagStr(MA, kAccessForMethod);
dprintf(" #%d : (in %s)\n", i, class_name);
dprintf(" name : '%s'\n", name);
dprintf(" type : '%s'\n", signature);
dprintf(" access : 0x%04x (%s)\n", MA, accessStr);
{
RBinSymbol *sym = R_NEW0 (RBinSymbol);
//sym->name = r_str_newf ("virtual.%s.%s", class_name, name);
sym->name = r_str_newf ("%s.%s", class_name, name);
sym->name = r_str_replace (sym->name, "method.", "", 0);
sym->name = r_str_replace (sym->name, ";", "", 0);
sym->name = r_str_newf ("%s.method.%s%s", class_name, name, signature);
//sym->name = r_str_replace (sym->name, "method.", "", 0);
//sym->name = r_str_replace (sym->name, ";", "", 0); // TODO: fix ; after method name
sym->type = r_str_const ("METH");
sym->paddr = sym->vaddr = MC;
r_list_append (bin->methods_list, sym);
}
free (name);
free(signature);
}
free (class_name);
return methods;
}
static int dex_loadcode(RBinFile *arch, RBinDexObj *bin) {
int i;
int *methods = NULL;
@ -657,49 +801,43 @@ static int dex_loadcode(RBinFile *arch, RBinDexObj *bin) {
return false;
}
dprintf ("Walking %d classes\n", bin->header.class_size);
/* debug prototypes */
/*
for (i = 0; i < bin->header.prototypes_size; i++) {
dprintf("PROTO[%d], %d, %d, %d\n", i, bin->protos[i].shorty_id, bin->protos[i].return_type_id, bin->protos[i].parameters_off );
}
*/
/* debug strings */
/*
for (i = 0; i < bin->header.strings_size; i++) {
dprintf("STR[%d], %s\n", i, getstr(bin, i));
}
*/
if (bin->classes) {
for (i = 0; i < bin->header.class_size; i++) {
char *super_name, *class_name;
struct dex_class_t *c = &bin->classes[i];
class_name = dex_class_name (bin, c);
super_name = dex_class_super_name (bin, c);
//eprintf ("%s\n", class_name);
dprintf ("{\n");
dprintf (" class: 0x%x,\n", c->class_id); // indexed by ordinal
dprintf (" super: \"%s\",\n", super_name); // indexed by name
dprintf (" name: \"%s\",\n", class_name);
dprintf (" methods: [\n");
// sdb_queryf ("(-1)classes=%s", class_name)
// sdb_queryf ("class.%s.super=%s", super_name)
// sdb_queryf ("class.%s.methods=%d", class_name, DM);
#if 0
if (c->class_data_offset == 0) {
eprintf ("Skip class\n");
continue;
}
#endif
free (methods);
dprintf("Class #%d -\n", i); // TODO: rename this to idx
methods = parse_class (arch, bin, c, NULL);
dprintf (" ],\n");
dprintf ("},");
//dprintf (" ],\n");
//dprintf ("},");
free (class_name);
free (super_name);
}
}
if (methods) {
dprintf ("imports: \n");
//dprintf ("imports: \n");
for (i = 0; i < bin->header.method_size; i++) {
//RBinDexMethod *method = &bin->methods[i];
if (methods[i]) {
#if 0
struct dex_class_t *c = &bin->classes[i];
char *class_name = dex_class_name (bin, c);
char *method_name = dex_method_name (bin, i);
// dprintf ("java %s %s\n", class_name, method_name);
free (class_name);
free (method_name);
#endif
continue;
}
if (i >= bin->header.class_size) {
@ -880,26 +1018,20 @@ static RList* classes (RBinFile *arch) {
//class->name = strdup (name[0]<0x41? name+1: name);
class->name = dex_class_name_byid (bin, entry.class_id);
// find reference to this class instance
char *cn = getClassName (class->name);
char *cn = dex_class_name (bin, &entry);
if (cn) {
free (class->name);
class->index = class_index++;
class->addr = entry.class_id + bin->header.class_offset;
class->name = cn;
class->name = r_str_replace (cn, ";", "", 0);
//class->addr = class_addr;
free (parse_class (arch, bin, &entry, class));
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);
dprintf ("# super_class = %d;\n", entry.super_class);
dprintf ("# interfaces_offset = %08x;\n", entry.interfaces_offset);
//dprintf ("ut32 source_file = %08x;\n", entry.source_file);
dprintf ("# anotations_offset = %08x;\n", entry.anotations_offset);
dprintf ("# class_data_offset = %08x;\n", entry.class_data_offset);
dprintf ("# static_values_offset = %08x;\n\n", entry.static_values_offset);
} else {
dprintf("INVALID CLASS NAME");
free (class->name);
free (class);
}
@ -934,10 +1066,12 @@ static RList* entries(RBinFile *arch) {
dex_loadcode (arch, bin);
}
#if 1
// TODO: entry point in dalvik? WTF!
// XXX: entry + main???
r_list_foreach (bin->methods_list, iter, m) {
if (strlen (m->name) > 4 && !strcmp (m->name + strlen (m->name) - 5, ".main")) {
dprintf ("ENTRY -> %s\n", m->name);
// LOOKING FOR ".method.main([Ljava/lang/String;)V"
if (strlen (m->name) > 26 && !strcmp (m->name + strlen (m->name) - 27, ".main([Ljava/lang/String;)V")) {
//dprintf ("ENTRY -> %s\n", m->name);
if (!already_entry (ret, m->paddr)) {
if ((ptr = R_NEW0 (RBinAddr))) {
ptr->paddr = ptr->vaddr = m->paddr;
@ -1074,7 +1208,7 @@ static RList* sections(RBinFile *arch) {
} else {
ptr->size = ptr->vsize = arch->buf->length - ptr->vaddr;
// hacky workaround
dprintf ("Hack\n");
//dprintf ("Hack\n");
//ptr->size = ptr->vsize = 1024;
}
ptr->srwx = R_BIN_SCN_READABLE | R_BIN_SCN_MAP; //|2;
@ -1128,4 +1262,4 @@ RLibStruct radare_plugin = {
.data = &r_bin_plugin_dex,
.version = R2_VERSION
};
#endif
#endif