ut64 analyzeStackBased(RCore *core, Sdb *db, ut64 addr, RList *delayed_commands) { #define addCall(x) sdb_array_add_num (db, "calls", x, 0); #define addUcall(x) sdb_array_add_num (db, "ucalls", x, 0); #define addUjmp(x) sdb_array_add_num (db, "ujmps", x, 0); #define addCjmp(x) sdb_array_add_num (db, "cjmps", x, 0); #define addRet(x) sdb_array_add_num (db, "rets", x, 0); #define bbAddOpcode(x) sdb_array_insert_num (db, sdb_fmt ("bb.%"PFMT64x, addr+cur), -1, x, 0); ut64 oaddr = addr; ut64 *value = NULL; RAnalOp *op; int cur = 0; bool block_end = false; RStack *stack = r_stack_newf (10, free); addTarget (core, stack, db, addr); while (!r_stack_is_empty (stack)) { block_end = false; value = (ut64*) r_stack_pop (stack); if (!value) { eprintf ("Failed to pop next address from stack\n"); break; } addr = *value; free (value); cur = 0; while (!block_end) { op = r_core_anal_op (core, addr + cur, R_ANAL_OP_MASK_BASIC); if (!op || !op->mnemonic) { eprintf ("Cannot analyze opcode at %"PFMT64d"\n", addr+cur); oaddr = UT64_MAX; break; } if (op->mnemonic[0] == '?') { eprintf ("Cannot analyze opcode at %"PFMT64d"\n", addr+cur); oaddr = UT64_MAX; break; } bbAddOpcode (addr+cur); switch (op->type) { case R_ANAL_OP_TYPE_NOP: // skip nops if (cur == 0) { cur -= op->size; addr += op->size; oaddr += op->size; } break; case R_ANAL_OP_TYPE_CALL: /* A call instruction implies that the destination * is a new function unless the address is inside * the same range than the current function */ addCall (op->jump); r_list_append (delayed_commands, r_str_newf ("axC %"PFMT64d" %"PFMT64d, op->jump, addr + cur)); break; case R_ANAL_OP_TYPE_UCALL: case R_ANAL_OP_TYPE_ICALL: case R_ANAL_OP_TYPE_RCALL: case R_ANAL_OP_TYPE_IRCALL: /* unknown calls depend on ESIL or DEBUG tracing * information to know the destination, we can mark * those 'calls' for later adding tracepoints in * there to record all possible destinations */ addUcall (addr+cur); if (op->ptr != UT64_MAX) { r_list_append (delayed_commands, r_str_newf ("axC %"PFMT64d" %"PFMT64d, op->ptr, addr + cur)); } break; case R_ANAL_OP_TYPE_UJMP: case R_ANAL_OP_TYPE_RJMP: case R_ANAL_OP_TYPE_IJMP: case R_ANAL_OP_TYPE_IRJMP: /* an unknown jump use to go into computed destinations * outside the current function, but it may result * on an antidisasm trick */ addUjmp (addr + cur); /* An unknown jump breaks the basic blocks */ block_end = true; // XXX more investigation here break; case R_ANAL_OP_TYPE_TRAP: if (cur == 0) { // skip leading int3 cur -= op->size; addr += op->size; oaddr += op->size; } else { block_end = true; } break; case R_ANAL_OP_TYPE_RET: addRet (addr + cur); bbAdd (db, addr, addr + cur + op->size, UT64_MAX, UT64_MAX); block_end = true; break; case R_ANAL_OP_TYPE_CJMP: addCjmp (addr+cur); bbAdd (db, addr, addr + cur + op->size, op->jump, addr + cur + op->size); addTarget (core, stack, db, op->jump); addTarget (core, stack, db, addr + cur + op->size); block_end = true; r_list_append (delayed_commands, r_str_newf ("axc %"PFMT64d" %"PFMT64d, op->jump, addr + cur)); break; case R_ANAL_OP_TYPE_JMP: addUjmp (addr+cur); bbAdd (db, addr, addr + cur + op->size, op->jump, UT64_MAX); addTarget (core, stack, db, op->jump); block_end = true; r_list_append (delayed_commands, r_str_newf ("axc %"PFMT64d" %"PFMT64d, op->jump, addr + cur)); break; case R_ANAL_OP_TYPE_UNK: case R_ANAL_OP_TYPE_ILL: eprintf ("a2f: Invalid instruction\n"); block_end = true; break; default: if (op->ptr != UT64_MAX) { r_list_append (delayed_commands, r_str_newf ("axd %"PFMT64d" %"PFMT64d, op->ptr, addr + cur)); } break; } cur += op->size; r_anal_op_free (op); op = NULL; } } r_stack_free (stack); return oaddr; }
ut64 analyzeIterative (RCore *core, Sdb *db, ut64 addr) { #define addCall(x) sdb_array_add_num (db, "calls", x, 0); #define addUcall(x) sdb_array_add_num (db, "ucalls", x, 0); #define addUjmp(x) sdb_array_add_num (db, "ujmps", x, 0); #define addCjmp(x) sdb_array_add_num (db, "cjmps", x, 0); #define addRet(x) sdb_array_add_num (db, "rets", x, 0); #define bbAddOpcode(x) sdb_array_insert_num (db, sdb_fmt (0, "bb.%"PFMT64x, bb_begin), -1, x, 0); /* this loop creates basic blocks */ ut64 oaddr = addr; RAnalOp *op; int cur = 0; int fcn_size = 0; ut64 bb_end = addr; ut64 bb_begin = addr; eprintf ("-> 0x%08"PFMT64x"\n", addr); for (;;) { op = r_core_anal_op (core, addr + cur); if (!op || !op->mnemonic) { eprintf ("Cannot analyze opcode at %"PFMT64d"\n", addr+cur); break; } eprintf ("0x%08"PFMT64x" %s\n", addr + cur, op->mnemonic); if (op->mnemonic[0] == '?') { eprintf ("Cannot analyze opcode at %"PFMT64d"\n", addr+cur); break; } bb_end += op->size; fcn_size += op->size; bbAddOpcode (addr+cur); switch (op->type) { case R_ANAL_OP_TYPE_NOP: /* If placed at the beginning..just skip them */ if (cur == 0) { eprintf ("NOPSKIP %d\n", op->size); oaddr += op->size; bb_begin = addr = oaddr; fcn_size -= op->size; cur -= op->size; } break; case R_ANAL_OP_TYPE_CALL: /* A call instruction implies that the destination * is a new function unless the address is inside * the same range than the current function */ addCall (op->jump); // add call reference break; case R_ANAL_OP_TYPE_UCALL: /* unknown calls depend on ESIL or DEBUG tracing * information to know the destination, we can mark * those 'calls' for later adding tracepoints in * there to record all possible destinations */ addUcall (addr+cur); break; case R_ANAL_OP_TYPE_UJMP: /* an unknown jump use to go into computed destinations * outside the current function, but it may result * on an antidisasm trick */ addUjmp (addr+cur); /* An unknown jump breaks the basic blocks */ goto endOfFunction; case R_ANAL_OP_TYPE_TRAP: addRet (addr + cur); goto endOfFunction; case R_ANAL_OP_TYPE_RET: addRet (addr + cur); goto endOfFunction; case R_ANAL_OP_TYPE_CJMP: /* jumps use to go into the same function, so we*/ addCjmp (op->jump); bbAdd (db, bb_begin, bb_end, op->jump, bb_end); bb_begin = bb_end; break; case R_ANAL_OP_TYPE_JMP: /* jumps usually go to the same function, but they * can be used */ goto endOfFunction; case R_ANAL_OP_TYPE_UNK: eprintf ("Unknown instruction at 0x%08"PFMT64x"\n", addr+cur); goto endOfFunction; case R_ANAL_OP_TYPE_ILL: eprintf ("HLT\n"); goto endOfFunction; } cur += op->size; r_anal_op_free (op); op = NULL; } endOfFunction: r_anal_op_free (op); bbAdd (db, bb_begin, bb_end, UT64_MAX, UT64_MAX); return oaddr; }