mirror of
https://github.com/radareorg/radare2.git
synced 2025-02-05 13:06:52 +00:00
Adding java command to help identify external calls, reads, and writes
This commit is contained in:
parent
b4f1cd220f
commit
d876dec7ee
@ -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];
|
||||
|
@ -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 = {
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user