12 #define aprintf(format, ...) \
13 RZ_LOG_DEBUG(format, __VA_ARGS__)
26 analysis->
flb.
set(analysis->
flb.
f, flagname, case_addr, 1);
40 analysis->
flb.
set(analysis->
flb.
f,
tmp, default_case_addr, 1);
47 RzAnalysisJmpTableParams params = {
48 .jmp_address = jmpaddr,
53 .entry_size = tablesize,
54 .table_count = tablesize,
55 .default_case = default_addr,
61 return UT64_MUL_OVFCHK(params->table_count, params->entry_size) ||
62 params->table_count * params->entry_size >
ST32_MAX;
79 if (params->table_count == 0) {
80 params->table_count = analysis->opt.jmptbl_maxcount;
82 if (params->jmptbl_loc ==
UT64_MAX) {
83 aprintf(
"Invalid jump table location 0x%08" PFMT64x "\n", params->jmptbl_loc);
86 if (params->casetbl_loc ==
UT64_MAX) {
87 aprintf(
"Invalid case table location 0x%08" PFMT64x "\n", params->jmptbl_loc);
91 aprintf(
"Invalid jump table size at 0x%08" PFMT64x "\n", params->jmp_address);
94 ut64 jmpptr, case_idx, jmpptr_idx;
95 ut8 *jmptbl =
calloc(params->table_count, params->entry_size);
96 if (!jmptbl || !analysis->iob.read_at(analysis->iob.io, params->jmptbl_loc, jmptbl, params->table_count * params->entry_size)) {
100 ut8 *casetbl =
calloc(params->table_count,
sizeof(
ut8));
101 if (!casetbl || !analysis->iob.read_at(analysis->iob.io, params->casetbl_loc, casetbl, params->table_count)) {
106 for (case_idx = 0; case_idx < params->table_count; case_idx++) {
107 jmpptr_idx = casetbl[case_idx];
109 if (jmpptr_idx >= params->table_count) {
114 switch (params->entry_size) {
131 if (!analysis->iob.is_valid_offset(analysis->iob.io, jmpptr, 0)) {
134 jmpptr = params->jmptbl_off + jmpdelta;
135 if (!analysis->iob.is_valid_offset(analysis->iob.io, jmpptr, 0)) {
139 if (analysis->limit) {
140 if (jmpptr < analysis->
limit->from || jmpptr > analysis->limit->to) {
145 const ut64 jmpptr_idx_off = params->casetbl_loc + case_idx;
149 apply_case(analysis, block, params->jmp_address, params->entry_size, jmpptr, case_idx + params->case_shift, params->jmptbl_loc + jmpptr_idx * params->entry_size);
154 if (params->default_case == 0) {
157 apply_switch(analysis, params->jmp_address, params->jmptbl_loc, case_idx, params->default_case);
179 if (params->table_count == 0) {
180 params->table_count = analysis->opt.jmptbl_maxcount;
182 if (params->jmptbl_loc ==
UT64_MAX) {
183 aprintf(
"Invalid jump table location 0x%08" PFMT64x "\n", params->jmptbl_loc);
187 aprintf(
"Invalid jump table size at 0x%08" PFMT64x "\n", params->jmp_address);
191 ut8 *jmptbl =
calloc(params->table_count, params->entry_size);
195 bool is_arm = analysis->cur->arch && !strncmp(analysis->cur->arch,
"arm", 3);
197 analysis->iob.read_at(analysis->iob.io, params->jmptbl_loc, jmptbl, params->table_count * params->entry_size);
198 for (offs = 0; offs + params->entry_size - 1 < params->table_count * params->entry_size; offs += params->entry_size) {
199 switch (params->entry_size) {
223 if (params->entry_size == 2 &&
is_arm) {
224 jmpptr = params->jmp_address + 4 + (jmpptr * 2);
225 }
else if (params->entry_size == 1 &&
is_arm) {
226 jmpptr = params->jmp_address + 4 + (jmpptr * 2);
227 }
else if (!analysis->iob.is_valid_offset(analysis->iob.io, jmpptr, 0)) {
230 jmpptr = params->jmptbl_off + jmpdelta;
231 if (!analysis->iob.is_valid_offset(analysis->iob.io, jmpptr, 0)) {
235 if (analysis->limit) {
236 if (jmpptr < analysis->
limit->from || jmpptr > analysis->limit->to) {
240 apply_case(analysis, block, params->jmp_address, params->entry_size, jmpptr, (offs / params->entry_size) + params->case_shift, params->jmptbl_loc + offs);
245 if (params->default_case == 0) {
248 apply_switch(analysis, params->jmp_address, params->jmptbl_loc, offs / params->entry_size, params->default_case);
259 if (
op->dst &&
op->dst->reg &&
op->dst->reg->offset == (*cmp_reg)->offset) {
261 *start_casenum_shift = -(
st64)
op->disp;
264 *start_casenum_shift = -(
st64)
op->val;
266 *start_casenum_shift =
op->val;
269 *cmp_reg =
op->src[0]->reg;
291 bool foundCmp =
false;
295 if (lea_address > jmp_address) {
299 params->jmp_address = jmp_address;
301 int search_sz = jmp_address - lea_address;
307 analysis->iob.read_at(analysis->iob.io, lea_address, (
ut8 *)
buf, search_sz);
312 for (
i = 0;
i + 8 < search_sz;
i +=
len) {
339 params->table_count = 0;
340 }
else if (tmp_aop.
refptr == 0) {
342 params->table_count = tmp_aop.
val + 1;
345 params->table_count = tmp_aop.
refptr + 1;
350 cmp_reg = tmp_aop.
dst->
reg;
351 }
else if (tmp_aop.
reg) {
353 }
else if (tmp_aop.
src[0] && tmp_aop.
src[0]->
reg) {
354 cmp_reg = tmp_aop.
src[0]->
reg;
361 params->case_shift = 0;
365 ut64 op_addr = lea_address + op_off;
367 buf + op_off, search_sz - op_off,
413 if (params->table_count == 0) {
414 params->table_count = analysis->opt.jmptbl_maxcount;
417 for (offs = 0; offs + params->entry_size - 1 < params->table_count * params->entry_size; offs += params->entry_size) {
418 jmpptr = params->jmptbl_loc + offs;
419 apply_case(analysis, block, params->jmp_address, params->entry_size, jmpptr, offs / params->entry_size, params->jmptbl_loc + offs);
424 if (params->default_case == 0 || params->default_case ==
UT32_MAX) {
427 apply_switch(analysis, params->jmp_address, params->jmptbl_loc, offs / params->entry_size, params->default_case);
454 params->jmp_address = jmp_address;
457 RzBinSection *
s = analysis->binb.get_vsect_at(analysis->binb.bin, jmp_address);
458 if (
s &&
s->name[0]) {
459 bool in_plt = strstr(
s->name,
".plt") !=
NULL;
460 if (!in_plt && strstr(
s->name,
"_stubs") !=
NULL) {
470 rz_list_foreach (fcn->bbs,
iter, tmp_bb) {
471 if (tmp_bb->
jump == block->addr || tmp_bb->
fail == block->addr) {
477 if (!prev_bb || !prev_bb->
jump || !prev_bb->
fail) {
478 aprintf(
"Missing predecesessor on basic block conditional jump at 0x%08" PFMT64x ", required by jump table\n", jmp_address);
483 params->default_case = prev_bb->
jump == block->addr ? prev_bb->
fail : prev_bb->
jump;
491 analysis->iob.read_at(analysis->iob.io, prev_bb->
addr, (
ut8 *)bb_buf, prev_bb->
size);
499 params->table_count =
val;
505 for (
i = prev_bb->
ninstr - 1;
i >= 0;
i--) {
508 if (prev_pos >= prev_bb->
size) {
513 bb_buf + prev_pos,
buflen,
528 params->table_count = 0;
531 params->table_count = tmp_aop.
val + 1;
534 params->table_count = tmp_aop.
refptr + 1;
539 bb_buf + prev_pos,
buflen,
542 cmp_reg = tmp_aop.
dst->
reg;
543 }
else if (tmp_aop.
reg) {
545 }
else if (tmp_aop.
src[0] && tmp_aop.
src[0]->
reg) {
546 cmp_reg = tmp_aop.
src[0]->
reg;
554 params->case_shift = 0;
555 for (
i--;
i >= 0;
i--) {
558 if (prev_pos >= prev_bb->
size) {
563 bb_buf + prev_pos,
buflen,
static bool isValid(ut64 addr)
RZ_API ut64 rz_analysis_block_get_op_addr(RzAnalysisBlock *block, size_t i)
RZ_API void rz_analysis_block_add_switch_case(RzAnalysisBlock *block, ut64 switch_addr, ut64 case_value, ut64 case_addr)
RZ_API ut16 rz_analysis_block_get_op_offset(RzAnalysisBlock *block, size_t i)
RZ_API bool rz_analysis_task_item_new(RZ_NONNULL RzAnalysis *analysis, RZ_NONNULL RzVector *tasks, RZ_NONNULL RzAnalysisFunction *fcn, RZ_NULLABLE RzAnalysisBlock *block, ut64 address)
Adds a new task item to the tasks parameter.
RZ_API RzAnalysisHint * rz_analysis_hint_get(RzAnalysis *a, ut64 addr)
RZ_API void rz_analysis_hint_free(RzAnalysisHint *h)
RZ_API void rz_analysis_hint_set_immbase(RzAnalysis *a, ut64 addr, int base)
RZ_API void Ht_() free(HtName_(Ht) *ht)
static bool jmptable_size_is_invalid(RzAnalysisJmpTableParams *params)
#define aprintf(format,...)
RZ_API bool rz_analysis_walkthrough_arm_jmptbl_style(RZ_NONNULL RzAnalysis *analysis, RZ_NONNULL RzAnalysisFunction *fcn, RZ_NONNULL RzAnalysisBlock *block, RZ_NONNULL RzAnalysisJmpTableParams *params)
Marks for analysis ARM specific jump table cases.
RZ_API bool rz_analysis_get_jmptbl_info(RZ_NONNULL RzAnalysis *analysis, RZ_NONNULL RzAnalysisFunction *fcn, RZ_NONNULL RzAnalysisBlock *block, ut64 jmp_address, RZ_NONNULL RzAnalysisJmpTableParams *params)
Gets some necessary information about a jump table to perform analysis on.
static void apply_switch(RzAnalysis *analysis, ut64 switch_addr, ut64 jmptbl_addr, ut64 cases_count, ut64 default_case_addr)
RZ_API bool rz_analysis_walkthrough_jmptbl(RZ_NONNULL RzAnalysis *analysis, RZ_NONNULL RzAnalysisFunction *fcn, RZ_NONNULL RzAnalysisBlock *block, RZ_NONNULL RzAnalysisJmpTableParams *params)
Marks the jump table cases for analysis.
static bool detect_casenum_shift(RzAnalysisOp *op, RzRegItem **cmp_reg, st64 *start_casenum_shift)
RZ_API bool rz_analysis_get_delta_jmptbl_info(RZ_NONNULL RzAnalysis *analysis, RZ_NONNULL RzAnalysisFunction *fcn, ut64 jmp_address, ut64 lea_address, RZ_NONNULL RzAnalysisJmpTableParams *params)
Gets some necessary information about a jump table to perform analysis on.
static void apply_case(RzAnalysis *analysis, RzAnalysisBlock *block, ut64 switch_addr, ut64 offset_sz, ut64 case_addr, ut64 id, ut64 case_addr_loc)
RZ_API bool rz_analysis_jmptbl(RzAnalysis *analysis, RzAnalysisFunction *fcn, RzAnalysisBlock *block, ut64 jmpaddr, ut64 table, ut64 tablesize, ut64 default_addr)
RZ_API bool rz_analysis_walkthrough_casetbl(RZ_NONNULL RzAnalysis *analysis, RZ_NONNULL RzAnalysisFunction *fcn, RZ_NONNULL RzAnalysisBlock *block, RZ_NONNULL RzAnalysisJmpTableParams *params)
Marks for analysis jump table cases with a space optimization for multiple cases corresponding to the...
void * malloc(size_t size)
void * calloc(size_t number, size_t size)
static uint32_t const uint8_t uint32_t uint32_t limit
RZ_API bool rz_analysis_op_fini(RzAnalysisOp *op)
RZ_API int rz_analysis_op(RzAnalysis *analysis, RzAnalysisOp *op, ut64 addr, const ut8 *data, int len, RzAnalysisOpMask mask)
static int is_arm(RzBinPEObj *bin)
RZ_API RzRegItem * rz_reg_get(RzReg *reg, const char *name, int type)
@ RZ_ANALYSIS_XREF_TYPE_CODE
@ RZ_ANALYSIS_OP_MASK_BASIC
@ RZ_ANALYSIS_OP_MASK_VAL
@ RZ_ANALYSIS_OP_MASK_HINT
#define RZ_ANALYSIS_OP_TYPE_MASK
@ RZ_ANALYSIS_OP_TYPE_CMP
@ RZ_ANALYSIS_OP_TYPE_SUB
@ RZ_ANALYSIS_OP_TYPE_ADD
@ RZ_ANALYSIS_OP_TYPE_CJMP
@ RZ_ANALYSIS_OP_TYPE_MOV
@ RZ_ANALYSIS_OP_TYPE_LEA
#define rz_return_val_if_fail(expr, val)
static ut16 rz_read_le16(const void *src)
static ut32 rz_read_le32(const void *src)
static ut8 rz_read_le8(const void *src)
static ut64 rz_read_le64(const void *src)
RZ_API void * rz_vector_push(RzVector *vec, void *x)
RZ_API void rz_vector_fini(RzVector *vec)
#define rz_vector_foreach_prev(vec, it)
RZ_API void rz_vector_init(RzVector *vec, size_t elem_size, RzVectorFree free, void *free_user)
ut64(WINAPI *w32_GetEnabledXStateFeatures)()
RZ_API bool rz_analysis_xrefs_set(RzAnalysis *analysis, ut64 from, ut64 to, RzAnalysisXRefType type)