Add ablc, ab-, Fix and optimize in af- and aafs ##analysis

* Add ablc, ab-, Fix and optimize in af- and aafs ##analysis

* delete dangling basic blocks after 'aafs' when using 'af-*'
* add test for aafs and ablc
* queue reanalysis on write, and mark detectwrite tests as broken
* function reanalisis tests in a separate file
This commit is contained in:
pancake 2022-01-12 12:07:26 +01:00 committed by GitHub
parent fdc1ba6d6d
commit fba739a1ee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 339 additions and 230 deletions

View File

@ -65,6 +65,7 @@ static RAnalBlock *block_new(RAnal *a, ut64 addr, ut64 size) {
return block;
}
#if 0
static void block_free(RAnalBlock *block) {
if (!block) {
return;
@ -79,10 +80,19 @@ static void block_free(RAnalBlock *block) {
free (block->parent_reg_arena);
free (block);
}
#endif
void __block_free_rb(RBNode *node, void *user) {
RAnalBlock *block = unwrap (node);
block_free (block);
r_anal_block_unref (block);
//block_free (block);
}
R_API void r_anal_block_reset(RAnal *a) {
if (a->bb_tree) {
r_rbtree_free (a->bb_tree, __block_free_rb, NULL);
a->bb_tree = NULL;
}
}
R_API RAnalBlock *r_anal_get_block_at(RAnal *anal, ut64 addr) {
@ -181,11 +191,23 @@ R_API RAnalBlock *r_anal_create_block(RAnal *anal, ut64 addr, ut64 size) {
return block;
}
R_API void r_anal_delete_block_at(RAnal *anal, ut64 addr) {
RAnalBlock *bb = r_anal_get_block_at (anal, addr);
if (bb) {
r_anal_delete_block (bb);
}
}
R_API void r_anal_delete_block(RAnalBlock *bb) {
r_anal_block_ref (bb);
while (!r_list_empty (bb->fcns)) {
r_anal_function_remove_block (r_list_first (bb->fcns), bb);
RListIter *iter, *iter2;
RAnalFunction *fcn;
r_list_foreach_safe (bb->fcns, iter, iter2, fcn) {
r_anal_function_remove_block (fcn, bb);
}
}
r_rbtree_aug_delete (&bb->anal->bb_tree, &bb->addr, __bb_addr_cmp, NULL, NULL, NULL, __max_end);
r_anal_block_unref (bb);
}
@ -371,13 +393,16 @@ R_API void r_anal_block_unref(RAnalBlock *bb) {
if (!bb) {
return;
}
if (bb->ref < 1) {
return;
}
r_return_if_fail (bb->ref > 0);
bb->ref--;
r_return_if_fail (bb->ref >= r_list_length (bb->fcns)); // all of the block's functions must hold a reference to it
// r_return_if_fail (bb->ref >= r_list_length (bb->fcns)); // all of the block's functions must hold a reference to it
if (bb->ref < 1) {
RAnal *anal = bb->anal;
r_return_if_fail (!bb->fcns || r_list_empty (bb->fcns));
r_rbtree_aug_delete (&anal->bb_tree, &bb->addr, __bb_addr_cmp, NULL, __block_free_rb, NULL, __max_end);
// r_return_if_fail (r_list_empty (bb->fcns));
}
}

View File

@ -1597,6 +1597,7 @@ R_API int r_anal_function_del_locs(RAnal *anal, ut64 addr) {
}
if (r_anal_function_contains (fcn, addr)) {
r_anal_function_delete (fcn);
break;
}
}
r_anal_function_del (anal, addr);
@ -1604,14 +1605,13 @@ R_API int r_anal_function_del_locs(RAnal *anal, ut64 addr) {
}
R_API int r_anal_function_del(RAnal *a, ut64 addr) {
RAnalFunction *fcn;
RListIter *iter, *iter_tmp;
r_list_foreach_safe (a->fcns, iter, iter_tmp, fcn) {
if (fcn->addr == addr) {
r_anal_function_delete (fcn);
}
RAnalFunction *fcn = r_anal_get_function_at (a, addr);
if (fcn) {
r_anal_function_delete (fcn);
// r_anal_function_free (fcn);
return true;
}
return true;
return false;
}
R_API RAnalFunction *r_anal_get_fcn_in(RAnal *anal, ut64 addr, int type) {
@ -2241,6 +2241,7 @@ static void clear_bb_vars(RAnalFunction *fcn, RAnalBlock *bb, ut64 from, ut64 to
}
static void update_analysis(RAnal *anal, RList *fcns, HtUP *reachable) {
// huge slowdown
RListIter *it, *it2, *tmp;
RAnalFunction *fcn;
bool old_jmpmid = anal->opt.jmpmid;

View File

@ -97,11 +97,13 @@ R_API void r_anal_function_free(RAnalFunction *fcn) {
}
RAnalBlock *block;
RListIter *iter;
r_list_foreach (fcn->bbs, iter, block) {
r_list_delete_data (block->fcns, fcn);
r_anal_block_unref (block);
RListIter *iter, *iter2;
r_list_foreach_safe (fcn->bbs, iter, iter2, block) {
r_anal_function_remove_block (fcn, block);
// r_list_delete_data (block->fcns, fcn);
//r_anal_block_unref (block);
}
// fcn->bbs->free = r_anal_block_unref;
r_list_free (fcn->bbs);
RAnal *anal = fcn->anal;

View File

@ -2206,7 +2206,9 @@ static void get_bbupdate(RAGraph *g, RCore *core, RAnalFunction *fcn) {
R_FREE (saved_arena);
return;
}
r_list_sort (fcn->bbs, (RListComparator) bbcmp);
if (fcn->bbs) {
r_list_sort (fcn->bbs, (RListComparator) bbcmp);
}
shortcuts = r_config_get_i (core->config, "graph.nodejmps");
r_list_foreach (fcn->bbs, iter, bb) {
@ -4300,7 +4302,11 @@ R_API int r_core_visual_graph(RCore *core, RAGraph *g, RAnalFunction *_fcn, int
exit_graph = true;
is_error = !ret;
}
get_bbupdate (g, core, fcn);
fcn = r_anal_get_fcn_in (core->anal, core->offset, 0);
if (fcn) {
get_bbupdate (g, core, fcn);
fcn = r_anal_get_fcn_in (core->anal, core->offset, 0);
}
core->cons->event_resize = NULL; // avoid running old event with new data
core->cons->event_data = grd;
@ -4397,7 +4403,10 @@ R_API int r_core_visual_graph(RCore *core, RAGraph *g, RAnalFunction *_fcn, int
r_config_set_i (core->config, "graph.edges", e);
g->edgemode = e;
g->need_update_dim = true;
get_bbupdate (g, core, fcn);
RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, core->offset, 0);
if (fcn) {
get_bbupdate (g, core, fcn);
}
}
break;
case '\\':
@ -4415,7 +4424,10 @@ R_API int r_core_visual_graph(RCore *core, RAGraph *g, RAnalFunction *_fcn, int
}
r_config_set_i (core->config, "graph.linemode", e);
g->can->linemode = e;
get_bbupdate (g, core, fcn);
RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, core->offset, 0);
if (fcn) {
get_bbupdate (g, core, fcn);
}
}
break;
case 13:
@ -4548,13 +4560,13 @@ R_API int r_core_visual_graph(RCore *core, RAGraph *g, RAnalFunction *_fcn, int
disMode = (disMode + 1) % 3;
applyDisMode (core);
g->need_reload_nodes = true;
get_bbupdate (g, core, fcn);
RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, core->offset, 0);
if (fcn) {
get_bbupdate (g, core, fcn);
}
break;
case 'u':
{
if (!fcn) {
break;
}
RIOUndos *undo = r_io_sundo (core->io, core->offset);
if (undo) {
r_core_seek (core, undo->off, false);
@ -4568,9 +4580,6 @@ R_API int r_core_visual_graph(RCore *core, RAGraph *g, RAnalFunction *_fcn, int
}
case 'U':
{
if (!fcn) {
break;
}
RIOUndos *undo = r_io_sundo_redo (core->io);
if (undo) {
r_core_seek (core, undo->off, false);
@ -4583,6 +4592,7 @@ R_API int r_core_visual_graph(RCore *core, RAGraph *g, RAnalFunction *_fcn, int
break;
}
case 'r':
fcn = r_anal_get_fcn_in (core->anal, core->offset, 0);
if (fcn) {
g->layout = r_config_get_i (core->config, "graph.layout");
g->need_reload_nodes = true;
@ -4605,11 +4615,11 @@ R_API int r_core_visual_graph(RCore *core, RAGraph *g, RAnalFunction *_fcn, int
} else {
r_core_cmd0 (core, "ecn");
}
if (!fcn) {
break;
}
g->edgemode = r_config_get_i (core->config, "graph.edges");
get_bbupdate (g, core, fcn);
fcn = r_anal_get_fcn_in (core->anal, core->offset, 0);
if (fcn) {
get_bbupdate (g, core, fcn);
}
break;
case '$':
r_core_cmd (core, "dr PC=$$", 0);
@ -4620,12 +4630,14 @@ R_API int r_core_visual_graph(RCore *core, RAGraph *g, RAnalFunction *_fcn, int
r_core_panels_root (core, core->panels_root);
break;
case '\'':
fcn = r_anal_get_fcn_in (core->anal, core->offset, 0);
if (fcn) {
r_config_toggle (core->config, "graph.comments");
g->need_reload_nodes = true;
}
break;
case ';':
fcn = r_anal_get_fcn_in (core->anal, core->offset, 0);
if (fcn) {
showcursor (core, true);
char buf[256];
@ -4653,12 +4665,14 @@ R_API int r_core_visual_graph(RCore *core, RAGraph *g, RAnalFunction *_fcn, int
}
break;
case '(':
fcn = r_anal_get_fcn_in (core->anal, core->offset, 0);
if (fcn) {
r_core_cmd0 (core, "wao recj@B:-1");
g->need_reload_nodes = true;
}
break;
case ')':
fcn = r_anal_get_fcn_in (core->anal, core->offset, 0);
if (fcn) {
rotateAsmemu (core);
g->need_reload_nodes = true;
@ -4668,7 +4682,10 @@ R_API int r_core_visual_graph(RCore *core, RAGraph *g, RAnalFunction *_fcn, int
{
showcursor (core, true);
r_core_visual_define (core, "", 0);
get_bbupdate (g, core, fcn);
RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, core->offset, 0);
if (fcn) {
get_bbupdate (g, core, fcn);
}
showcursor (core, false);
}
break;

View File

@ -4625,16 +4625,23 @@ R_API RList* r_core_anal_cycles(RCore *core, int ccl) {
return hooks;
}
int cmd_anal_fcn(RCore *core, const char *input);
R_API void r_core_anal_undefine(RCore *core, ut64 off) {
RAnalFunction *f = r_anal_get_fcn_in (core->anal, off, -1);
// very slow
// RAnalFunction *f = r_anal_get_fcn_in (core->anal, off, -1);
RAnalFunction *f = r_anal_get_function_at (core->anal, off);
if (f) {
if (!strncmp (f->name, "fcn.", 4)) {
r_flag_unset_name (core->flags, f->name);
}
r_meta_del (core->anal, R_META_TYPE_ANY, r_anal_function_min_addr (f), r_anal_function_linear_size (f));
r_anal_function_del (core->anal, off);
}
r_anal_function_del_locs (core->anal, off);
r_anal_function_del (core->anal, off);
//r_anal_function_del_locs (core->anal, off);
r_anal_delete_block_at (core->anal, off);
char *abcmd = r_str_newf ("ab-0x%"PFMT64x, off);
cmd_anal_fcn (core, abcmd);
free (abcmd);
}
/* Join function at addr2 into function at addr */

View File

@ -174,10 +174,11 @@ static const char *help_msg_ab[] = {
"Usage:", "ab", "# analyze basic block",
"ab", " [addr]", "show basic block information at given address",
"ab.", "", "same as: ab $$",
"ab-", "[addr]", "delete basic block at given address",
"aba", " [addr]", "analyze esil accesses in basic block (see aea?)",
"abb", " [length]", "analyze N bytes and extract basic blocks",
"abj", " [addr]", "display basic block information in JSON",
"abl", "[,qj]", "list all basic blocks",
"abl", "[?] [.-cqj]", "list all basic blocks",
"abx", " [hexpair-bytes]", "analyze N bytes",
"abt", "[?] [addr] [num]", "find num paths from current offset to addr",
NULL
@ -187,6 +188,7 @@ static const char *help_msg_abl[] = {
"Usage:", "abl", "analyzed basicblocks listing",
"abl", "", "list all program-wide basic blocks analyzed",
"abl,", " [table-query]", "render the list using a table",
"ablc", "", "count how many basic blocks are registered",
"ablj", "", "in json format",
"ablq", "", "in quiet format",
NULL
@ -1630,7 +1632,7 @@ static int var_cmd(RCore *core, const char *str) {
return true;
case 'd': // "afvd"
if (!fcn) {
eprintf ("Cannot find function.\n");
eprintf ("afvd: Cannot find function.\n");
} else if (str[1]) {
p = strchr (ostr, ' ');
if (!p) {
@ -1688,7 +1690,7 @@ static int var_cmd(RCore *core, const char *str) {
free (ostr);
return true;
} else {
eprintf ("Cannot find function\n");
eprintf ("afvt: Cannot find function\n");
return false;
}
}
@ -1711,7 +1713,7 @@ static int var_cmd(RCore *core, const char *str) {
break;
case '-': // "afv[bsr]-"
if (!fcn) {
eprintf ("Cannot find function\n");
eprintf ("afv: Cannot find function\n");
return false;
}
if (str[2] == '*') {
@ -2512,6 +2514,14 @@ static void anal_bb_list(RCore *core, const char *input) {
RTable *table = NULL;
RBIter iter;
RAnalBlock *block;
if (mode == 'c') {
ut64 count = 0;
r_rbtree_foreach (core->anal->bb_tree, iter, block, RAnalBlock, _rb) {
count++;
}
r_cons_printf ("%"PFMT64d"\n", count);
return;
}
if (mode == 'j') {
pj = pj_new ();
pj_o (pj);
@ -2941,8 +2951,6 @@ static bool anal_fcn_del_bb(RCore *core, const char *input) {
}
eprintf ("Cannot find basic block\n");
}
} else {
eprintf ("Cannot find function\n");
}
return false;
}
@ -3853,29 +3861,32 @@ R_API void r_core_af(RCore *core, ut64 addr, const char *name, bool anal_calls)
#endif
}
static int cmd_anal_fcn(RCore *core, const char *input) {
int cmd_anal_fcn(RCore *core, const char *input) {
char i;
r_cons_break_timeout (r_config_get_i (core->config, "anal.timeout"));
switch (input[1]) {
case '-': // "af-"
if (!input[2]) {
if (!input[2]) { // "af-"
cmd_anal_fcn (core, "f-$$");
r_core_anal_undefine (core, core->offset);
} else if (!strcmp (input + 2, "*")) {
} else if (!strcmp (input + 2, "*")) { // "af-*"
RAnalFunction *f;
RListIter *iter, *iter2;
r_list_foreach_safe (core->anal->fcns, iter, iter2, f) {
ut64 addr = f->addr;
r_anal_del_jmprefs (core->anal, f);
r_core_anal_undefine (core, f->addr);
// r_anal_function_del_locs (core->anal, f->addr);
// r_anal_function_del (core->anal, addr);
r_core_anal_undefine (core, addr);
}
} else {
ut64 addr = input[2]
? r_num_math (core->num, input + 2)
: core->offset;
// r_anal_function_del_locs (core->anal, addr);
// r_anal_function_del (core->anal, addr);
r_core_anal_undefine (core, addr);
r_anal_function_del_locs (core->anal, addr);
r_anal_function_del (core->anal, addr);
}
break;
case 'j': // "afj"
@ -11658,6 +11669,17 @@ static int cmd_anal(void *data, const char *input) {
r_core_cmdf (core, "afbij @ 0x%"PFMT64x, addr);
break;
}
case '-': // "ab-"
if (input[2] == '*') {
r_anal_block_reset (core->anal);
} else {
ut64 addr = core->offset;
if (input[2] == ' ') {
addr = r_num_math (core->num, input + 1);
}
r_anal_delete_block_at (core->anal, addr);
}
break;
case 0:
case ' ': { // "ab "
// find block

View File

@ -2796,11 +2796,16 @@ static void ev_iowrite_cb(REvent *ev, int type, void *user, void *data) {
RCore *core = user;
REventIOWrite *iow = data;
if (r_config_get_i (core->config, "anal.detectwrites")) {
// works, but loses varnames and such, but at least is not crashing
char *cmd = r_str_newf ("af-0x%08"PFMT64x";af 0x%08"PFMT64x, iow->addr, iow->addr);
r_list_append (core->cmdqueue, cmd);
#if 0
r_anal_update_analysis_range (core->anal, iow->addr, iow->len);
if (core->cons->event_resize && core->cons->event_data) {
// Force a reload of the graph
core->cons->event_resize (core->cons->event_data);
}
#endif
}
}

View File

@ -1824,7 +1824,6 @@ static bool empty_signature(const char *s) {
}
static void ds_show_functions(RDisasmState *ds) {
RAnalFunction *f;
RCore *core = ds->core;
char *fcn_name;
bool fcn_name_alloc = false; // whether fcn_name needs to be freed by this function
@ -1837,7 +1836,7 @@ static void ds_show_functions(RDisasmState *ds) {
bool showSig = ds->show_fcnsig && ds->show_calls;
bool call = r_config_get_i (core->config, "asm.calls");
const char *lang = demangle ? r_config_get (core->config, "bin.lang") : NULL;
f = r_anal_get_function_at (core->anal, ds->at);
RAnalFunction *f = r_anal_get_function_at (core->anal, ds->at);
if (!f) {
return;
}
@ -2348,7 +2347,6 @@ static void ds_show_flags(RDisasmState *ds, bool overlapped) {
//const char *beginch;
RFlagItem *flag;
RListIter *iter;
RAnalFunction *f = NULL;
if (!ds->show_flags) {
return;
}
@ -2356,7 +2354,7 @@ static void ds_show_flags(RDisasmState *ds, bool overlapped) {
char addr[64] = {0};
ut64 switch_addr = UT64_MAX;
int case_start = -1, case_prev = 0, case_current = 0;
f = r_anal_get_function_at (ds->core->anal, ds->at);
RAnalFunction *f = r_anal_get_function_at (ds->core->anal, ds->at);
const RList *flaglist = r_flag_get_list (core->flags, ds->at);
RList *uniqlist = custom_sorted_flags (flaglist);
int count = 0;

View File

@ -282,7 +282,6 @@ static ut64 getFunctionSize(Sdb *db) {
static bool analyzeFunction(RCore *core, ut64 addr) {
Sdb *db = sdb_new0 ();
RFlagItem *fi;
RList *delayed_commands = NULL;
RListIter *iter;
ut64 loc_addr = 0;
char *command = NULL;
@ -293,7 +292,7 @@ static bool analyzeFunction(RCore *core, ut64 addr) {
return false;
}
delayed_commands = r_list_newf (free);
RList *delayed_commands = r_list_newf (free);
if (!delayed_commands) {
eprintf ("Failed to initialize the delayed command list\n");
sdb_free (db);
@ -354,7 +353,6 @@ static bool analyzeFunction(RCore *core, ut64 addr) {
loc_addr, addr, (int)(addr_end - addr), jump, fail);
sdb_aforeach_next (c);
}
if (vars) {
// handling arguments
RAnalFunction *fcn = r_anal_get_function_at (core->anal, addr);

View File

@ -1397,6 +1397,7 @@ typedef bool (*RAnalAddrCb)(ut64 addr, void *user);
// lifetime
R_API void r_anal_block_ref(RAnalBlock *bb);
R_API void r_anal_block_unref(RAnalBlock *bb);
R_API void r_anal_block_reset(RAnal *a);
// Create one block covering the given range.
// This will fail if the range overlaps any existing blocks.
@ -1424,6 +1425,7 @@ R_API bool r_anal_block_merge(RAnalBlock *a, RAnalBlock *b);
// Manually delete a block and remove it from all its functions
// If there are more references to it than from its functions only, it will not be removed immediately!
R_API void r_anal_delete_block(RAnalBlock *bb);
R_API void r_anal_delete_block_at(RAnal *anal, ut64 addr);
R_API void r_anal_block_set_size(RAnalBlock *block, ut64 size);

View File

@ -178,7 +178,7 @@ R_API bool r_rbtree_aug_delete(RBNode **root, void *data, RBComparator cmp, void
}
}
}
if (del_link) {
if (del_link && *del_link) {
del = *del_link;
if (q->child[q->child[0] == NULL]) {
q->child[q->child[0] == NULL]->parent = p;

View File

@ -5,3 +5,4 @@ CMDS=aae
EXPECT=<<EOF
EOF
RUN

26
test/db/cmd/cmd_aafs Normal file
View File

@ -0,0 +1,26 @@
NAME=aafs
FILE=bins/elf/arm32esilcrash
CMDS=<<EOF
aafs
aflc
ablc
s 0x000081ac
af-$$
ablc
af
ablc
ab-$$
ablc
ab-*
ablc
EOF
EXPECT=<<EOF
1921
1921
1920
1923
1922
0
EOF
RUN

View File

@ -449,179 +449,3 @@ EXPECT=<<EOF
EOF
RUN
NAME=Automatically reanalyze function control flow after a write
FILE=-
ARGS=-a x86 -b 64 -e anal.detectwrites=true
CMDS=<<EOF
wa jne 6 @ 2
wa ret @ 8
af
pdr
wa jne 8 @ 4
pdr
wa mov rax, [rbp-4]
pdr
afvn test var_4h
wa jne 0 @ 4
pdr
wx 00000000
afv # check var was deleted
EOF
EXPECT=<<EOF
/ 9: fcn.00000000 ();
| 0x00000000 0000 add byte [rax], al
| 0x00000002 7502 jne 6
| // true: 0x00000006 false: 0x00000004
| 0x00000004 0000 add byte [rax], al
| // true: 0x00000006
| 0x00000006 0000 add byte [rax], al
\ 0x00000008 c3 ret
/ 9: fcn.00000000 ();
| 0x00000000 0000 add byte [rax], al
| 0x00000002 7502 jne 6
| // true: 0x00000006 false: 0x00000004
| 0x00000004 7502 jne 8
| // true: 0x00000008 false: 0x00000006
| 0x00000006 0000 add byte [rax], al
| // true: 0x00000008
\ 0x00000008 c3 ret
/ 9: fcn.00000000 ();
| ; var int64_t var_4h @ rbp-0x4
| 0x00000000 488b45fc mov rax, qword [var_4h]
| 0x00000004 7502 jne 8
| // true: 0x00000008 false: 0x00000006
| 0x00000006 0000 add byte [rax], al
| // true: 0x00000008
\ 0x00000008 c3 ret
/ 9: fcn.00000000 ();
| ; var int64_t test @ rbp-0x4
| 0x00000000 488b45fc mov rax, qword [test]
| 0x00000004 75fa jne fcn.00000000
| // true: 0x00000000 false: 0x00000006
| 0x00000006 0000 add byte [rax], al
\ 0x00000008 c3 ret
EOF
RUN
NAME=Write misaligns jump instruction, control flow is reanalyzed
FILE=-
ARGS=-a x86 -b 64 -e anal.detectwrites=true
CMDS=<<EOF
wx e80200000075020000c3
af
pdr
wa jne 9
pdr
wx e802
pdr
EOF
EXPECT=<<EOF
/ 10: fcn.00000000 ();
| 0x00000000 e802000000 call 7
| 0x00000005 7502 jne 9
| // true: 0x00000009 false: 0x00000007
| ; CALL XREF from fcn.00000000 @
| 0x00000007 0000 add byte [rax], al
| // true: 0x00000009
\ 0x00000009 c3 ret
/ 10: fcn.00000000 (int64_t arg_2h);
| ; arg int64_t arg_2h @ rbp+0x2
| 0x00000000 7507 jne 9
| // true: 0x00000009 false: 0x00000002
| 0x00000002 0000 add byte [rax], al
| 0x00000004 007502 add byte [arg_2h], dh
| ; CALL XREF from fcn.00000000 @
| 0x00000007 0000 add byte [rax], al
| // true: 0x00000009
\ 0x00000009 c3 ret
/ 10: fcn.00000000 (int64_t arg_2h);
| ; arg int64_t arg_2h @ rbp+0x2
| 0x00000000 e802000000 call 7
| 0x00000005 7502 jne 9
| // true: 0x00000009 false: 0x00000007
| ; CALL XREF from fcn.00000000 @
| 0x00000007 0000 add byte [rax], al
| // true: 0x00000009
\ 0x00000009 c3 ret
EOF
RUN
NAME=Write reanalysis keeps already unreachable block
FILE=-
ARGS=-a x86 -b 64 -e anal.detectwrites=true
CMDS=<<EOF
wx 0000c300c3
af
afb+ 0 4 1
pdr
wa add byte [rax], bl
pdr
EOF
EXPECT=<<EOF
/ 4: fcn.00000000 ();
| 0x00000000 0000 add byte [rax], al
| 0x00000002 c3 ret
\ 0x00000004 c3 ret
/ 4: fcn.00000000 ();
| 0x00000000 0018 add byte [rax], bl
| 0x00000002 c3 ret
\ 0x00000004 c3 ret
EOF
RUN
NAME=Write reanalysis of child of non-modified block
FILE=-
ARGS=-a x86 -b 64 -e anal.detectwrites=true
CMDS=<<EOF
wx eb020000000075fac3
af
wx eb04eb02
pdr
af-
wx eb020000eb020000000075fac3
af
wx eb040000eb02 @ 4
pdr
EOF
EXPECT=<<EOF
/ 7: fcn.00000000 ();
| 0x00000000 eb04 jmp 6
| // true: 0x00000006
| 0x00000002 eb02 jmp 6
| // true: 0x00000006
| ; CODE XREFS from fcn.00000000 @ , 0x2
| 0x00000006 75fa jne 2
| // true: 0x00000002 false: 0x00000008
\ 0x00000008 c3 ret
/ 11: fcn.00000000 ();
| 0x00000000 eb02 jmp 4
| // true: 0x00000004
| ; CODE XREF from fcn.00000000 @
| 0x00000004 eb04 jmp 0xa
| // true: 0x0000000a
| ; CODE XREF from fcn.00000000 @
| ; CODE XREF from fcn.00000000 @ +0x2
| 0x00000006 0000 add byte [rax], al
| ; CODE XREF from fcn.00000000 @ 0x4
| 0x00000008 eb02 jmp 0xc
| // true: 0x0000000c
| ; CODE XREF from fcn.00000000 @ 0x4
| 0x0000000a 75fa jne 6
| // true: 0x00000006 false: 0x0000000c
| ; CODE XREF from fcn.00000000 @ 0x8
\ 0x0000000c c3 ret
EOF
RUN

181
test/db/cmd/write-fun Normal file
View File

@ -0,0 +1,181 @@
NAME=Automatically reanalyze function control flow after a write
FILE=-
BROKEN=1
ARGS=-a x86 -b 64 -e anal.detectwrites=true
CMDS=<<EOF
wa jne 6 @ 2
wa ret @ 8
af
pdr
wa jne 8 @ 4
pdr
wa mov rax, [rbp-4]
pdr
afvn test var_4h
wa jne 0 @ 4
pdr
wx 00000000
afv # check var was deleted
EOF
EXPECT=<<EOF
/ 9: fcn.00000000 ();
| 0x00000000 0000 add byte [rax], al
| 0x00000002 7502 jne 6
| // true: 0x00000006 false: 0x00000004
| 0x00000004 0000 add byte [rax], al
| // true: 0x00000006
| 0x00000006 0000 add byte [rax], al
\ 0x00000008 c3 ret
/ 9: fcn.00000000 ();
| 0x00000000 0000 add byte [rax], al
| 0x00000002 7502 jne 6
| // true: 0x00000006 false: 0x00000004
| 0x00000004 7502 jne 8
| // true: 0x00000008 false: 0x00000006
| 0x00000006 0000 add byte [rax], al
| // true: 0x00000008
\ 0x00000008 c3 ret
/ 9: fcn.00000000 ();
| ; var int64_t var_4h @ rbp-0x4
| 0x00000000 488b45fc mov rax, qword [var_4h]
| 0x00000004 7502 jne 8
| // true: 0x00000008 false: 0x00000006
| 0x00000006 0000 add byte [rax], al
| // true: 0x00000008
\ 0x00000008 c3 ret
/ 9: fcn.00000000 ();
| ; var int64_t test @ rbp-0x4
| 0x00000000 488b45fc mov rax, qword [test]
| 0x00000004 75fa jne fcn.00000000
| // true: 0x00000000 false: 0x00000006
| 0x00000006 0000 add byte [rax], al
\ 0x00000008 c3 ret
EOF
RUN
NAME=Write misaligns jump instruction, control flow is reanalyzed
FILE=-
BROKEN=1
ARGS=-a x86 -b 64 -e anal.detectwrites=true
CMDS=<<EOF
wx e80200000075020000c3
af
pdr
wa jne 9
pdr
wx e802
pdr
EOF
EXPECT=<<EOF
/ 10: fcn.00000000 ();
| 0x00000000 e802000000 call 7
| 0x00000005 7502 jne 9
| // true: 0x00000009 false: 0x00000007
| ; CALL XREF from fcn.00000000 @
| 0x00000007 0000 add byte [rax], al
| // true: 0x00000009
\ 0x00000009 c3 ret
/ 10: fcn.00000000 (int64_t arg_2h);
| ; arg int64_t arg_2h @ rbp+0x2
| 0x00000000 7507 jne 9
| // true: 0x00000009 false: 0x00000002
| 0x00000002 0000 add byte [rax], al
| 0x00000004 007502 add byte [arg_2h], dh
| ; CALL XREF from fcn.00000000 @
| 0x00000007 0000 add byte [rax], al
| // true: 0x00000009
\ 0x00000009 c3 ret
/ 10: fcn.00000000 (int64_t arg_2h);
| ; arg int64_t arg_2h @ rbp+0x2
| 0x00000000 e802000000 call 7
| 0x00000005 7502 jne 9
| // true: 0x00000009 false: 0x00000007
| ; CALL XREF from fcn.00000000 @
| 0x00000007 0000 add byte [rax], al
| // true: 0x00000009
\ 0x00000009 c3 ret
EOF
RUN
NAME=Write reanalysis keeps already unreachable block
BROKEN=1
FILE=-
ARGS=-a x86 -b 64 -e anal.detectwrites=true
CMDS=<<EOF
wx 0000c300c3
af
afb+ 0 4 1
pdr
wa add byte [rax], bl
pdr
EOF
EXPECT=<<EOF
/ 4: fcn.00000000 ();
| 0x00000000 0000 add byte [rax], al
| 0x00000002 c3 ret
\ 0x00000004 c3 ret
/ 4: fcn.00000000 ();
| 0x00000000 0018 add byte [rax], bl
| 0x00000002 c3 ret
\ 0x00000004 c3 ret
EOF
RUN
NAME=Write reanalysis of child of non-modified block
FILE=-
BROKEN=1
ARGS=-a x86 -b 64 -e anal.detectwrites=true
CMDS=<<EOF
wx eb020000000075fac3
af
wx eb04eb02
pdr
af-
wx eb020000eb020000000075fac3
af
wx eb040000eb02 @ 4
pdr
EOF
EXPECT=<<EOF
/ 7: fcn.00000000 ();
| 0x00000000 eb04 jmp 6
| // true: 0x00000006
| 0x00000002 eb02 jmp 6
| // true: 0x00000006
| ; CODE XREFS from fcn.00000000 @ , 0x2
| 0x00000006 75fa jne 2
| // true: 0x00000002 false: 0x00000008
\ 0x00000008 c3 ret
/ 11: fcn.00000000 ();
| 0x00000000 eb02 jmp 4
| // true: 0x00000004
| ; CODE XREF from fcn.00000000 @
| 0x00000004 eb04 jmp 0xa
| // true: 0x0000000a
| ; CODE XREF from fcn.00000000 @
| ; CODE XREF from fcn.00000000 @ +0x2
| 0x00000006 0000 add byte [rax], al
| ; CODE XREF from fcn.00000000 @ 0x4
| 0x00000008 eb02 jmp 0xc
| // true: 0x0000000c
| ; CODE XREF from fcn.00000000 @ 0x4
| 0x0000000a 75fa jne 6
| // true: 0x00000006 false: 0x0000000c
| ; CODE XREF from fcn.00000000 @ 0x8
\ 0x0000000c c3 ret
EOF
RUN