mirror of
https://github.com/radareorg/radare2.git
synced 2024-12-13 16:18:33 +00:00
Enhance DEX parser
This commit is contained in:
parent
9fdc110816
commit
a76977a895
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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
|
Loading…
Reference in New Issue
Block a user