Adding java command to help identify external calls, reads, and writes

This commit is contained in:
Adam Pridgen 2014-04-02 17:02:03 -05:00
parent b4f1cd220f
commit d876dec7ee
6 changed files with 167 additions and 24 deletions

View File

@ -483,7 +483,6 @@ static int java_print_ssa_fcn (RAnal *anal, char *addrs) {
return 0;
}
static int analyze_from_code_buffer ( RAnal *anal, RAnalFunction *fcn, ut64 addr, const ut8 *code_buf, ut64 code_length ) {
char gen_name[1025];

View File

@ -112,6 +112,7 @@ static const char * r_cmd_get_next_classname_str (const char * str, const char *
static int r_cmd_java_handle_summary_info (RCore *core, const char *cmd);
static int r_cmd_java_handle_reload_bin (RCore *core, const char *cmd);
static int r_cmd_java_handle_list_code_references (RCore *core, const char *cmd);
typedef struct r_cmd_java_cms_t {
const char *name;
@ -196,6 +197,11 @@ typedef struct r_cmd_java_cms_t {
#define SUMMARY_INFO_DESC "print summary information for the current java class file"
#define SUMMARY_INFO_LEN 7
#define LIST_CODE_REFS "lcr"
#define LIST_CODE_REFS_ARGS "NONE"
#define LIST_CODE_REFS_DESC "list all references to fields and methods in code sections"
#define LIST_CODE_REFS_LEN 3
static RCmdJavaCmd JAVA_CMDS[] = {
@ -214,6 +220,7 @@ static RCmdJavaCmd JAVA_CMDS[] = {
{REPLACE_CLASS_NAME, REPLACE_CLASS_NAME_ARGS, REPLACE_CLASS_NAME_DESC, REPLACE_CLASS_NAME_LEN, r_cmd_java_handle_replace_classname_value},
{RELOAD_BIN, RELOAD_BIN_ARGS, RELOAD_BIN_DESC, RELOAD_BIN_LEN, r_cmd_java_handle_reload_bin},
{SUMMARY_INFO, SUMMARY_INFO_ARGS, SUMMARY_INFO_DESC, REPLACE_CLASS_NAME_LEN, r_cmd_java_handle_summary_info},
{LIST_CODE_REFS, LIST_CODE_REFS_ARGS, LIST_CODE_REFS_DESC, REPLACE_CLASS_NAME_LEN, r_cmd_java_handle_list_code_references},
};
enum {
@ -232,7 +239,8 @@ enum {
REPLACE_CLASS_NAME_IDX = 12,
RELOAD_BIN_IDX = 13,
SUMMARY_INFO_IDX = 14,
END_CMDS = 15,
LIST_CODE_REFS_IDX = 15,
END_CMDS = 16,
};
static ut8 r_cmd_java_obj_ref (const char *name, const char *class_name, ut32 len) {
@ -1076,6 +1084,7 @@ static int r_cmd_java_handle_flags_str_at (RCore *core, const char *cmd) {
return res;
}
static char r_cmd_java_is_valid_java_mcf (char b) {
char c = 0;
switch (b) {
@ -1468,6 +1477,96 @@ static int r_cmd_java_print_method_name (RBinJavaObj *obj, ut16 idx) {
return R_TRUE;
}
static int r_cmd_java_handle_list_code_references (RCore *core, const char *input) {
RAnal *anal = get_anal (core);
RBinJavaObj *bin = (RBinJavaObj *) r_cmd_java_get_bin_obj (anal);
RAnalBlock *bb = NULL;
RAnalFunction *fcn = NULL;
RListIter *bb_iter = NULL, *fcn_iter = NULL;
if (!bin) return R_FALSE;
const char *fmt = "0x%"PFMT64x" %s type: %s class: %s name: %s desc: %s\n";
r_list_foreach (anal->fcns, fcn_iter, fcn) {
r_list_foreach (fcn->bbs, bb_iter, bb) {
const char *operation = NULL, *type = NULL;
ut64 addr = -1;
ut16 class_idx = -1, name_and_type_idx = -1;
char *class_name = NULL, name = NULL, descriptor = NULL;
// if bb_type is a call
if (bb->type2 & R_ANAL_EX_CODEOP_CALL == R_ANAL_EX_CODEOP_CALL) {
ut8 op_byte = bb->op_bytes[0];
// look at the bytes determine if it belongs to this class
switch (op_byte) {
case 0xb6: // invokevirtual
operation = "call virtual";
type = "function";
addr = bb->addr;
break;
case 0xb7: // invokespecial
operation = "call special";
type = "function";
addr = bb->addr;
break;
case 0xb8: // invokestatic
operation = "call static";
type = "function";
addr = bb->addr;
break;
case 0xb9: // invokeinterface
operation = "call special";
type = "function";
addr = bb->addr;
break;
case 0xba: // invokedynamic
operation = "call special";
type = "function";
addr = bb->addr;
break;
default:
operation = NULL;
addr = -1;
break;
}
} else if (bb->type2 & R_ANAL_EX_LDST_LOAD_GET_STATIC == R_ANAL_EX_LDST_LOAD_GET_STATIC) {
operation = "read static";
type = "field";
addr = bb->addr;
} else if (bb->type2 & R_ANAL_EX_LDST_LOAD_GET_FIELD == R_ANAL_EX_LDST_LOAD_GET_FIELD) {
operation = "read dynamic";
type = "field";
addr = bb->addr;
} else if (bb->type2 & R_ANAL_EX_LDST_STORE_PUT_STATIC == R_ANAL_EX_LDST_STORE_PUT_STATIC) {
operation = "write static";
type = "field";
addr = bb->addr;
} else if (bb->type2 & R_ANAL_EX_LDST_STORE_PUT_FIELD == R_ANAL_EX_LDST_STORE_PUT_FIELD) {
operation = "write dynamic";
type = "field";
addr = bb->addr;
}
if (operation && addr != -1) {
class_idx = R_BIN_JAVA_USHORT (bb->op_bytes, 1);
name_and_type_idx = R_BIN_JAVA_USHORT (bb->op_bytes, 3);
r_bin_add_import_from_anal (bin, class_idx, name_and_type_idx, type);
class_name = r_bin_java_get_name_from_bin_cp_list (bin, class_idx);
name = r_bin_java_get_item_name_from_bin_cp_list (bin, name_and_type_idx);
descriptor = r_bin_java_get_item_desc_from_bin_cp_list (bin, name_and_type_idx);
r_cons_printf (fmt, addr, operation, type, class_name, name, descriptor);
free (class_name);
free (name);
free (descriptor);
}
}
}
return R_TRUE;
}
// PLUGIN Definition Info
RCorePlugin r_core_plugin_java = {

View File

@ -227,7 +227,8 @@ typedef struct r_bin_symbol_t {
char bind[R_BIN_SIZEOF_STRINGS];
char type[R_BIN_SIZEOF_STRINGS];
char visibility_str[R_BIN_SIZEOF_STRINGS];
const char *classname;
char classname[R_BIN_SIZEOF_STRINGS];
char descriptor[R_BIN_SIZEOF_STRINGS];
ut64 rva;
ut64 offset;
ut64 size;
@ -239,6 +240,8 @@ typedef struct r_bin_import_t {
char name[R_BIN_SIZEOF_STRINGS];
char bind[R_BIN_SIZEOF_STRINGS];
char type[R_BIN_SIZEOF_STRINGS];
char classname[R_BIN_SIZEOF_STRINGS];
char descriptor[R_BIN_SIZEOF_STRINGS];
ut64 ordinal;
ut32 visibility;
} RBinImport;

View File

@ -622,6 +622,8 @@ static void r_bin_java_reset_bin_info (RBinJavaObj *bin) {
bin->entrypoint = NULL;
bin->entrypoint_code_attr = NULL;
r_list_free (bin->imports_list);
r_bin_java_fields_list_free (bin);
r_bin_java_methods_list_free (bin);
r_bin_java_constant_pool_list_free (bin);
@ -2533,8 +2535,6 @@ static int r_bin_java_new_bin (RBinJavaObj *bin, ut64 loadaddr, Sdb *kv, const u
bin->lines.count = 0;
bin->loadaddr = loadaddr;
r_bin_java_get_java_null_cp ();
bin->cp_list = bin->interfaces_list = NULL;
bin->attrs_list = NULL;
bin->id = r_num_rand (UT32_MAX);
bin->kv = kv ? kv : sdb_new(NULL, NULL, 0);
bin->AllJavaBinObjs = NULL;
@ -2545,7 +2545,9 @@ R_API int r_bin_java_load_bin (RBinJavaObj *bin, const ut8 * buf, ut64 buf_sz) {
ut64 adv = 0;
R_BIN_JAVA_GLOBAL_BIN = bin;
if (!bin) return R_FALSE;
r_bin_java_reset_bin_info (bin);
memcpy ((ut8* ) &bin->cf, buf, 10);
if (memcmp (bin->cf.cafebabe, "\xCA\xFE\xBA\xBE", 4)) {
eprintf ("r_bin_java_new_bin: Invalid header (%02x %02x %02x %02x)\n",
@ -2572,6 +2574,8 @@ R_API int r_bin_java_load_bin (RBinJavaObj *bin, const ut8 * buf, ut64 buf_sz) {
adv += r_bin_java_parse_methods (bin, adv, buf, buf_sz);
adv += r_bin_java_parse_attrs (bin, adv, buf, buf_sz);
// imports require accessing a the specific method
bin->imports_list = r_list_newf (free);
//add_cp_objs_to_sdb(bin);
//add_method_infos_to_sdb(bin);
//add_field_infos_to_sdb(bin);
@ -2783,9 +2787,9 @@ R_API RBinSymbol* r_bin_java_create_new_symbol_from_field(RBinJavaField *fm_type
}
strncpy (sym->forwarder, "NONE", R_BIN_SIZEOF_STRINGS);
if (fm_type->class_name) {
sym->classname = strdup (fm_type->class_name);
strncpy (sym->classname, fm_type->class_name, R_BIN_SIZEOF_STRINGS);
} else {
sym->classname = NULL;//strdup ("NONE");
strncpy (sym->classname, "UNKNOWN", R_BIN_SIZEOF_STRINGS);
}
sym->ordinal = fm_type->metas->ord;
@ -2821,9 +2825,9 @@ R_API RBinSymbol* r_bin_java_create_new_symbol_from_method_meta(RBinJavaField *f
strncpy (sym->forwarder, "NONE", R_BIN_SIZEOF_STRINGS);
if (fm_type->class_name) {
sym->classname = strdup (fm_type->class_name);
strncpy (sym->bind, fm_type->class_name, R_BIN_SIZEOF_STRINGS);
} else {
sym->classname = NULL;//strdup ("NONE");
strncpy (sym->bind, "UNKNOWN", R_BIN_SIZEOF_STRINGS);
}
sym->offset = fm_type->file_offset;//r_bin_java_get_method_code_offset (fm_type);
@ -2868,7 +2872,7 @@ R_API RBinSymbol* r_bin_java_create_new_symbol_from_ref(RBinJavaCPTypeObj *obj,
type_name = NULL;
}
if (class_name)
sym->classname = class_name;
strncpy (sym->classname, class_name, R_BIN_SIZEOF_STRINGS);
sym->offset = obj->file_offset + baddr;
sym->rva = obj->file_offset + baddr;
@ -3135,6 +3139,35 @@ R_API const RList* r_bin_java_get_methods_list(RBinJavaObj* bin) {
R_API void r_bin_add_import_from_anal (RBinJavaObj * bin, ut16 class_idx, ut16 name_type_idx, const char * type) {
RBinImport * import = R_NEW0(RBinImport);
char *class_name = r_bin_java_get_name_from_bin_cp_list (bin, class_idx);
char *name = r_bin_java_get_item_name_from_bin_cp_list (bin, name_type_idx);
char *descriptor = r_bin_java_get_item_desc_from_bin_cp_list (bin, name_type_idx);
strncpy (import->classname, class_name, R_BIN_SIZEOF_STRINGS);
strncpy (import->name, name, R_BIN_SIZEOF_STRINGS);
strncpy (import->bind, "NONE", R_BIN_SIZEOF_STRINGS);
strncpy (import->type, type, R_BIN_SIZEOF_STRINGS);
strncpy (import->descriptor, descriptor, R_BIN_SIZEOF_STRINGS);
r_list_append (bin->imports_list, import);
}
RList* r_bin_java_get_imports(RBinJavaObj* bin) {
RList *ret = r_list_new ();
RBinImport *import = NULL;
RListIter *iter;
ret->free = free;
r_list_foreach (bin->imports_list, iter, import) {
RBinImport *n_import = R_NEW0(RBinImport);
memcpy (n_import, import, sizeof (RBinImport));
r_list_append (ret, n_import);
}
return ret;
}
RList* r_bin_java_get_symbols(RBinJavaObj* bin) {
RListIter *iter = NULL, *iter_tmp=NULL;
RList *symbols = r_list_new ();
@ -3190,7 +3223,7 @@ R_API void* r_bin_java_free (RBinJavaObj* bin) {
//}
free (bin_obj_key);
r_list_free (bin->imports_list);
// XXX - Need to remove all keys belonging to this class from
// the share meta information sdb.
// TODO e.g. iterate over bin->kv and delete all obj, func, etc. keys

View File

@ -734,6 +734,7 @@ typedef struct r_bin_java_obj_t {
RList* cp_list;
RList* interfaces_list;
RList* attrs_list;
RList* imports_list;
RList* functions;
RList* disassembly;
@ -1008,6 +1009,7 @@ R_API ut64 r_bin_java_parse_fields (RBinJavaObj *bin, const ut64 offset, const u
R_API ut64 r_bin_java_parse_methods (RBinJavaObj *bin, const ut64 offset, const ut8 * buf, const ut64 len);
R_API ut64 r_bin_java_parse_attrs (RBinJavaObj *bin, const ut64 offset, const ut8 * buf, const ut64 len);
R_API int r_bin_java_load_bin (RBinJavaObj *bin, const ut8 * buf, ut64 len);
R_API void r_bin_add_import_from_anal (RBinJavaObj * bin, ut16 class_idx, ut16 name_type_idx, const char * type);

View File

@ -17,7 +17,8 @@
#define IFDBG if(0)
static void init_switch_op ();
static int enter_switch_op (ut64 addr, const ut8 * bytes, char *output, int outlen );
static int enter_switch_op (ut64 addr, const ut8 * bytes);
static int update_switch_op (ut64 addr, const ut8 * bytes);
static int update_bytes_consumed (int sz);
static int handle_switch_op (ut64 addr, const ut8 * bytes, char *output, int outlen );
@ -38,7 +39,7 @@ static void init_switch_op () {
memset (&SWITCH_OP, 0, sizeof(SWITCH_OP));
}
static int enter_switch_op (ut64 addr, const ut8 * bytes, char *output, int outlen ) {
static int enter_switch_op (ut64 addr, const ut8 * bytes ) {
ut8 idx = bytes[0];
IN_SWITCH_OP = 1;
ut8 sz = (BYTES_CONSUMED+1) % 4 ? 1 + 4 - (BYTES_CONSUMED+1) % 4: 1; // + (BYTES_CONSUMED+1) % 4;
@ -51,9 +52,7 @@ static int enter_switch_op (ut64 addr, const ut8 * bytes, char *output, int outl
SWITCH_OP.min_val = (int)(UINT (bytes, sz + 4));
SWITCH_OP.max_val = (int)(UINT (bytes, sz + 8));
sz += 12;
snprintf (output, outlen, "%s default: 0x%04"PFMT64x, JAVA_OPS[idx].name,
SWITCH_OP.def_jmp+SWITCH_OP.addr);
return update_bytes_consumed(sz);
return sz;
}
static int update_bytes_consumed (int sz) {
@ -61,22 +60,27 @@ static int update_bytes_consumed (int sz) {
return sz;
}
static int update_switch_op (ut64 addr, const ut8 * bytes) {
int sz = 4;
int ccase = SWITCH_OP.cur_val + SWITCH_OP.min_val;
SWITCH_OP.cur_val++;
if ( ccase+1 > SWITCH_OP.max_val) IN_SWITCH_OP = 0;
return update_bytes_consumed(sz);
}
static int handle_switch_op (ut64 addr, const ut8 * bytes, char *output, int outlen ) {
int sz = 4;
ut32 jmp = (int)(UINT (bytes, 0)) + SWITCH_OP.addr;
int ccase = SWITCH_OP.cur_val + SWITCH_OP.min_val;
snprintf(output, outlen, "case %d: goto 0x%04x", ccase, jmp);
SWITCH_OP.cur_val++;
if ( ccase+1 > SWITCH_OP.max_val) IN_SWITCH_OP = 0;
update_switch_op (addr, bytes);
return update_bytes_consumed(sz);
}
R_IPI int java_print_opcode(RBinJavaObj *obj, ut64 addr, int idx, const ut8 *bytes, char *output, int outlen) {
char *arg = NULL; //(char *) malloc (1024);
int sz = 0;
ut32 val_one = 0,
val_two = 0;
@ -169,7 +173,10 @@ R_IPI int java_print_opcode(RBinJavaObj *obj, ut64 addr, int idx, const ut8 *byt
// XXX - Figure out what constitutes the [<high>] value
case 0xab: // tableswitch
case 0xaa: // tableswitch
return enter_switch_op (addr, bytes, output, outlen);
sz = enter_switch_op (addr, bytes);
snprintf (output, outlen, "%s default: 0x%04"PFMT64x, JAVA_OPS[idx].name,
SWITCH_OP.def_jmp+SWITCH_OP.addr);
return update_bytes_consumed (sz);
case 0xb6: // invokevirtual
case 0xb7: // invokespecial
case 0xb8: // invokestatic