Add analysis.jmp.tblmaxoffset configuration option

Allows the user to configure the maximum offset from the jump table jump instruction to consider it valid
This commit is contained in:
GustavoLCR 2022-06-18 23:43:11 -03:00 committed by Anton Kochkov
parent 2eba4e190d
commit d8dd2c5097
3 changed files with 18 additions and 5 deletions

View file

@ -12,7 +12,6 @@
#define SDB_KEY_BB "bb.0x%" PFMT64x ".0x%" PFMT64x
// XXX must be configurable by the user
#define JMPTBL_LEA_SEARCH_SZ 64
#define JMPTBL_MAXFCNSIZE 4096
#define BB_ALIGN 0x10
#define MAX_SCAN_SIZE 0x7ffffff
@ -164,7 +163,7 @@ static bool isSymbolNextInstruction(RzAnalysis *analysis, RzAnalysisOp *op) {
return (fi && fi->name && (strstr(fi->name, "imp.") || strstr(fi->name, "sym.") || strstr(fi->name, "entry") || strstr(fi->name, "main")));
}
static bool is_delta_pointer_table(RzAnalysis *analysis, RzAnalysisFunction *fcn, ut64 addr, ut64 lea_ptr, ut64 *jmptbl_addr, ut64 *casetbl_addr, RzAnalysisOp *jmp_aop) {
static bool is_delta_pointer_table(RzAnalysis *analysis, ut64 addr, ut64 lea_ptr, ut64 *jmptbl_addr, ut64 *casetbl_addr, RzAnalysisOp *jmp_aop) {
int i;
ut64 dst;
st32 jmptbl[64] = { 0 };
@ -244,12 +243,17 @@ static bool is_delta_pointer_table(RzAnalysis *analysis, RzAnalysisFunction *fcn
for (i = 0; i < 3; i++) {
dst = lea_ptr + (st32)rz_read_le32(jmptbl);
if (!analysis->iob.is_valid_offset(analysis->iob.io, dst, 0)) {
RZ_LOG_VERBOSE("Jump table target is not valid: 0x%" PFMT64x "\n", dst);
return false;
}
if (dst > fcn->addr + JMPTBL_MAXFCNSIZE) {
if (!UT64_ADD_OVFCHK(jmp_aop->addr, analysis->opt.jmptbl_maxoffset) &&
dst > jmp_aop->addr + analysis->opt.jmptbl_maxoffset) {
RZ_LOG_VERBOSE("Jump table target is too far away: 0x%" PFMT64x "\n", dst);
return false;
}
if (analysis->opt.jmpabove && dst < (fcn->addr < JMPTBL_MAXFCNSIZE ? 0 : fcn->addr - JMPTBL_MAXFCNSIZE)) {
if (analysis->opt.jmpabove && !UT64_SUB_OVFCHK(jmp_aop->addr, analysis->opt.jmptbl_maxoffset) &&
dst < jmp_aop->addr - analysis->opt.jmptbl_maxoffset) {
RZ_LOG_VERBOSE("Jump table target is too far away: 0x%" PFMT64x "\n", dst);
return false;
}
}
@ -985,7 +989,7 @@ static RzAnalysisBBEndCause run_basic_block_analysis(RzAnalysisTaskItem *item, R
RzAnalysisOp jmp_aop = { 0 };
ut64 jmptbl_addr = op.ptr;
ut64 casetbl_addr = op.ptr;
if (is_delta_pointer_table(analysis, fcn, op.addr, op.ptr, &jmptbl_addr, &casetbl_addr, &jmp_aop)) {
if (is_delta_pointer_table(analysis, op.addr, op.ptr, &jmptbl_addr, &casetbl_addr, &jmp_aop)) {
// we require both checks here since rz_analysis_get_jmptbl_info uses
// BB info of the final jmptbl jump, which is no present with
// is_delta_pointer_table just scanning ahead

View file

@ -2649,6 +2649,13 @@ static bool cb_analysis_jmptblmax(void *user, void *data) {
return true;
}
static bool cb_analysis_jmptblmaxoffset(void *user, void *data) {
RzCore *core = (RzCore *)user;
RzConfigNode *node = (RzConfigNode *)data;
core->analysis->opt.jmptbl_maxoffset = node->i_value > UT32_MAX ? UT32_MAX : node->i_value;
return true;
}
static bool cb_analysis_cjmpref(void *user, void *data) {
RzCore *core = (RzCore *)user;
RzConfigNode *node = (RzConfigNode *)data;
@ -2935,6 +2942,7 @@ RZ_API int rz_core_config_init(RzCore *core) {
SETCB("analysis.jmp.tbl", "true", &cb_analysis_jmptbl, "Analyze jump tables in switch statements");
SETICB("analysis.jmp.tblmax", 512, &cb_analysis_jmptblmax, "Maximum amount of entries to analyze in jump tables");
SETICB("analysis.jmp.tblmaxoffset", 4096, &cb_analysis_jmptblmaxoffset, "Maximum offset from the jump table jump instruction to consider it valid");
SETCB("analysis.jmp.cref", "false", &cb_analysis_cjmpref, "Create references for conditional jumps");
SETCB("analysis.jmp.ref", "true", &cb_analysis_jmpref, "Create references for unconditional jumps");

View file

@ -533,6 +533,7 @@ typedef struct rz_analysis_options_t {
int hpskip; // skip `mov reg,reg` and `lea reg,[reg]`
int jmptbl; // analyze jump tables
int jmptbl_maxcount; // maximum amount of entries to analyse in a jump table
ut32 jmptbl_maxoffset; // maximum offset from the jump table jump instruction to consider it valid
int nonull;
bool pushret; // analyze push+ret as jmp
bool armthumb; //