RzIL: add aezsue to support Step until PC equals given address and output VM changes (#4466)
This commit is contained in:
parent
ba780a78dc
commit
a420733022
9 changed files with 151 additions and 28 deletions
|
|
@ -228,17 +228,18 @@ RZ_API bool rz_analysis_il_vm_sync_to_reg(RzAnalysisILVM *vm, RZ_NONNULL RzReg *
|
|||
return rz_il_vm_sync_to_reg(vm->vm, vm->reg_binding, reg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Repeatedly perform steps in the VM until the condition callback returns false
|
||||
*
|
||||
* If given, this syncs the contents of \p reg into the vm.
|
||||
* Then it repeatedly disassembles an instruction at the program counter of the vm and executes it as long as cond() returns true.
|
||||
* Finally the contents are optionally synced back to \p reg.
|
||||
*
|
||||
* \return and indicator for which error occured, if any, or RZ_ANALYSIS_IL_STEP_RESULT_SUCCESS if cond() returned false
|
||||
*/
|
||||
RZ_API RzAnalysisILStepResult rz_analysis_il_vm_step_while(RZ_NONNULL RzAnalysis *analysis, RZ_NONNULL RzAnalysisILVM *vm, RZ_NULLABLE RzReg *reg,
|
||||
bool (*cond)(RzAnalysisILVM *vm, void *user), void *user) {
|
||||
static void il_events(RzILVM *vm, RzStrBuf *sb) {
|
||||
void **it;
|
||||
rz_pvector_foreach (vm->events, it) {
|
||||
RzILEvent *evt = *it;
|
||||
rz_il_event_stringify(evt, sb);
|
||||
rz_strbuf_append(sb, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
static RzAnalysisILStepResult analysis_il_vm_step_while(
|
||||
RZ_NONNULL RzAnalysis *analysis, RZ_NONNULL RzAnalysisILVM *vm, RZ_NULLABLE RzReg *reg,
|
||||
bool with_events, RZ_NONNULL RzAnalysisILVMCondCallback cond, RZ_NULLABLE void *user) {
|
||||
|
||||
rz_return_val_if_fail(analysis && vm, false);
|
||||
RzAnalysisPlugin *cur = analysis->cur;
|
||||
|
|
@ -250,36 +251,96 @@ RZ_API RzAnalysisILStepResult rz_analysis_il_vm_step_while(RZ_NONNULL RzAnalysis
|
|||
rz_analysis_il_vm_sync_from_reg(vm, reg);
|
||||
}
|
||||
|
||||
RzAnalysisOp op = { 0 };
|
||||
RzAnalysisILStepResult res = RZ_ANALYSIS_IL_STEP_RESULT_SUCCESS;
|
||||
while (cond(vm, user)) {
|
||||
ut64 addr = rz_bv_to_ut64(vm->vm->pc);
|
||||
ut8 code[32] = { 0 };
|
||||
analysis->read_at(analysis, addr, code, sizeof(code));
|
||||
RzAnalysisOp op = { 0 };
|
||||
rz_analysis_op_init(&op);
|
||||
int r = rz_analysis_op(analysis, &op, addr, code, sizeof(code), RZ_ANALYSIS_OP_MASK_IL | RZ_ANALYSIS_OP_MASK_HINT);
|
||||
RzILOpEffect *ilop = r < 0 ? NULL : op.il_op;
|
||||
int r = rz_analysis_op(analysis, &op, addr, code, sizeof(code), RZ_ANALYSIS_OP_MASK_IL | RZ_ANALYSIS_OP_MASK_HINT | RZ_ANALYSIS_OP_MASK_DISASM);
|
||||
|
||||
if (ilop) {
|
||||
bool succ = rz_il_vm_step(vm->vm, ilop, addr + (op.size > 0 ? op.size : 1));
|
||||
if (!succ) {
|
||||
res = RZ_ANALYSIS_IL_STEP_IL_RUNTIME_ERROR;
|
||||
}
|
||||
} else {
|
||||
if (r < 0 || !op.il_op) {
|
||||
res = RZ_ANALYSIS_IL_STEP_INVALID_OP;
|
||||
}
|
||||
|
||||
rz_analysis_op_fini(&op);
|
||||
if (res != RZ_ANALYSIS_IL_STEP_RESULT_SUCCESS) {
|
||||
break;
|
||||
}
|
||||
if (!rz_il_vm_step(vm->vm, op.il_op, addr + (op.size > 0 ? op.size : 1))) {
|
||||
res = RZ_ANALYSIS_IL_STEP_IL_RUNTIME_ERROR;
|
||||
break;
|
||||
}
|
||||
if (!with_events) {
|
||||
rz_analysis_op_fini(&op);
|
||||
continue;
|
||||
}
|
||||
|
||||
RzStrBuf sb = { 0 };
|
||||
rz_strbuf_init(&sb);
|
||||
rz_il_op_effect_stringify(op.il_op, &sb, true);
|
||||
rz_strbuf_append(&sb, "\n");
|
||||
il_events(vm->vm, &sb);
|
||||
|
||||
rz_cons_printf("0x%llx [", addr);
|
||||
for (int i = 0; i < op.size; ++i) {
|
||||
rz_cons_printf("%x", code[i]);
|
||||
}
|
||||
rz_cons_printf("] %s\n%s\n", op.mnemonic, rz_strbuf_get(&sb));
|
||||
rz_strbuf_fini(&sb);
|
||||
rz_analysis_op_fini(&op);
|
||||
}
|
||||
rz_analysis_op_fini(&op);
|
||||
if (reg) {
|
||||
rz_analysis_il_vm_sync_to_reg(vm, reg);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Repeatedly perform steps in the VM until the \p cond callback returns false
|
||||
*
|
||||
* \param analysis Pointer to an RzAnalysis struct, likely representing the analysis context.
|
||||
* \param vm Pointer to an RzAnalysisILVM struct, representing the IL virtual machine to be stepped.
|
||||
* \param reg Optional pointer to an RzReg struct, potentially holding register values to be used during the step.
|
||||
* \param cond Pointer to a function that determines the loop's continuation condition. This function takes two arguments:
|
||||
* * vm: Pointer to the same RzAnalysisILVM struct passed to rz_analysis_il_vm_step_while.
|
||||
* * user: Pointer to user-provided data that can be used by the condition function.
|
||||
* \param user Pointer to user-defined data that can be passed to the condition function.
|
||||
*
|
||||
* \return RZ_ANALYSIS_IL_STEP_RESULT: Enumeration value indicating the outcome of the stepping operation.
|
||||
* Possible values (implementation specific):
|
||||
* - RZ_ANALYSIS_IL_STEP_OK: Successful execution of the while loop step.
|
||||
* - RZ_ANALYSIS_IL_STEP_ERROR: Encountered an error during execution.
|
||||
* - RZ_ANALYSIS_IL_STEP_INVALID: Invalid arguments or state resulted in undefined behavior.
|
||||
*/
|
||||
RZ_API RzAnalysisILStepResult rz_analysis_il_vm_step_while(
|
||||
RZ_NONNULL RzAnalysis *analysis, RZ_NONNULL RzAnalysisILVM *vm, RZ_NULLABLE RzReg *reg,
|
||||
RZ_NONNULL RzAnalysisILVMCondCallback cond, RZ_NULLABLE void *user) {
|
||||
return analysis_il_vm_step_while(analysis, vm, reg, false, cond, user);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Repeatedly perform steps in the VM until the \p cond callback returns false
|
||||
* and output VM changes (read & write)
|
||||
*
|
||||
* \param analysis Pointer to an RzAnalysis struct, likely representing the analysis context.
|
||||
* \param vm Pointer to an RzAnalysisILVM struct, representing the IL virtual machine to be stepped.
|
||||
* \param reg Optional pointer to an RzReg struct, potentially holding register values to be used during the step.
|
||||
* \param cond Pointer to a function that determines the loop's continuation condition. This function takes two arguments:
|
||||
* * vm: Pointer to the same RzAnalysisILVM struct passed to rz_analysis_il_vm_step_while.
|
||||
* * user: Pointer to user-provided data that can be used by the condition function.
|
||||
* \param user Pointer to user-defined data that can be passed to the condition function.
|
||||
*
|
||||
* \return RZ_ANALYSIS_IL_STEP_RESULT: Enumeration value indicating the outcome of the stepping operation.
|
||||
* Possible values (implementation specific):
|
||||
* - RZ_ANALYSIS_IL_STEP_OK: Successful execution of the while loop step.
|
||||
* - RZ_ANALYSIS_IL_STEP_ERROR: Encountered an error during execution.
|
||||
* - RZ_ANALYSIS_IL_STEP_INVALID: Invalid arguments or state resulted in undefined behavior.
|
||||
*/
|
||||
RZ_API RzAnalysisILStepResult rz_analysis_il_vm_step_while_with_events(
|
||||
RZ_NONNULL RzAnalysis *analysis, RZ_NONNULL RzAnalysisILVM *vm, RZ_NULLABLE RzReg *reg,
|
||||
RZ_NONNULL RzAnalysisILVMCondCallback cond, RZ_NULLABLE void *user) {
|
||||
return analysis_il_vm_step_while(analysis, vm, reg, true, cond, user);
|
||||
}
|
||||
|
||||
static bool step_cond_once(RzAnalysisILVM *vm, void *user) {
|
||||
bool *stepped = user;
|
||||
if (*stepped) {
|
||||
|
|
|
|||
|
|
@ -741,6 +741,23 @@ RZ_API bool rz_core_il_step_until(RZ_NONNULL RzCore *core, ut64 until) {
|
|||
return step_handle_result(core, r);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform zero or more steps starting at the PC given by analysis->reg in RzIL
|
||||
* until reaching the given PC and output VM changes (read & write)
|
||||
* \param until destination address where to stop
|
||||
* \return false if an error occured (e.g. invalid op)
|
||||
*/
|
||||
RZ_API bool rz_core_il_step_until_with_events(RZ_NONNULL RzCore *core, ut64 until) {
|
||||
rz_return_val_if_fail(core && until, false);
|
||||
if (!step_assert_vm(core)) {
|
||||
return false;
|
||||
}
|
||||
RzAnalysisILStepResult r = rz_analysis_il_vm_step_while_with_events(
|
||||
core->analysis, core->analysis->il_vm, core->analysis->reg,
|
||||
step_cond_until, &until);
|
||||
return step_handle_result(core, r);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a single step at the PC given by analysis->reg in RzIL and print any events that happened
|
||||
* \return false if an error occured (e.g. invalid op)
|
||||
|
|
|
|||
|
|
@ -4675,6 +4675,12 @@ RZ_IPI RzCmdStatus rz_il_vm_step_until_addr_handler(RzCore *core, int argc, cons
|
|||
return RZ_CMD_STATUS_OK;
|
||||
}
|
||||
|
||||
RZ_IPI RzCmdStatus rz_il_vm_step_until_addr_with_events_handler(RzCore *core, int argc, const char **argv) {
|
||||
ut64 address = rz_num_math(core->num, argv[1]);
|
||||
rz_core_il_step_until_with_events(core, address);
|
||||
return RZ_CMD_STATUS_OK;
|
||||
}
|
||||
|
||||
RZ_IPI RzCmdStatus rz_il_vm_status_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) {
|
||||
if (argc == 3) {
|
||||
ut64 value = rz_num_math(core->num, argv[2]);
|
||||
|
|
|
|||
|
|
@ -990,6 +990,13 @@ commands:
|
|||
args:
|
||||
- name: address
|
||||
type: RZ_CMD_ARG_TYPE_RZNUM
|
||||
- name: aezsue
|
||||
summary: Step until PC equals given address and output VM changes (read & write)
|
||||
type: RZ_CMD_DESC_TYPE_ARGV
|
||||
cname: il_vm_step_until_addr_with_events
|
||||
args:
|
||||
- name: address
|
||||
type: RZ_CMD_ARG_TYPE_RZNUM
|
||||
- name: aezv
|
||||
summary: Print or modify the current status of the RzIL Virtual Machine
|
||||
cname: il_vm_status
|
||||
|
|
|
|||
|
|
@ -213,6 +213,7 @@ static const RzCmdDescArg il_step_until_opt_args[2];
|
|||
static const RzCmdDescArg il_vm_step_args[2];
|
||||
static const RzCmdDescArg il_vm_step_with_events_args[2];
|
||||
static const RzCmdDescArg il_vm_step_until_addr_args[2];
|
||||
static const RzCmdDescArg il_vm_step_until_addr_with_events_args[2];
|
||||
static const RzCmdDescArg il_vm_status_args[3];
|
||||
static const RzCmdDescArg analysis_graph_dataref_args[2];
|
||||
static const RzCmdDescArg analysis_graph_dataref_global_args[2];
|
||||
|
|
@ -4046,6 +4047,20 @@ static const RzCmdDescHelp il_vm_step_until_addr_help = {
|
|||
.args = il_vm_step_until_addr_args,
|
||||
};
|
||||
|
||||
static const RzCmdDescArg il_vm_step_until_addr_with_events_args[] = {
|
||||
{
|
||||
.name = "address",
|
||||
.type = RZ_CMD_ARG_TYPE_RZNUM,
|
||||
.flags = RZ_CMD_ARG_FLAG_LAST,
|
||||
|
||||
},
|
||||
{ 0 },
|
||||
};
|
||||
static const RzCmdDescHelp il_vm_step_until_addr_with_events_help = {
|
||||
.summary = "Step until PC equals given address and output VM changes (read & write)",
|
||||
.args = il_vm_step_until_addr_with_events_args,
|
||||
};
|
||||
|
||||
static const RzCmdDescArg il_vm_status_args[] = {
|
||||
{
|
||||
.name = "var_name",
|
||||
|
|
@ -19727,6 +19742,9 @@ RZ_IPI void rzshell_cmddescs_init(RzCore *core) {
|
|||
RzCmdDesc *il_vm_step_until_addr_cd = rz_cmd_desc_argv_new(core->rcmd, aez_cd, "aezsu", rz_il_vm_step_until_addr_handler, &il_vm_step_until_addr_help);
|
||||
rz_warn_if_fail(il_vm_step_until_addr_cd);
|
||||
|
||||
RzCmdDesc *il_vm_step_until_addr_with_events_cd = rz_cmd_desc_argv_new(core->rcmd, aez_cd, "aezsue", rz_il_vm_step_until_addr_with_events_handler, &il_vm_step_until_addr_with_events_help);
|
||||
rz_warn_if_fail(il_vm_step_until_addr_with_events_cd);
|
||||
|
||||
RzCmdDesc *il_vm_status_cd = rz_cmd_desc_argv_modes_new(core->rcmd, aez_cd, "aezv", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_TABLE | RZ_OUTPUT_MODE_JSON | RZ_OUTPUT_MODE_QUIET, rz_il_vm_status_handler, &il_vm_status_help);
|
||||
rz_warn_if_fail(il_vm_status_cd);
|
||||
|
||||
|
|
|
|||
|
|
@ -454,6 +454,8 @@ RZ_IPI RzCmdStatus rz_il_vm_step_handler(RzCore *core, int argc, const char **ar
|
|||
RZ_IPI RzCmdStatus rz_il_vm_step_with_events_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode);
|
||||
// "aezsu"
|
||||
RZ_IPI RzCmdStatus rz_il_vm_step_until_addr_handler(RzCore *core, int argc, const char **argv);
|
||||
// "aezsue"
|
||||
RZ_IPI RzCmdStatus rz_il_vm_step_until_addr_with_events_handler(RzCore *core, int argc, const char **argv);
|
||||
// "aezv"
|
||||
RZ_IPI RzCmdStatus rz_il_vm_status_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode);
|
||||
// "aga"
|
||||
|
|
|
|||
|
|
@ -261,8 +261,12 @@ RZ_API void rz_il_vm_mem_storew(RzILVM *vm, RzILMemIndex index, RzBitVector *key
|
|||
return;
|
||||
}
|
||||
RzBitVector *old_value = rz_il_mem_loadw(mem, key, rz_bv_len(value), vm->big_endian);
|
||||
rz_il_mem_storew(mem, key, value, vm->big_endian);
|
||||
if (!rz_il_mem_storew(mem, key, value, vm->big_endian)) {
|
||||
RZ_LOG_ERROR("StoreW mem %u 0x%llx failed\n", (unsigned int)index, rz_bv_to_ut64(key));
|
||||
goto end;
|
||||
}
|
||||
rz_il_vm_event_add(vm, rz_il_event_mem_write_new(key, old_value, value));
|
||||
end:
|
||||
rz_bv_free(old_value);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1700,13 +1700,20 @@ RZ_API RZ_OWN RzAnalysisILConfig *rz_analysis_il_config_new(ut32 pc_size, bool b
|
|||
RZ_API void rz_analysis_il_config_free(RzAnalysisILConfig *cfg);
|
||||
RZ_API void rz_analysis_il_config_add_label(RZ_NONNULL RzAnalysisILConfig *cfg, RZ_NONNULL RZ_OWN RzILEffectLabel *label);
|
||||
|
||||
typedef bool (*RzAnalysisILVMCondCallback)(RzAnalysisILVM *vm, void *user);
|
||||
|
||||
RZ_API RZ_OWN RzAnalysisILVM *rz_analysis_il_vm_new(RzAnalysis *a, RZ_NULLABLE RzReg *init_state_reg);
|
||||
RZ_API void rz_analysis_il_vm_free(RZ_NULLABLE RzAnalysisILVM *vm);
|
||||
RZ_API void rz_analysis_il_vm_sync_from_reg(RzAnalysisILVM *vm, RZ_NONNULL RzReg *reg);
|
||||
RZ_API bool rz_analysis_il_vm_sync_to_reg(RzAnalysisILVM *vm, RZ_NONNULL RzReg *reg);
|
||||
RZ_API RzAnalysisILStepResult rz_analysis_il_vm_step(RZ_NONNULL RzAnalysis *analysis, RZ_NONNULL RzAnalysisILVM *vm, RZ_NULLABLE RzReg *reg);
|
||||
RZ_API RzAnalysisILStepResult rz_analysis_il_vm_step_while(RZ_NONNULL RzAnalysis *analysis, RZ_NONNULL RzAnalysisILVM *vm, RZ_NULLABLE RzReg *reg,
|
||||
bool (*cond)(RzAnalysisILVM *vm, void *user), void *user);
|
||||
RZ_API RzAnalysisILStepResult rz_analysis_il_vm_step(
|
||||
RZ_NONNULL RzAnalysis *analysis, RZ_NONNULL RzAnalysisILVM *vm, RZ_NULLABLE RzReg *reg);
|
||||
RZ_API RzAnalysisILStepResult rz_analysis_il_vm_step_while(
|
||||
RZ_NONNULL RzAnalysis *analysis, RZ_NONNULL RzAnalysisILVM *vm, RZ_NULLABLE RzReg *reg,
|
||||
RZ_NONNULL RzAnalysisILVMCondCallback cond, RZ_NULLABLE void *user);
|
||||
RZ_API RzAnalysisILStepResult rz_analysis_il_vm_step_while_with_events(
|
||||
RZ_NONNULL RzAnalysis *analysis, RZ_NONNULL RzAnalysisILVM *vm, RZ_NULLABLE RzReg *reg,
|
||||
RZ_NONNULL RzAnalysisILVMCondCallback cond, RZ_NULLABLE void *user);
|
||||
RZ_API bool rz_analysis_il_vm_setup(RzAnalysis *analysis);
|
||||
RZ_API void rz_analysis_il_vm_cleanup(RzAnalysis *analysis);
|
||||
|
||||
|
|
|
|||
|
|
@ -672,6 +672,7 @@ RZ_API void rz_core_analysis_esil_init_regs(RZ_NONNULL RzCore *core);
|
|||
RZ_API void rz_core_analysis_il_reinit(RZ_NONNULL RzCore *core);
|
||||
RZ_API bool rz_core_il_step(RZ_NONNULL RzCore *core, ut64 n);
|
||||
RZ_API bool rz_core_il_step_until(RZ_NONNULL RzCore *core, ut64 until);
|
||||
RZ_API bool rz_core_il_step_until_with_events(RZ_NONNULL RzCore *core, ut64 until);
|
||||
|
||||
/* canalysis.c */
|
||||
typedef enum rz_core_analysis_name_type {
|
||||
|
|
|
|||
Loading…
Reference in a new issue