static int attributes_walk(RBinJavaObj *bin, struct r_bin_java_attr_t *attr, int sz2, int fields) { char buf[0xffff+1]; // that's kinda ugly :) int sz3, sz4; int j=0,k; char *name; for (j=0; j<sz2; j++) { if (r_buf_read_at (bin->b, R_BUF_CUR, (ut8*)buf, 6) != 6) { eprintf ("Cannot read 6 bytes in class file\n"); return R_FALSE; } attr->name_idx = R_BIN_JAVA_USHORT(buf,0); name = get_cp (bin, attr->name_idx-1)->value; // XXX: if name is null.. wat? attr->name = strdup (name? name: ""); name = (get_cp(bin, attr->name_idx-1))->value;//cp_items[R_BIN_JAVA_USHORT(buf,0)-1].value; IFDBG printf(" %2d: Name Index: %d (%s)\n", j, attr->name_idx, name); // TODO add comment with constant pool index sz3 = R_BIN_JAVA_UINT (buf, 2); if (fields) { attr->type = R_BIN_JAVA_TYPE_FIELD; IFDBG printf ("FIELD\n"); } else if (sz3 > 0){ attr->length = sz3; IFDBG printf (" Length: %d\n", sz3); //R_BIN_JAVA_UINT(buf, 2)); if (!name) { IFDBG printf ("**ERROR ** Cannot identify attribute name into constant pool\n"); continue; } if (!strcmp (name, "Code")) { attr->type = R_BIN_JAVA_TYPE_CODE; r_buf_read_at (bin->b, R_BUF_CUR, (ut8*)buf, 8); attr->info.code.max_stack = R_BIN_JAVA_USHORT(buf, 0); IFDBG printf(" Max Stack: %d\n", attr->info.code.max_stack); attr->info.code.max_locals = R_BIN_JAVA_USHORT(buf, 2); IFDBG printf(" Max Locals: %d\n", attr->info.code.max_locals); attr->info.code.code_length = R_BIN_JAVA_UINT(buf, 4); IFDBG printf(" Code Length: %d\n", attr->info.code.code_length); attr->info.code.code_offset = (ut64)bin->b->cur; IFDBG printf(" Code At Offset: 0x%08"PFMT64x"\n", (ut64)attr->info.code.code_offset); r_buf_read_at(bin->b, R_BUF_CUR, (ut8*)buf, R_BIN_JAVA_UINT(buf, 4)); // READ CODE sz4 = read_short(bin); attr->info.code.exception_table_length = sz4; IFDBG printf(" Exception table length: %d\n", attr->info.code.exception_table_length); for (k=0;k<sz4;k++) { r_buf_read_at(bin->b, R_BUF_CUR, (ut8*)buf, 8); attr->info.code.start_pc = R_BIN_JAVA_USHORT(buf,0); IFDBG printf(" start_pc: 0x%04x\n", attr->info.code.start_pc); attr->info.code.end_pc = R_BIN_JAVA_USHORT(buf,2); IFDBG printf(" end_pc: 0x%04x\n", attr->info.code.end_pc); attr->info.code.handler_pc = R_BIN_JAVA_USHORT(buf,4); IFDBG printf(" handler_pc: 0x%04x\n", attr->info.code.handler_pc); attr->info.code.catch_type = R_BIN_JAVA_USHORT(buf,6); IFDBG printf(" catch_type: %d\n", attr->info.code.catch_type); } sz4 = (unsigned int)read_short(bin); IFDBG printf(" code Attributes_count: %d\n", sz4); if (sz4>0) { attr->attributes = malloc(1+sz4 * sizeof(struct r_bin_java_attr_t)); attributes_walk(bin, attr->attributes, sz4, fields); } } else if (!strcmp (name, "LineNumberTable")) { attr->type = R_BIN_JAVA_TYPE_LINENUM; sz4 = (unsigned int)read_short (bin); attr->info.linenum.table_length = sz4; IFDBG printf(" Table Length: %d\n", attr->info.linenum.table_length); eprintf ("line.%d.sym=%s\n", bin->midx, bin->methods[bin->midx].name); for (k=0; k<sz4; k++) { r_buf_read_at (bin->b, R_BUF_CUR, (ut8*)buf, 4); attr->info.linenum.start_pc = R_BIN_JAVA_USHORT (buf, 0); //eprintf (" %2d: start_pc: 0x%04x\n", k, attr->info.linenum.start_pc); attr->info.linenum.line_number = R_BIN_JAVA_USHORT (buf, 2); //eprintf (" line_number: %d\n", attr->info.linenum.line_number); eprintf ("line.%d.%d.%d=0x%x\n", bin->midx, k, attr->info.linenum.line_number, attr->info.linenum.start_pc); } } else if (!strcmp (name, "StackMapTable")) { r_buf_read_at (bin->b, R_BUF_CUR, (ut8*)buf, 2); // XXX: this is probably wrong //printf(" StackMapTable: %d\n", USHORT(buf, 0)); } else if (!strcmp (name, "LocalVariableTable")) { int i; ut32 lvtl = (ut32)read_short (bin); eprintf ("local.%d.sym=%s\n", bin->midx, bin->methods[bin->midx].name); for (i=0; i<lvtl; i++) { int start_pc = start_pc = read_short (bin); int length = length = read_short (bin); int name_idx = name_idx = read_short (bin); int desc_idx = desc_idx = read_short (bin); int index = index = read_short (bin); const char *name = get_cp (bin, name_idx-1)->value; const char *desc = get_cp (bin, desc_idx-1)->value; eprintf ("local.%d.%d.type=%s\n", bin->midx, i, desc); eprintf ("local.%d.%d.name=%s\n", bin->midx, i, name); } } else if (!strcmp (name, "ConstantValue")) { attr->type = R_BIN_JAVA_TYPE_CONST; r_buf_read_at (bin->b, R_BUF_CUR, (ut8*)buf, 2); #if 0 printf(" Name Index: %d\n", R_BIN_JAVA_USHORT(buf, 0)); // %s\n", R_BIN_JAVA_USHORT(buf, 0), cp_items[R_BIN_JAVA_USHORT(buf,0)-1].value); printf(" AttributeLength: %d\n", R_BIN_JAVA_UINT(buf, 2)); #endif attr->info.const_value_idx = R_BIN_JAVA_USHORT(buf, 0); IFDBG printf (" ConstValueIndex: %d\n", attr->info.const_value_idx); } else { eprintf ("** ERROR ** Unknown section '%s'\n", name); return R_FALSE; } } } return R_TRUE; }
static char * java_resolve(RBinJavaObj *BIN_OBJ, int idx, ut8 space_bn_name_type) { // TODO XXX FIXME add a size parameter to the str when it is passed in RBinJavaCPTypeObj *item = NULL, *item2 = NULL; char *class_str = NULL, *name_str = NULL, *desc_str = NULL, *string_str = NULL, *empty = "", *cp_name = NULL, *cp_name2 = NULL, *str = NULL; int memory_alloc = 0; if (BIN_OBJ && BIN_OBJ->cp_count < 1 ) { //javasm_init(BIN_OBJ); return NULL; } item = (RBinJavaCPTypeObj *) r_bin_java_get_item_from_bin_cp_list (BIN_OBJ, idx); if (item) { cp_name = ((RBinJavaCPTypeMetas *) item->metas->type_info)->name; IFDBG eprintf("java_resolve Resolved: (%d) %s\n", idx, cp_name); } else { str = malloc (512); if (str) snprintf (str,512, "(%d) INVALID CP_OBJ", idx); return str; } cp_name = ((RBinJavaCPTypeMetas *) item->metas->type_info)->name; if ( strcmp (cp_name, "Class") == 0 ) { item2 = (RBinJavaCPTypeObj *) r_bin_java_get_item_from_bin_cp_list (BIN_OBJ, idx); //str = r_bin_java_get_name_from_bin_cp_list (BIN_OBJ, idx-1); class_str = empty; class_str = r_bin_java_get_item_name_from_bin_cp_list (BIN_OBJ, item); if (!class_str) class_str = empty; name_str = r_bin_java_get_item_name_from_bin_cp_list (BIN_OBJ, item2); if (!name_str) name_str = empty; desc_str = r_bin_java_get_item_desc_from_bin_cp_list (BIN_OBJ, item2); if (!desc_str) desc_str = empty; memory_alloc = strlen (class_str) + strlen (name_str) + strlen (desc_str) + 3; if (memory_alloc) str = malloc (memory_alloc); if (str && !space_bn_name_type) snprintf (str, memory_alloc, "%s%s", name_str, desc_str); else if (str && space_bn_name_type) snprintf (str, memory_alloc, "%s %s", name_str, desc_str); if (class_str != empty) free (class_str); if (name_str != empty) free (name_str); if (desc_str != empty) free (desc_str); }else if ( strcmp (cp_name, "MethodRef") == 0 || strcmp (cp_name, "FieldRef") == 0 || strcmp (cp_name, "InterfaceMethodRef") == 0) { /* * The MethodRef, FieldRef, and InterfaceMethodRef structures */ class_str = r_bin_java_get_name_from_bin_cp_list (BIN_OBJ, item->info.cp_method.class_idx); if (!class_str) class_str = empty; name_str = r_bin_java_get_item_name_from_bin_cp_list (BIN_OBJ, item); if (!name_str) name_str = empty; desc_str = r_bin_java_get_item_desc_from_bin_cp_list (BIN_OBJ, item); if (!desc_str) desc_str = empty; memory_alloc = strlen (class_str) + strlen (name_str) + strlen (desc_str) + 3; if (memory_alloc) str = malloc (memory_alloc); if (str && !space_bn_name_type) snprintf (str, memory_alloc, "%s/%s%s", class_str, name_str, desc_str); else if (str && space_bn_name_type) snprintf (str, memory_alloc, "%s/%s %s", class_str, name_str, desc_str); if (class_str != empty) free (class_str); if (name_str != empty) free (name_str); if (desc_str != empty) free (desc_str); } else if (strcmp (cp_name, "String") == 0) { ut32 length = r_bin_java_get_utf8_len_from_bin_cp_list (BIN_OBJ, item->info.cp_string.string_idx); string_str = r_bin_java_get_utf8_from_bin_cp_list (BIN_OBJ, item->info.cp_string.string_idx); str = NULL; IFDBG eprintf("java_resolve String got: (%d) %s\n", item->info.cp_string.string_idx, string_str); if (!string_str) { string_str = empty; length = strlen (empty); } memory_alloc = length + 3; if (memory_alloc) str = malloc (memory_alloc); if (str) { //r_name_filter(string_str, length); snprintf (str, memory_alloc, "\"%s\"", string_str); } IFDBG eprintf("java_resolve String return: %s\n", str); if (string_str != empty) free (string_str); } else if (strcmp (cp_name, "Utf8") == 0) { str = malloc (item->info.cp_utf8.length+3); if (str) { snprintf (str, item->info.cp_utf8.length+3, "\"%s\"", item->info.cp_utf8.bytes); } } else if (strcmp (cp_name, "Long") == 0) { str = malloc (34); if (str) { snprintf (str, 34, "0x%llx", rbin_java_raw_to_long (item->info.cp_long.bytes.raw,0)); } } else if (strcmp (cp_name, "Double") == 0) { str = malloc (1000); if (str) { snprintf (str, 1000, "%f", rbin_java_raw_to_double (item->info.cp_double.bytes.raw,0)); } } else if (strcmp (cp_name, "Integer") == 0) { str = malloc (34); if (str) { snprintf (str, 34, "0x%08x", R_BIN_JAVA_UINT (item->info.cp_integer.bytes.raw,0)); } } else if (strcmp (cp_name, "Float") == 0) { str = malloc (34); if (str) { snprintf (str, 34, "%f", R_BIN_JAVA_FLOAT (item->info.cp_float.bytes.raw,0)); } } else if (strcmp (cp_name, "NameAndType") == 0) { str = malloc (64); if (str) { name_str = r_bin_java_get_item_name_from_bin_cp_list (BIN_OBJ, item); if (!name_str) name_str = empty; desc_str = r_bin_java_get_item_desc_from_bin_cp_list (BIN_OBJ, item); if (!desc_str) desc_str = empty; memory_alloc = strlen (name_str) + strlen (desc_str) + 3; if (memory_alloc) str = malloc (memory_alloc); if (str && !space_bn_name_type) snprintf (str, memory_alloc, "%s%s", name_str, desc_str); else if (str && space_bn_name_type) snprintf (str, memory_alloc, "%s %s", name_str, desc_str); if (name_str != empty) free (name_str); if (desc_str != empty) free (desc_str); } } else { str = malloc (16); if (str) { snprintf (str, 16, "(null)"); } } return str; }
static int javasm_init(RBinJavaObj *bin) { unsigned short sz, sz2; char buf[0x4096]; int i, j; /* Initialize structs */ bin->cp_items = NULL; bin->fields = NULL; bin->methods = NULL; /* Initialize cp_null_item */ cp_null_item.tag = -1; strncpy (cp_null_item.name, "(null)", sizeof (cp_null_item.name)-1); cp_null_item.value = strdup ("(null)"); /* start parsing */ r_buf_read_at (bin->b, R_BUF_CUR, (ut8*)&bin->cf, 10); //sizeof(struct r_bin_java_classfile_t), 1, bin->fd); if (memcmp (bin->cf.cafebabe, "\xCA\xFE\xBA\xBE", 4)) { eprintf ("javasm_init: Invalid header (%02x %02x %02x %02x)\n", bin->cf.cafebabe[0], bin->cf.cafebabe[1], bin->cf.cafebabe[2], bin->cf.cafebabe[3]); return R_FALSE; } bin->cf.cp_count = R_BIN_JAVA_SWAPUSHORT (bin->cf.cp_count); if (bin->cf.major[0]==bin->cf.major[1] && bin->cf.major[0]==0) { fprintf(stderr, "This is a MachO\n"); return R_FALSE; } bin->cf.cp_count--; IFDBG printf ("ConstantPoolCount %d\n", bin->cf.cp_count); bin->cp_items = malloc (sizeof (struct r_bin_java_cp_item_t)*(bin->cf.cp_count+1)); eprintf ("%d\n", bin->cf.cp_count); for(i=0;i<bin->cf.cp_count;i++) { struct constant_t *c; r_buf_read_at (bin->b, R_BUF_CUR, (ut8*)buf, 1); c = NULL; for (j=0; constants[j].name; j++) { if (constants[j].tag == buf[0]) { c = &constants[j]; break; } } if (c == NULL) { fprintf (stderr, "Invalid tag '%d' at offset 0x%08"PFMT64x"\n", *buf, (ut64)bin->b->cur); return R_FALSE; } IFDBG printf (" %3d %s: ", i+1, c->name); /* store constant pool item */ strncpy (bin->cp_items[i].name, c->name, sizeof (bin->cp_items[i].name)-1); bin->cp_items[i].ord = i+1; bin->cp_items[i].tag = c->tag; bin->cp_items[i].value = NULL; // no string by default bin->cp_items[i].off = bin->b->cur-1; /* read bytes */ switch (c->tag) { case 1: // Utf8 string r_buf_read_at (bin->b, R_BUF_CUR, (ut8*)buf, 2); sz = R_BIN_JAVA_USHORT (buf, 0); bin->cp_items[i].length = sz; bin->cp_items[i].off += 3; if (sz<sizeof (buf)) { r_buf_read_at (bin->b, R_BUF_CUR, (ut8*)buf, sz); buf[sz] = '\0'; } else { eprintf ("Invalid utf8 length %d\n", sz); buf[0] = 0; } break; default: r_buf_read_at (bin->b, R_BUF_CUR, (ut8*)buf, c->len); } memcpy (bin->cp_items[i].bytes, buf, 5); /* parse value */ switch (c->tag) { case 1: // eprintf ("%s\n", buf); bin->cp_items[i].value = strdup (buf); break; case 5: case 6: i += 2; break; case 7: IFDBG eprintf ("%d\n", R_BIN_JAVA_USHORT (buf,0)); break; case 8: IFDBG printf("string ptr %d\n", R_BIN_JAVA_USHORT(buf, 0)); break; case 9: case 11: case 10: // METHOD REF IFDBG printf("class = %d, ", R_BIN_JAVA_USHORT(buf,0)); IFDBG printf("name_type = %d\n", R_BIN_JAVA_USHORT(buf,2)); break; case 12: IFDBG printf("name = %d, ", R_BIN_JAVA_USHORT(buf,0)); IFDBG printf("descriptor = %d\n", R_BIN_JAVA_USHORT(buf,2)); break; default: printf ("%d\n", R_BIN_JAVA_UINT (buf, 40)); } } r_buf_read_at (bin->b, R_BUF_CUR, (ut8*)&bin->cf2, sizeof(struct r_bin_java_classfile2_t)); IFDBG printf ("Access flags: 0x%04x\n", bin->cf2.access_flags); bin->cf2.this_class = R_BIN_JAVA_SWAPUSHORT(bin->cf2.this_class); IFDBG printf ("This class: %d\n", bin->cf2.this_class); //printf("This class: %d (%s)\n", R_BIN_JAVA_SWAPUSHORT(bin->cf2.this_class), bin->cp_items[R_BIN_JAVA_SWAPUSHORT(bin->cf2.this_class)-1].value); // XXX this is a double pointer !!1 //printf("Super class: %d (%s)\n", R_BIN_JAVA_SWAPUSHORT(bin->cf2.super_class), bin->cp_items[R_BIN_JAVA_SWAPUSHORT(bin->cf2.super_class)-1].value); sz = read_short(bin); /* TODO: intefaces*/ IFDBG printf("Interfaces count: %d\n", sz); if (sz>0) { r_buf_read_at(bin->b, R_BUF_CUR, (ut8*)buf, sz*2); sz = read_short(bin); for(i=0;i<sz;i++) { fprintf(stderr, "Interfaces: TODO\n"); } } sz = read_short(bin); bin->fields_count = sz; IFDBG printf("Fields count: %d\n", sz); if (sz>0) { bin->fields = malloc (1+sz * sizeof(struct r_bin_java_fm_t)); for (i=0;i<sz;i++) { r_buf_read_at(bin->b, R_BUF_CUR, (ut8*)buf, 8); bin->fields[i].flags = R_BIN_JAVA_USHORT(buf, 0); IFDBG printf("%2d: Access Flags: %d\n", i, bin->fields[i].flags); bin->fields[i].name_idx = R_BIN_JAVA_USHORT(buf, 2); bin->fields[i].name = r_str_dup (NULL, (get_cp (bin, R_BIN_JAVA_USHORT(buf,2)-1))->value); IFDBG printf(" Name Index: %d (%s)\n", bin->fields[i].name_idx, bin->fields[i].name); bin->fields[i].descriptor_idx = R_BIN_JAVA_USHORT(buf, 4); bin->fields[i].descriptor = NULL; IFDBG printf(" Descriptor Index: %d\n", bin->fields[i].descriptor_idx); //, bin->cp_items[R_BIN_JAVA_USHORT(buf, 4)-1].value); sz2 = R_BIN_JAVA_USHORT(buf, 6); bin->fields[i].attr_count = sz2; IFDBG printf(" field Attributes Count: %d\n", sz2); if (sz2 > 0) { bin->fields[i].attributes = malloc(1+sz2 * sizeof(struct r_bin_java_attr_t)); for(j=0;j<sz2;j++) attributes_walk(bin, &bin->fields[i].attributes[j], sz2, 1); } } } sz = read_short(bin); bin->methods_count = sz; IFDBG printf("Methods count: %d\n", sz); if (sz>0) { bin->methods = malloc(sz * sizeof(struct r_bin_java_fm_t)); for (i=0;i<sz;i++) { r_buf_read_at(bin->b, R_BUF_CUR, (ut8*)buf, 8); bin->methods[i].flags = R_BIN_JAVA_USHORT(buf, 0); IFDBG printf("%2d: Access Flags: %d\n", i, bin->methods[i].flags); bin->methods[i].name_idx = R_BIN_JAVA_USHORT(buf, 2); #if OLD bin->methods[i].name = r_str_dup (NULL, (get_cp(bin, R_BIN_JAVA_USHORT(buf, 2)-1))->value); #else bin->methods[i].name = malloc (1024); // XXX: can null ptr here snprintf (bin->methods[i].name, 1023, "%s%s", (get_cp (bin, R_BIN_JAVA_USHORT (buf, 2)-1))->value, (get_cp (bin, R_BIN_JAVA_USHORT (buf, 2)))->value); #endif bin->midx = i; IFDBG printf(" Name Index: %d (%s)\n", bin->methods[i].name_idx, bin->methods[i].name); bin->methods[i].descriptor_idx = R_BIN_JAVA_USHORT (buf, 4); bin->methods[i].descriptor = r_str_dup (NULL, (get_cp(bin, R_BIN_JAVA_USHORT(buf, 4)-1))->value); IFDBG printf(" Descriptor Index: %d (%s)\n", bin->methods[i].descriptor_idx, bin->methods[i].descriptor); sz2 = R_BIN_JAVA_USHORT(buf, 6); bin->methods[i].attr_count = sz2; IFDBG printf(" method Attributes Count: %d\n", sz2); if (sz2 > 0) { bin->methods[i].attributes = malloc (1+sz2 * sizeof (struct r_bin_java_attr_t)); for (j=0; j<sz2; j++) { if (!attributes_walk (bin, &bin->methods[i].attributes[j], sz2, 0)) return R_FALSE; } } } } return R_TRUE; }