/* radare - Apache 2.0 - Copyright 2013 - Adam Pridgen */ #include #include #include #include #include #include #ifdef IFDBG #undef IFDBG #endif #define DO_THE_DBG 0 #define IFDBG if(DO_THE_DBG) #define IFINT if(0) static void r_anal_ex_perform_pre_anal(RAnal *anal, RAnalState *state, ut64 addr); static void r_anal_ex_perform_pre_anal_op_cb(RAnal *anal, RAnalState *state, ut64 addr); static void r_anal_ex_perform_pre_anal_bb_cb(RAnal *anal, RAnalState *state, ut64 addr); //static void r_anal_ex_perform_pre_anal_fn_cb(RAnal *anal, RAnalState *state, ut64 addr); static void r_anal_ex_perform_post_anal(RAnal *anal, RAnalState *state, ut64 addr); static void r_anal_ex_perform_post_anal_op_cb(RAnal *anal, RAnalState *state, ut64 addr); static void r_anal_ex_perform_post_anal_bb_cb(RAnal *anal, RAnalState *state, ut64 addr); //static void r_anal_ex_perform_post_anal_fn_cb(RAnal *anal, RAnalState *state, ut64 addr); static void r_anal_ex_perform_revisit_bb_cb(RAnal *anal, RAnalState *state, ut64 addr); ut64 extract_code_op(ut64 ranal2_op_type); ut64 extract_load_store_op(ut64 ranal2_op_type); ut64 extract_unknown_op(ut64 ranal2_op_type); ut64 extract_bin_op(ut64 ranal2_op_type); static void r_anal_ex_perform_pre_anal(RAnal *anal, RAnalState *state, ut64 addr) { if (anal->cur && anal->cur->pre_anal) { anal->cur->pre_anal (anal, state, addr); } } static void r_anal_ex_perform_pre_anal_op_cb(RAnal *anal, RAnalState *state, ut64 addr) { if (anal->cur && anal->cur->pre_anal_op_cb) { anal->cur->pre_anal_op_cb (anal, state, addr); } } static void r_anal_ex_perform_pre_anal_bb_cb(RAnal *anal, RAnalState *state, ut64 addr) { if (anal->cur && anal->cur->pre_anal_bb_cb) { anal->cur->pre_anal_bb_cb (anal, state, addr); } } /*static void r_anal_ex_perform_pre_anal_fn_cb(RAnal *anal, RAnalState *state, ut64 addr) { if (anal->cur && anal->cur->pre_anal_fn_cb) { anal->cur->pre_anal_fn_cb (anal, state, addr); } }*/ static void r_anal_ex_perform_post_anal_op_cb(RAnal *anal, RAnalState *state, ut64 addr) { if (anal->cur && anal->cur->post_anal_op_cb) { anal->cur->post_anal_op_cb (anal, state, addr); } } static void r_anal_ex_perform_post_anal_bb_cb(RAnal *anal, RAnalState *state, ut64 addr) { if (anal->cur && anal->cur->post_anal_bb_cb) { anal->cur->post_anal_bb_cb (anal, state, addr); } } /*static void r_anal_ex_perform_post_anal_fn_cb(RAnal *anal, RAnalState *state, ut64 addr) { if (anal->cur && anal->cur->post_anal_fn_cb) { anal->cur->post_anal_fn_cb (anal, state, addr); } }*/ static void r_anal_ex_perform_post_anal(RAnal *anal, RAnalState *state, ut64 addr) { if (anal->cur && anal->cur->post_anal) { anal->cur->post_anal (anal, state, addr); } } static void r_anal_ex_perform_revisit_bb_cb(RAnal *anal, RAnalState *state, ut64 addr) { if (anal->cur && anal->cur->revisit_bb_anal) { anal->cur->revisit_bb_anal (anal, state, addr); } } R_API int r_anal_ex_bb_address_comparator(RAnalBlock *a, RAnalBlock *b){ if (a->addr == b->addr) { return 0; } if (a->addr < b->addr) { return -1; } // a->addr > b->addr return 1; } R_API int r_anal_ex_bb_head_comparator(RAnalBlock *a, RAnalBlock *b){ if (a->head == b->head) { return 0; } if (a->head < b->head) { return -1; } // a->head > b->head return 1; } R_API void r_anal_ex_clone_op_switch_to_bb (RAnalBlock *bb, RAnalOp *op) { RListIter *iter; RAnalCaseOp *caseop = NULL; if (bb && op && op->switch_op) { bb->switch_op = r_anal_switch_op_new (op->switch_op->addr, op->switch_op->min_val, op->switch_op->max_val); r_list_foreach (op->switch_op->cases, iter, caseop) { r_anal_switch_op_add_case (bb->switch_op, caseop->addr, caseop->value, caseop->jump); } } } R_API RAnalOp * r_anal_ex_get_op(RAnal *anal, RAnalState *state, ut64 addr) { RAnalOp *current_op = state->current_op; const ut8 * data; // current_op set in a prior stage if (current_op) { return current_op; } if (!anal->cur || (!anal->cur->op_from_buffer && !anal->cur->op)) { return NULL; } if (!r_anal_state_addr_is_valid(state, addr) || (anal->cur && (!anal->cur->op && !anal->cur->op_from_buffer))) { state->done = 1; return NULL; } data = r_anal_state_get_buf_by_addr(state, addr); if (anal->cur->op_from_buffer) { current_op = anal->cur->op_from_buffer (anal, addr, data, r_anal_state_get_len (state, addr)); } else { current_op = r_anal_op_new(); anal->cur->op (anal, current_op, addr, data, r_anal_state_get_len (state, addr)); } state->current_op = current_op; return current_op; } R_API RAnalBlock * r_anal_ex_get_bb(RAnal *anal, RAnalState *state, ut64 addr) { RAnalBlock *current_bb = state->current_bb; RAnalOp *op = state->current_op; // current_bb set before in a pre-analysis stage. if (current_bb) { return current_bb; } if (r_anal_state_addr_is_valid (state, addr) && !op) { op = r_anal_ex_get_op (anal, state, addr); } if (!op || !r_anal_state_addr_is_valid (state, addr)) { return NULL; } current_bb = r_anal_bb_new (); if (!current_bb) { return NULL; } r_anal_ex_op_to_bb (anal, state, current_bb, op); if (r_anal_op_is_eob (op)) { current_bb->type |= R_ANAL_BB_TYPE_LAST; } if (!current_bb->op_bytes) { current_bb->op_sz = state->current_op->size; current_bb->op_bytes = malloc (current_bb->op_sz); if (current_bb->op_bytes) { int buf_len = r_anal_state_get_len (state, addr); if (current_bb->op_sz > buf_len) { r_anal_bb_free (current_bb); return NULL; } memcpy (current_bb->op_bytes, r_anal_state_get_buf_by_addr (state, addr), current_bb->op_sz); } } state->current_bb = current_bb; // this can be overridden in a post_bb_anal_cb state->next_addr = addr + current_bb->op_sz; current_bb->op_sz = state->current_op->size; return current_bb; } R_API void r_anal_ex_update_bb_cfg_head_tail( RAnalBlock *start, RAnalBlock * head, RAnalBlock * tail ) { RAnalBlock *bb = start; if (bb) { bb->head = head; bb->tail = tail; } if (bb && bb->next){ bb->head = head; bb->tail = tail; do { bb->next->prev = bb; bb = bb->next; bb->head = head; bb->tail = tail; } while (bb->next && !(bb->type & R_ANAL_BB_TYPE_TAIL)); } } R_API RList* r_anal_ex_perform_analysis(RAnal *anal, RAnalState *state, ut64 addr) { if (anal && anal->cur && anal->cur->analysis_algorithm) { return anal->cur->analysis_algorithm (anal, state, addr); } return r_anal_ex_analysis_driver (anal, state, addr); } R_API RList* r_anal_ex_analysis_driver(RAnal *anal, RAnalState *state, ut64 addr ) { ut64 consumed_iter = 0; ut64 bytes_consumed = 0, len = r_anal_state_get_len (state, addr); RAnalBlock *pcurrent_bb = state->current_bb, *pcurrent_head = state->current_bb_head, *past_bb = NULL; RAnalOp *pcurrent_op = state->current_op; ut64 backup_addr = state->current_addr; state->current_addr = addr; RList *bb_list = r_anal_bb_list_new (); if (state->done) { return bb_list; } state->current_bb_head = NULL; state->current_bb = NULL; state->current_op = NULL; r_anal_ex_perform_pre_anal (anal, state, state->current_addr); while (!state->done && bytes_consumed < len) { state->current_bb = r_anal_state_search_bb (state, state->current_addr); // check state for bb if (state->current_bb) { // TODO something special should happen here. r_anal_ex_perform_revisit_bb_cb (anal, state, state->current_addr); consumed_iter += state->current_bb->op_sz; bytes_consumed += state->current_bb->op_sz; if (state->done) { break; } continue; } r_anal_ex_perform_pre_anal_op_cb (anal, state, state->current_addr); if (state->done) { break; } r_anal_ex_get_op (anal, state, state->current_addr); r_anal_ex_perform_post_anal_op_cb (anal, state, state->current_addr); if (state->done) { break; } r_anal_ex_perform_pre_anal_bb_cb (anal, state, state->current_addr); if (state->done) { break; } if (!r_anal_ex_get_bb (anal, state, state->current_addr)) { break; } if (!state->current_bb_head) { state->current_bb_head = state->current_bb; if (state->current_bb_head) { state->current_bb_head->type |= R_ANAL_BB_TYPE_HEAD; } } if (past_bb) { past_bb->next = state->current_bb; state->current_bb->prev = past_bb; } past_bb = state->current_bb; //state->current_bb is shared in two list and one ht!!! //source of UAF this should be rewritten to avoid such errors r_anal_state_insert_bb (state, state->current_bb); r_list_append (bb_list, state->current_bb); r_anal_ex_perform_post_anal_bb_cb (anal, state, state->current_addr); if (state->done) { break; } if (state->current_bb) { bytes_consumed += state->current_bb->op_sz; consumed_iter += state->current_bb->op_sz; } state->current_addr = state->next_addr; r_anal_op_free (state->current_op); state->current_op = NULL; state->current_bb = NULL; if (!consumed_iter) { eprintf ("No bytes consumed, bailing!\n"); break; } consumed_iter = 0; } r_anal_op_free (state->current_op); r_anal_ex_perform_post_anal (anal, state, addr); state->current_op = pcurrent_op; state->current_bb = pcurrent_bb; state->current_bb_head = pcurrent_head; state->current_addr = backup_addr; return bb_list; } R_API void r_anal_ex_op_to_bb(RAnal *anal, RAnalState *state, RAnalBlock *bb, RAnalOp *op) { //ut64 cnd_jmp = (R_ANAL_EX_COND_OP | R_ANAL_EX_CODEOP_JMP); bb->addr = op->addr; bb->size = op->size; bb->type2 = op->type2; bb->type = r_anal_ex_map_anal_ex_to_anal_bb_type ( op->type2 ); bb->fail = op->fail; bb->jump = op->jump; bb->conditional = R_ANAL_EX_COND_OP & op->type2 ? R_ANAL_OP_TYPE_COND : 0; if (r_anal_op_is_eob (op)) { bb->type |= R_ANAL_BB_TYPE_LAST; } r_anal_ex_clone_op_switch_to_bb (bb, op); } R_API ut64 r_anal_ex_map_anal_ex_to_anal_bb_type (ut64 ranal2_op_type) { ut64 bb_type = 0; ut64 conditional = (R_ANAL_EX_COND_OP & ranal2_op_type)? R_ANAL_OP_TYPE_COND : 0; ut64 code_op_val = ranal2_op_type & (R_ANAL_EX_CODE_OP | 0x1FF); if (conditional) bb_type |= R_ANAL_BB_TYPE_COND; if (ranal2_op_type & R_ANAL_EX_LOAD_OP) bb_type |= R_ANAL_BB_TYPE_LD; if (ranal2_op_type & R_ANAL_EX_BIN_OP) bb_type |= R_ANAL_BB_TYPE_BINOP; if (ranal2_op_type & R_ANAL_EX_LOAD_OP) bb_type |= R_ANAL_BB_TYPE_LD; if (ranal2_op_type & R_ANAL_EX_STORE_OP) bb_type |= R_ANAL_BB_TYPE_ST; /* mark bb with a comparison */ if (ranal2_op_type & R_ANAL_EX_BINOP_CMP) bb_type |= R_ANAL_BB_TYPE_CMP; /* change in control flow here */ if (code_op_val & R_ANAL_EX_CODEOP_JMP) { bb_type |= R_ANAL_BB_TYPE_JMP; bb_type |= R_ANAL_BB_TYPE_TAIL; } else if (code_op_val & R_ANAL_EX_CODEOP_CALL) { bb_type |= R_ANAL_BB_TYPE_CALL; bb_type |= R_ANAL_BB_TYPE_TAIL; } else if ( code_op_val & R_ANAL_EX_CODEOP_SWITCH) { bb_type |= R_ANAL_BB_TYPE_SWITCH; bb_type |= R_ANAL_BB_TYPE_TAIL; } else if (code_op_val & R_ANAL_EX_CODEOP_LEAVE || code_op_val & R_ANAL_EX_CODEOP_RET ) { bb_type |= R_ANAL_BB_TYPE_RET; bb_type |= R_ANAL_BB_TYPE_LAST; bb_type |= R_ANAL_BB_TYPE_TAIL; } if ( ranal2_op_type & R_ANAL_EX_UNK_OP && code_op_val & R_ANAL_EX_CODEOP_JMP) bb_type |= R_ANAL_BB_TYPE_FOOT; if ( conditional && code_op_val & R_ANAL_EX_CODEOP_JMP) bb_type |= R_ANAL_BB_TYPE_BODY; return bb_type; } R_API int r_anal_ex_is_op_type_eop(ut64 x) { ut8 result = (x & R_ANAL_EX_CODE_OP) ? 1 : 0; return result && ( (x & R_ANAL_EX_CODEOP_LEAVE) == R_ANAL_EX_CODEOP_LEAVE || (x & R_ANAL_EX_CODEOP_RET) == R_ANAL_EX_CODEOP_RET || (x & R_ANAL_EX_CODEOP_JMP) == R_ANAL_EX_CODEOP_JMP || (x & R_ANAL_EX_CODEOP_SWITCH) == R_ANAL_EX_CODEOP_SWITCH); } ut64 extract_code_op(ut64 ranal2_op_type) { ut64 conditional = R_ANAL_EX_COND_OP & ranal2_op_type ? R_ANAL_OP_TYPE_COND : 0; ut64 code_op_val = ranal2_op_type & (R_ANAL_EX_CODE_OP | 0x1FF); switch (code_op_val) { case R_ANAL_EX_CODEOP_CALL : return conditional | R_ANAL_OP_TYPE_CALL; case R_ANAL_EX_CODEOP_JMP : return conditional | R_ANAL_OP_TYPE_JMP; case R_ANAL_EX_CODEOP_RET : return conditional | R_ANAL_OP_TYPE_RET; case R_ANAL_EX_CODEOP_LEAVE: return R_ANAL_OP_TYPE_LEAVE; case R_ANAL_EX_CODEOP_SWI : return R_ANAL_OP_TYPE_SWI; case R_ANAL_EX_CODEOP_TRAP : return R_ANAL_OP_TYPE_TRAP; case R_ANAL_EX_CODEOP_SWITCH: return R_ANAL_OP_TYPE_SWITCH; } return R_ANAL_OP_TYPE_UNK; } ut64 extract_load_store_op(ut64 ranal2_op_type) { if ( (ranal2_op_type & R_ANAL_EX_LDST_OP_PUSH) == R_ANAL_EX_LDST_OP_PUSH) { return R_ANAL_OP_TYPE_PUSH; } if ( (ranal2_op_type & R_ANAL_EX_LDST_OP_POP) == R_ANAL_EX_LDST_OP_POP) { return R_ANAL_OP_TYPE_POP; } if ( (ranal2_op_type & R_ANAL_EX_LDST_OP_MOV) == R_ANAL_EX_LDST_OP_MOV) { return R_ANAL_OP_TYPE_MOV; } if ( (ranal2_op_type & R_ANAL_EX_LDST_OP_EFF_ADDR) == R_ANAL_EX_LDST_OP_EFF_ADDR) { return R_ANAL_OP_TYPE_LEA; } return R_ANAL_OP_TYPE_UNK; } ut64 extract_unknown_op(ut64 ranal2_op_type) { if ( (ranal2_op_type & R_ANAL_EX_CODEOP_JMP) == R_ANAL_EX_CODEOP_JMP ) return R_ANAL_OP_TYPE_UJMP; if ( (ranal2_op_type & R_ANAL_EX_CODEOP_CALL) == R_ANAL_EX_CODEOP_CALL) return R_ANAL_OP_TYPE_UCALL; if ( (ranal2_op_type & R_ANAL_EX_LDST_OP_PUSH) == R_ANAL_EX_LDST_OP_PUSH) return R_ANAL_OP_TYPE_UPUSH; return R_ANAL_OP_TYPE_UNK; } ut64 extract_bin_op(ut64 ranal2_op_type) { ut64 bin_op_val = ranal2_op_type & (R_ANAL_EX_BIN_OP | 0x80000); switch (bin_op_val) { case R_ANAL_EX_BINOP_XCHG:return R_ANAL_OP_TYPE_XCHG; case R_ANAL_EX_BINOP_CMP: return R_ANAL_OP_TYPE_CMP; case R_ANAL_EX_BINOP_ADD: return R_ANAL_OP_TYPE_ADD; case R_ANAL_EX_BINOP_SUB: return R_ANAL_OP_TYPE_SUB; case R_ANAL_EX_BINOP_MUL: return R_ANAL_OP_TYPE_MUL; case R_ANAL_EX_BINOP_DIV: return R_ANAL_OP_TYPE_DIV; case R_ANAL_EX_BINOP_SHR: return R_ANAL_OP_TYPE_SHR; case R_ANAL_EX_BINOP_SHL: return R_ANAL_OP_TYPE_SHL; case R_ANAL_EX_BINOP_SAL: return R_ANAL_OP_TYPE_SAL; case R_ANAL_EX_BINOP_SAR: return R_ANAL_OP_TYPE_SAR; case R_ANAL_EX_BINOP_OR : return R_ANAL_OP_TYPE_OR; case R_ANAL_EX_BINOP_AND: return R_ANAL_OP_TYPE_AND; case R_ANAL_EX_BINOP_XOR: return R_ANAL_OP_TYPE_XOR; case R_ANAL_EX_BINOP_NOT: return R_ANAL_OP_TYPE_NOT; case R_ANAL_EX_BINOP_MOD: return R_ANAL_OP_TYPE_MOD; case R_ANAL_EX_BINOP_ROR: return R_ANAL_OP_TYPE_ROR; case R_ANAL_EX_BINOP_ROL: return R_ANAL_OP_TYPE_ROL; default: break; } return R_ANAL_OP_TYPE_UNK; } R_API ut64 r_anal_ex_map_anal_ex_to_anal_op_type (ut64 ranal2_op_type) { switch (ranal2_op_type) { case R_ANAL_EX_NULL_OP: return R_ANAL_OP_TYPE_NULL; case R_ANAL_EX_NOP: return R_ANAL_OP_TYPE_NOP; case R_ANAL_EX_ILL_OP: return R_ANAL_OP_TYPE_ILL; default: break; } if (ranal2_op_type & R_ANAL_EX_UNK_OP) { return extract_unknown_op(ranal2_op_type); } if (ranal2_op_type & R_ANAL_EX_CODE_OP) { return extract_code_op(ranal2_op_type); } if (ranal2_op_type & R_ANAL_EX_REP_OP) { ut64 ret = r_anal_ex_map_anal_ex_to_anal_op_type (ranal2_op_type & ~R_ANAL_EX_REP_OP); return R_ANAL_OP_TYPE_REP | ret; } if (ranal2_op_type & (R_ANAL_EX_LOAD_OP | R_ANAL_EX_STORE_OP)) { return extract_load_store_op(ranal2_op_type); } if (ranal2_op_type & R_ANAL_EX_BIN_OP) { return extract_bin_op(ranal2_op_type); } return R_ANAL_OP_TYPE_UNK; }