diff --git a/libr/anal/hint.c b/libr/anal/hint.c index 614e765078..0b09ed9182 100644 --- a/libr/anal/hint.c +++ b/libr/anal/hint.c @@ -55,6 +55,9 @@ static void setHint(RAnal *a, const char *type, ut64 addr, const char *s, ut64 p } } +R_API void r_anal_hint_set_offset(RAnal *a, ut64 addr, const char* typeoff) { + setHint (a, "Offset:", addr, r_str_trim_const (typeoff), 0); +} R_API void r_anal_hint_set_jump(RAnal *a, ut64 addr, ut64 ptr) { setHint (a, "jump:", addr, NULL, ptr); } @@ -112,6 +115,9 @@ R_API void r_anal_hint_unset_syntax(RAnal *a, ut64 addr) { R_API void r_anal_hint_unset_pointer(RAnal *a, ut64 addr) { unsetHint(a, "ptr:", addr); } +R_API void r_anal_hint_unset_offset(RAnal *a, ut64 addr) { + unsetHint (a, "Offset:", addr); +} R_API void r_anal_hint_unset_jump(RAnal *a, ut64 addr) { unsetHint (a, "jump:", addr); } @@ -125,6 +131,7 @@ R_API void r_anal_hint_free(RAnalHint *h) { free (h->esil); free (h->opcode); free (h->syntax); + free (h->offset); free (h); } } @@ -162,6 +169,7 @@ R_API RAnalHint *r_anal_hint_from_string(RAnal *a, ut64 addr, const char *str) { case 's': hint->size = sdb_atoi (nxt); break; case 'S': hint->syntax = (char*)sdb_decode (nxt, 0); break; case 'o': hint->opcode = (char*)sdb_decode (nxt, 0); break; + case 'O': hint->offset = (char*)sdb_decode (nxt, 0); break; case 'e': hint->esil = (char*)sdb_decode (nxt, 0); break; case 'a': hint->arch = (char*)sdb_decode (nxt, 0); break; } diff --git a/libr/anal/p/anal_x86_cs.c b/libr/anal/p/anal_x86_cs.c index 8f48203942..f8ecc8be5e 100644 --- a/libr/anal/p/anal_x86_cs.c +++ b/libr/anal/p/anal_x86_cs.c @@ -1931,6 +1931,8 @@ static void anop(RAnal *a, RAnalOp *op, ut64 addr, const ut8 *buf, int len, csh // number of bits shifted is greater than the size of the // destination. op->type = R_ANAL_OP_TYPE_SHL; + op->src[0] = r_anal_value_new (); + op->src[0]->imm = INSOP(1).imm; break; case X86_INS_SAR: case X86_INS_SARX: @@ -1949,6 +1951,8 @@ static void anop(RAnal *a, RAnalOp *op, ut64 addr, const ut8 *buf, int len, csh case X86_INS_SHRX: // TODO: Set CF: See case X86_INS_SAL for more details. op->type = R_ANAL_OP_TYPE_SHR; + op->src[0] = r_anal_value_new (); + op->src[0]->imm = INSOP(1).imm; break; case X86_INS_CMP: case X86_INS_CMPPD: diff --git a/libr/anal/types.c b/libr/anal/types.c index df43c10ddb..7d413ab320 100644 --- a/libr/anal/types.c +++ b/libr/anal/types.c @@ -119,6 +119,74 @@ R_API int r_anal_type_get_size(RAnal *anal, const char *type) { return 0; } +// FIXME: Make it recursive +static int get_types_by_offset(RAnal *anal, RList *offtypes, int offset, const char *k, const char *v) { + char buf[256] = {0}; + //r_cons_printf ("tk %s=%s\n", k, v); + // TODO: Add unions support + if (!strncmp (v, "struct", 6) && strncmp (k, "struct.", 7)) { + const char *typename = k; + int typesize = 0; + char* query = sdb_fmt (-1, "struct.%s", k); + char *members = sdb_get (anal->sdb_types, query, 0); + char *next, *ptr = members; + if (members) { + // Search for members, summarize the size + int typesize = 0; + do { + char *name = sdb_anext (ptr, &next); + if (!name) { + break; + } + query = sdb_fmt (-1, "struct.%s.%s", k, name); + char *subtype = sdb_get (anal->sdb_types, query, 0); + if (!subtype) { + break; + } + char *tmp = strchr (subtype, ','); + if (tmp) { + *tmp++ = 0; + tmp = strchr (tmp, ','); + if (tmp) { + *tmp++ = 0; + } + char *subname = tmp; + // TODO: Go recurse here + int elements = r_num_math (NULL, tmp); + if (elements == 0) { + elements = 1; + } + // TODO: Handle also alignment, unions, etc + // If previous types size matches the offset + if ((typesize / 8) == offset) { + // Add them in the list + buf[0] = '\0'; + sprintf (buf, "%s.%s", k, name); + r_list_append (offtypes, strdup (buf)); + } + typesize += r_anal_type_get_size (anal, subtype) * elements; + } + free (subtype); + ptr = next; + } while (next); + free (members); + } + } + return 0; +} + +R_API RList* r_anal_type_get_by_offset(RAnal *anal, ut64 offset) { + RList *offtypes = r_list_new (); + SdbList *ls = sdb_foreach_list (anal->sdb_types, true); + SdbListIter *lsi; + SdbKv *kv; + ls_foreach (ls, lsi, kv) { + get_types_by_offset (anal, offtypes, offset, kv->key, kv->value); + } + ls_free (ls); + return offtypes; +} + R_API char* r_anal_type_to_str (RAnal *a, const char *type) { // convert to C text... maybe that should be in format string.. return NULL; @@ -146,6 +214,17 @@ R_API int r_anal_type_link(RAnal *anal, const char *type, ut64 addr) { return false; } +R_API int r_anal_type_link_offset(RAnal *anal, const char *type, ut64 addr) { + if (sdb_const_get (anal->sdb_types, type, 0)) { + char *laddr = r_str_newf ("offset.%08"PFMT64x, addr); + sdb_set (anal->sdb_types, laddr, type, 0); + free (laddr); + return true; + } + // eprintf ("Cannot find type\n"); + return false; +} + R_API int r_anal_type_unlink(RAnal *anal, ut64 addr) { char *laddr = sdb_fmt (-1, "link.%08"PFMT64x, addr); sdb_unset (anal->sdb_types, laddr, 0); diff --git a/libr/core/cmd_type.c b/libr/core/cmd_type.c index 979c8d7875..aa1e2256a5 100644 --- a/libr/core/cmd_type.c +++ b/libr/core/cmd_type.c @@ -14,6 +14,7 @@ static const char *help_msg_t[] = { "t-", " ", "Delete types by its name", "t-*", "", "Remove all types", //"t-!", "", "Use to open $EDITOR", + "ta", " ", "Mark immediate as a type offset", "tb", " ", "Show matching enum bitfield for given number", "tc", " ([cctype])", "calling conventions listing and manipulations", "te", "[?]", "List all loaded enums", @@ -39,6 +40,14 @@ static const char *help_msg_t_minus[] = { NULL }; +static const char *help_msg_ta[] = { + "USAGE ta[...]", "", "", + "tas", " ", "List all matching structure offsets", + "ta", " ", "Change immediate to structure offset", + "ta?", "", "show this help", + NULL +}; + static const char *help_msg_tc[] = { "USAGE tc[...]", " [cctype]", "", "tc", "", "List all loaded structs", @@ -107,6 +116,7 @@ static const char *help_msg_tu[] = { static void cmd_type_init(RCore *core) { DEFINE_CMD_DESCRIPTOR (core, t); DEFINE_CMD_DESCRIPTOR_SPECIAL (core, t-, t_minus); + DEFINE_CMD_DESCRIPTOR (core, ta); DEFINE_CMD_DESCRIPTOR (core, tc); DEFINE_CMD_DESCRIPTOR (core, td); DEFINE_CMD_DESCRIPTOR (core, te); @@ -559,6 +569,85 @@ static int cmd_type(void *data, const char *input) { eprintf ("Invalid use of td. See td? for help\n"); } break; + // ta - link immediate type offset to an address + case 'a': // "ta" + switch (input[1]) { + case 's': { + char *off = strdup (input + 2); + r_str_chop (off); + int toff = r_num_math (NULL, off); + if (toff) { + RList *typeoffs = r_anal_type_get_by_offset (core->anal, toff); + RListIter *iter; + char *ty; + r_list_foreach (typeoffs, iter, ty) { + r_cons_printf ("%s\n", ty); + } + } + break; + } + case ' ': { + char *type = strdup (input + 2); + char *ptr = strchr (type, '='); + ut64 offimm = 0; + int i = 0; + ut64 addr; + + if (ptr) { + *ptr++ = 0; + r_str_chop (ptr); + if (ptr && *ptr) { + addr = r_num_math (core->num, ptr); + } else { + eprintf ("address is unvalid\n"); + free (type); + break; + } + } else { + addr = core->offset; + } + r_str_chop (type); + RAsmOp asmop; + RAnalOp op; + ut8 code[128] = {0}; + (void)r_io_read_at (core->io, core->offset, code, sizeof (code)); + r_asm_set_pc (core->assembler, addr); + int ret = r_asm_disassemble (core->assembler, &asmop, code, core->blocksize); + ret = r_anal_op (core->anal, &op, core->offset, code, core->blocksize); + if (ret >= 0) { + // HACK: Just convert only the first imm seen + for (i = 0; i < 3; i++) { + if (op.src[i] && op.src[i]->imm) { + offimm = op.src[i]->imm; + //eprintf ("imm = %d\n", offimm); + } + } + if (offimm != 0) { + // TODO: Allow to select from multiple choices + RList* otypes = r_anal_type_get_by_offset (core->anal, offimm); + RListIter *iter; + char *otype = NULL; + r_list_foreach (otypes, iter, otype) { + if (!strcmp(type, otype)) { + //eprintf ("Adding type offset %s\n", type); + r_anal_type_link_offset (core->anal, type, addr); + r_anal_hint_set_offset (core->anal, addr, otype); + break; + } + } + if (!otype) { + eprintf ("wrong type for opcode offset\n"); + } + } + } + free (type); + } + break; + case '?': + r_core_cmd_help (core, help_msg_ta); + break; + } + break; // tl - link a type to an address case 'l': // "tl" switch (input[1]) { diff --git a/libr/include/r_anal.h b/libr/include/r_anal.h index 33ab348d41..c3568218ee 100644 --- a/libr/include/r_anal.h +++ b/libr/include/r_anal.h @@ -677,6 +677,7 @@ typedef struct r_anal_hint_t { char *opcode; char *syntax; char *esil; + char *offset; int size; int bits; int immbase; @@ -1182,6 +1183,7 @@ R_API RAnalFunction *r_listrange_find_root(RListRange* s, ut64 addr); /* --------- */ /* REFACTOR */ /* ---------- */ /* type.c */ R_API int r_anal_type_get_size (RAnal *anal, const char *type); +R_API RList* r_anal_type_get_by_offset(RAnal *anal, ut64 offset); R_API RAnalType *r_anal_type_new(void); R_API void r_anal_type_add(RAnal *l, RAnalType *t); R_API void r_anal_type_del(RAnal *l, const char *name); @@ -1201,6 +1203,7 @@ R_API void r_anal_type_header (RAnal *anal, const char *hdr); R_API int r_anal_type_link (RAnal *anal, const char *val, ut64 addr); R_API int r_anal_type_unlink(RAnal *anal, ut64 addr); +R_API int r_anal_type_link_offset (RAnal *anal, const char *val, ut64 addr); R_API char *r_anal_type_format (RAnal *anal, const char *t); R_API int r_anal_type_set(RAnal *anal, ut64 at, const char *field, ut64 val); R_API int r_anal_type_func_exist(RAnal *anal, const char *func_name); @@ -1547,6 +1550,7 @@ R_API void r_anal_hint_free (RAnalHint *h); R_API RAnalHint *r_anal_hint_get(RAnal *anal, ut64 addr); R_API void r_anal_hint_set_syntax (RAnal *a, ut64 addr, const char *syn); R_API void r_anal_hint_set_jump (RAnal *a, ut64 addr, ut64 ptr); +R_API void r_anal_hint_set_offset (RAnal *a, ut64 addr, const char *typeoff); R_API void r_anal_hint_set_immbase (RAnal *a, ut64 addr, int base); R_API void r_anal_hint_set_fail (RAnal *a, ut64 addr, ut64 ptr); R_API void r_anal_hint_set_length (RAnal *a, ut64 addr, int length); @@ -1563,6 +1567,7 @@ R_API void r_anal_hint_unset_opcode(RAnal *a, ut64 addr); R_API void r_anal_hint_unset_arch(RAnal *a, ut64 addr); R_API void r_anal_hint_unset_syntax(RAnal *a, ut64 addr); R_API void r_anal_hint_unset_pointer(RAnal *a, ut64 addr); +R_API void r_anal_hint_unset_offset(RAnal *a, ut64 addr); R_API void r_anal_hint_unset_jump(RAnal *a, ut64 addr); R_API void r_anal_hint_unset_fail(RAnal *a, ut64 addr); R_API int r_anal_esil_eval(RAnal *anal, const char *str); diff --git a/libr/parse/parse.c b/libr/parse/parse.c index bd9e7f642a..a4446539ea 100644 --- a/libr/parse/parse.c +++ b/libr/parse/parse.c @@ -328,9 +328,14 @@ static int filter(RParse *p, RFlag *f, char *data, char *str, int len, bool big_ } if (p->hint) { int pnumleft, immbase = p->hint->immbase; - char num[256], *pnum, *tmp; + char num[256] = {0}, *pnum, *tmp; bool is_hex = false; int tmp_count; + if (p->hint->offset) { + *ptr = 0; + snprintf (str, len, "%s%s%s", data, p->hint->offset, (ptr != ptr2)? ptr2: ""); + return true; + } strncpy (num, ptr, sizeof (num)-2); pnum = num; if (!strncmp (pnum, "0x", 2)) {