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; }
int java_classdump(const char *file, int verbose) { RBinJavaClass2 cf2; unsigned short sz, sz2; int this_class; char buf[0x9999]; int i,j; FILE *fd = fopen(file, "rb"); if (fd == NULL) return -1; /* start parsing */ fread (&cf, 10, 1, fd); //sizeof(struct classfile), 1, fd); if (memcmp (cf.cafebabe, "\xCA\xFE\xBA\xBE", 4)) { eprintf ("java_classdump: Invalid header\n"); return -1; } javasm_init (); /* show class version information */ V printf ("Version: 0x%02x%02x 0x%02x%02x\n", cf.major[1],cf.major[0], cf.minor[1],cf.minor[0]); cf.cp_count = r_num_ntohs(cf.cp_count); if (cf.major[0]==cf.major[1] && cf.major[0]==0) { eprintf ("Oops. this is a Mach-O\n"); return 0; } cf.cp_count--; V printf ("ConstantPoolCount %d\n", cf.cp_count); cp_items = malloc (sizeof (struct cp_item)*(cf.cp_count+1)); for (i=0;i<cf.cp_count;i++) { struct constant_t *c; fread (buf, 1, 1, fd); c = NULL; for (j=0; r_bin_java_constants[j].name; j++) { if (r_bin_java_constants[j].tag == buf[0]) { c = &r_bin_java_constants[j]; break; } } if (c == NULL) { eprintf ("Invalid tag '%d'\n", buf[0]); return 0; } V eprintf (" %3d %s: ", i+1, c->name); /* store constant pool item */ strcpy (cp_items[i].name, c->name); cp_items[i].tag = c->tag; cp_items[i].value = NULL; // no string by default cp_items[i].off = ftell(fd)-1; /* read bytes */ switch (c->tag) { case 1: // utf 8 string fread (buf, 2, 1, fd); sz = USHORT (buf,0); //cp_items[i].len = sz; fread(buf, sz, 1, fd); buf[sz] = '\0'; break; default: fread(buf, c->len, 1, fd); } memcpy (cp_items[i].bytes, buf, 5); /* parse value */ switch(c->tag) { case 1: V printf ("%s\n", buf); cp_items[i].value = strdup(buf); break; case 7: V printf ("%d\n", USHORT(buf,0)); break; case 8: V printf ("string ptr %d\n", USHORT(buf, 0)); break; case 9: case 11: case 10: // METHOD REF V printf("class = %d, ", USHORT(buf,0)); V printf("name_type = %d\n", USHORT(buf,2)); break; case 12: V printf("name = %d, ", USHORT(buf,0)); V printf("descriptor = %d\n", USHORT(buf,2)); break; default: V printf("%d\n", UINT(buf, 40)); } } fread (&cf2, sizeof (RBinJavaClass2), 1, fd); check_eof(fd); V printf("Access flags: 0x%04x\n", cf2.access_flags); this_class = r_num_ntohs (cf2.this_class); V printf ("This class: %d\n", this_class); check_eof (fd); //printf("This class: %d (%s)\n", ntohs(cf2.this_class), cp_items[ntohs(cf2.this_class)-1].value); // XXX this is a double pointer !!1 //printf("Super class: %d (%s)\n", ntohs(cf2.super_class), cp_items[ntohs(cf2.super_class)-1].value); sz = read_short (fd); V printf ("Interfaces count: %d\n", sz); if (sz>0) { fread (buf, sz*2, 1, fd); sz = read_short (fd); for (i=0; i<sz; i++) { eprintf ("interfaces: TODO\n"); } } sz = read_short(fd); V printf("Fields count: %d\n", sz); if (sz>0) { for (i=0;i<sz;i++) { fread(buf, 8, 1, fd); V printf("%2d: Access Flags: %d\n", i, USHORT(buf, 0)); V printf(" Name Index: %d (%s)\n", USHORT(buf, 2), get_cp(USHORT(buf,2)-1)->value); V printf(" Descriptor Index: %d\n", USHORT(buf, 4)); //, cp_items[USHORT(buf, 4)-1].value); sz2 = USHORT(buf, 6); V printf(" field Attributes Count: %d\n", sz2); attributes_walk(fd, sz2, 1, verbose); } } sz = read_short(fd); V printf("Methods count: %d\n", sz); if (sz>0) { for (i=0;i<sz;i++) { fread(buf, 8, 1, fd); check_eof(fd); V printf("%2d: Access Flags: %d\n", i, USHORT(buf, 0)); V printf(" Name Index: %d (%s)\n", USHORT(buf, 2), get_cp(USHORT(buf, 2)-1)->value); V printf(" Descriptor Index: %d (%s)\n", USHORT(buf, 4), get_cp(USHORT(buf, 4)-1)->value); sz2 = USHORT(buf, 6); V printf(" method Attributes Count: %d\n", sz2); attributes_walk(fd, sz2, 0, verbose); } } fclose(fd); return 0; }
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; }
static int attributes_walk(FILE *fd, int sz2, int fields, int verbose) { char *name, buf[99999]; int sz, k, j=0; for (j=0;j<sz2;j++) { fread(buf, 6, 1, fd); name = (get_cp (USHORT(buf,0)-1))->value; V printf(" %2d: Name Index: %d (%s)\n", j, USHORT(buf,0), name); // TODO add comment with constant pool index if (fields) { V printf("FIELD\n"); } else { V printf (" Length: %d\n", UINT (buf, 2)); if (!name) { printf ("**ERROR ** Cannot identify attribute name into constant pool\n"); continue; } if (!strcmp (name, "Code")) { fread(buf, 8, 1, fd); V printf(" Max Stack: %d\n", USHORT(buf, 0)); V printf(" Max Locals: %d\n", USHORT(buf, 2)); V printf(" Code Length: %d\n", UINT(buf, 4)); V printf(" Code At Offset: 0x%08"PFMT64x"\n", (ut64)ftell(fd)); fread(buf, UINT(buf, 4), 1, fd); // READ CODE sz = read_short(fd); V printf(" Exception table length: %d\n", sz); for (k=0;k<sz;k++) { fread(buf, 8, 1, fd); V printf(" start_pc: 0x%04x\n", USHORT(buf,0)); V printf(" end_pc: 0x%04x\n", USHORT(buf,2)); V printf(" handler_pc: 0x%04x\n", USHORT(buf,4)); V printf(" catch_type: %d\n", USHORT(buf,6)); } sz = (int)read_short(fd); V printf(" code Attributes_count: %d\n", sz); if (sz>0) attributes_walk(fd, sz, fields, verbose); } else if (!strcmp(name, "LineNumberTable")) { sz = (int)read_short(fd); V printf(" Table Length: %d\n", sz); for(k=0;k<sz;k++) { fread(buf, 4, 1, fd); V printf(" %2d: start_pc: 0x%04x\n", k, USHORT(buf, 0)); V printf(" line_number: %d\n", USHORT(buf, 2)); } } else if (!strcmp(name, "StackMapTable")) { fread (buf, 2, 1, fd); V printf(" StackMapTable: %d\n", USHORT(buf, 0)); } else if (!strcmp (name, "LocalVariableTable")) { int i; ut32 lvtl = (ut32)read_short (fd); for (i=0; i<lvtl; i++) { int start_pc = start_pc = read_short (fd); int length = length = read_short (fd); int name_idx = name_idx = read_short (fd); int desc_idx = desc_idx = read_short (fd); int index = index = read_short (fd); } } else if (!strcmp(name, "ConstantValue")) { fread(buf, 2, 1, fd); #if 0 printf(" Name Index: %d\n", USHORT(buf, 0)); // %s\n", USHORT(buf, 0), cp_items[USHORT(buf,0)-1].value); printf(" AttributeLength: %d\n", UINT(buf, 2)); #endif V printf(" ConstValueIndex: %d\n", USHORT(buf, 0)); } else { fprintf (stderr, "** ERROR ** Unknown section '%s'\n", name); return 1; } } } return 0; }