Exemple #1
0
    def optimize(self, blk: mblock_t, ins: minsn_t) -> bool:
        # optimizer_log.info("Trying to optimize {0}".format(format_minsn_t(ins)))
        for ins_optimizer in self.instruction_optimizers:
            self._last_optimizer_tried = ins_optimizer
            new_ins = ins_optimizer.get_optimized_instruction(blk, ins)

            if new_ins is not None:
                if not check_ins_mop_size_are_ok(new_ins):
                    if check_ins_mop_size_are_ok(ins):
                        main_logger.error(
                            "Invalid optimized instruction: {0} (original was {1})"
                            .format(format_minsn_t(new_ins),
                                    format_minsn_t(ins)))
                    else:
                        main_logger.error(
                            "Invalid original instruction : {0} (original was {1})"
                            .format(format_minsn_t(new_ins),
                                    format_minsn_t(ins)))
                else:
                    ins.swap(new_ins)
                    self.optimizer_usage_info[ins_optimizer.name] += 1
                    if self.generate_z3_code:
                        try:
                            log_z3_instructions(new_ins, ins)
                        except KeyError:
                            pass
                    return True

        self.analyzer.analyze(blk, ins)
        return False
Exemple #2
0
 def eval_instruction(self,
                      blk: mblock_t,
                      ins: minsn_t,
                      environment: Union[None, MicroCodeEnvironment] = None,
                      raise_exception: bool = False) -> bool:
     try:
         if environment is None:
             environment = self.global_environment
         emulator_log.info(
             "Evaluating microcode instruction : '{0}'".format(
                 format_minsn_t(ins)))
         if ins is None:
             return False
         self._eval_instruction_and_update_environment(
             blk, ins, environment)
         return True
     except EmulationException as e:
         emulator_log.warning(
             "Can't evaluate instruction: '{0}': {1}".format(
                 format_minsn_t(ins), e))
         if raise_exception:
             raise e
     except Exception as e:
         emulator_log.warning(
             "Error during evaluation of: '{0}': {1}".format(
                 format_minsn_t(ins), e))
         if raise_exception:
             raise e
     return False
Exemple #3
0
    def print_info(self, detailed_info=False):
        formatted_mop_searched_list = [
            format_mop_t(x) for x in self.searched_mop_list
        ]
        tmp = ", ".join([
            "{0}={1}".format(formatted_mop, self.get_mop_constant_value(mop))
            for formatted_mop, mop in zip(formatted_mop_searched_list,
                                          self.searched_mop_list)
        ])
        logger.info("MopHistory: resolved={0}, path={1}, mops={2}".format(
            self.is_resolved(), self.block_serial_path, tmp))
        if detailed_info:
            str_mop_list = "['" + "', '".join(
                formatted_mop_searched_list) + "']"
            if len(self.block_path) == 0:
                logger.info(
                    "MopHistory for {0} => nothing".format(str_mop_list))
                return

            end_blk = self.block_path[-1]
            end_ins = end_blk.tail
            if self.history[-1].ins_list:
                end_ins = self.history[-1].ins_list[-1]

            if end_ins:
                logger.info("MopHistory for {0} {1}.{2}".format(
                    str_mop_list, end_blk.serial, format_minsn_t(end_ins)))
            else:
                logger.info("MopHistory for '{0}' {1}.tail".format(
                    str_mop_list, end_blk.serial))
            logger.info("  path {0}".format(self.block_serial_path))
            for blk_info in self.history:
                for blk_ins in blk_info.ins_list:
                    logger.info("   {0}.{1}".format(blk_info.blk.serial,
                                                    format_minsn_t(blk_ins)))
Exemple #4
0
    def get_optimized_instruction(self, blk: mblock_t,
                                  ins: minsn_t) -> Union[None, minsn_t]:
        if blk is not None:
            self.cur_maturity = blk.mba.maturity
        if self.cur_maturity not in self.maturities:
            return None
        tmp = minsn_to_ast(ins)
        if tmp is None:
            return None

        all_matchs = self.pattern_storage.get_matching_rule_pattern_info(tmp)
        for rule_pattern_info in all_matchs:
            try:
                new_ins = rule_pattern_info.rule.check_pattern_and_replace(
                    rule_pattern_info.pattern, tmp)
                if new_ins is not None:
                    self.rules_usage_info[rule_pattern_info.rule.name] += 1
                    optimizer_logger.info("Rule {0} matched:".format(
                        rule_pattern_info.rule.name))
                    optimizer_logger.info("  orig: {0}".format(
                        format_minsn_t(ins)))
                    optimizer_logger.info("  new : {0}".format(
                        format_minsn_t(new_ins)))
                    return new_ins
            except RuntimeError as e:
                optimizer_logger.error(
                    "Error during rule {0} for instruction {1}: {2}".format(
                        rule_pattern_info.rule, format_minsn_t(ins), e))
        return None
Exemple #5
0
    def func(self, blk: mblock_t, ins: minsn_t) -> bool:
        self.log_info_on_input(blk, ins)
        try:
            optimization_performed = self.optimize(blk, ins)

            if not optimization_performed:
                optimization_performed = ins.for_all_insns(
                    self.instruction_visitor)

            if optimization_performed:
                ins.optimize_solo()

                if blk is not None:
                    blk.mark_lists_dirty()
                    blk.mba.verify(True)

            return optimization_performed
        except RuntimeError as e:
            optimizer_logger.error(
                "RuntimeError while optimizing ins {0} with {1}: {2}".format(
                    format_minsn_t(ins), self._last_optimizer_tried, e))
        except D810Exception as e:
            optimizer_logger.error(
                "D810Exception while optimizing ins {0} with {1}: {2}".format(
                    format_minsn_t(ins), self._last_optimizer_tried, e))
        return False
    def fix_successor(self, fake_loop_block: mblock_t, pred: mblock_t,
                      pred_comparison_values: List[int]) -> bool:
        if len(pred_comparison_values) == 0:
            return False
        jmp_ins = fake_loop_block.tail
        compared_value = jmp_ins.r.nnn.value
        jmp_taken = False
        jmp_not_taken = False
        dst_serial = None
        if jmp_ins.opcode == m_jz:
            jmp_taken = all([
                possible_value == compared_value
                for possible_value in pred_comparison_values
            ])

            jmp_not_taken = all([
                possible_value != compared_value
                for possible_value in pred_comparison_values
            ])
        elif jmp_ins.opcode == m_jnz:
            jmp_taken = all([
                possible_value != compared_value
                for possible_value in pred_comparison_values
            ])
            jmp_not_taken = all([
                possible_value == compared_value
                for possible_value in pred_comparison_values
            ])
        # TODO: handles other jumps cases
        if jmp_taken:
            unflat_logger.info(
                "It seems that '{0}' is always taken when coming from {1}: {2}"
                .format(format_minsn_t(jmp_ins), pred.serial,
                        pred_comparison_values))
            dst_serial = jmp_ins.d.b
        if jmp_not_taken:
            unflat_logger.info(
                "It seems that '{0}' is never taken when coming from {1}: {2}".
                format(format_minsn_t(jmp_ins), pred.serial,
                       pred_comparison_values))
            dst_serial = fake_loop_block.serial + 1
        if dst_serial is None:
            unflat_logger.debug("Jump seems legit '{0}' from {1}: {2}".format(
                format_minsn_t(jmp_ins), pred.serial, pred_comparison_values))
            return False
        dump_microcode_for_debug(
            self.mba, self.log_dir,
            "{0}_before_fake_jump".format(self.cur_maturity_pass))
        unflat_logger.info(
            "Making pred {0} with value {1} goto {2} ({3})".format(
                pred.serial, pred_comparison_values, dst_serial,
                format_minsn_t(jmp_ins)))
        dump_microcode_for_debug(
            self.mba, self.log_dir,
            "{0}_after_fake_jump".format(self.cur_maturity_pass))
        return change_1way_block_successor(pred, dst_serial)
Exemple #7
0
 def sort_predecessors(self, blk):
     # this function sorts the blk predecessors into three list:
     # - A list of predecessors where the jump is always taken
     # - A list of predecessors where the jump is never taken
     # - A list of predecessors where we don't know
     pred_jmp_always_taken = []
     pred_jmp_never_taken = []
     pred_jmp_unk = []
     op_compared = mop_t(blk.tail.l)
     blk_preset_list = [x for x in blk.predset]
     for pred_serial in blk_preset_list:
         cmp_variable_tracker = MopTracker([op_compared],
                                           max_nb_block=100,
                                           max_path=1000)
         cmp_variable_tracker.reset()
         pred_blk = blk.mba.get_mblock(pred_serial)
         pred_histories = cmp_variable_tracker.search_backward(
             pred_blk, pred_blk.tail)
         pred_values = get_all_possibles_values(pred_histories,
                                                [op_compared])
         pred_values = [x[0] for x in pred_values]
         unflat_logger.info(
             "Pred {0} has {1} possible path ({2} different cst): {3}".
             format(pred_blk.serial, len(pred_values),
                    len(set(pred_values)), pred_values))
         if None in pred_values:
             pred_jmp_unk.append(pred_blk)
             continue
         is_jmp_always_taken, is_jmp_never_taken = self.is_jump_taken(
             blk, pred_values)
         if is_jmp_always_taken and is_jmp_never_taken:
             # this should never happen
             unflat_logger.error(
                 "It seems that I am stupid: '{0}' is always taken and not taken when coming from {1}: {2}"
                 .format(format_minsn_t(blk.tail), pred_blk.serial,
                         pred_values))
             pred_jmp_unk.append(pred_blk)
             continue
         if is_jmp_always_taken:
             unflat_logger.info(
                 "It seems that '{0}' is always taken when coming from {1}: {2}"
                 .format(format_minsn_t(blk.tail), pred_blk.serial,
                         pred_values))
             pred_jmp_always_taken.append(pred_blk)
         if is_jmp_never_taken:
             unflat_logger.info(
                 "It seems that '{0}' is never taken when coming from {1}: {2}"
                 .format(format_minsn_t(blk.tail), pred_blk.serial,
                         pred_values))
             pred_jmp_never_taken.append(pred_blk)
     return pred_jmp_always_taken, pred_jmp_never_taken, pred_jmp_unk
Exemple #8
0
    def simplify(self, ins):
        if ins.opcode not in [m_add, m_sub]:
            return None
        self.formatted_ins = format_minsn_t(ins)
        self.add_non_cst_mop_list = []
        self.add_cst_mop_list = []
        self.sub_non_cst_mop_list = []
        self.sub_cst_mop_list = []
        self.add_mop(0, ins.l)
        if ins.opcode == m_add:
            self.add_mop(0, ins.r)
        else:
            self.add_mop(1, ins.r)

        self._is_instruction_simplified = False
        final_add_list, final_sub_list, final_add_cst_list, final_sub_cst_list = self.do_simplification(
        )
        if not self._is_instruction_simplified:
            return None

        simplified_ins = self.create_new_chain(ins, final_add_list,
                                               final_sub_list,
                                               final_add_cst_list,
                                               final_sub_cst_list)

        return simplified_ins
Exemple #9
0
 def _eval_call(self, ins: minsn_t,
                environment: MicroCodeEnvironment) -> Union[None, int]:
     # TODO: implement
     emulator_log.warning(
         "Evaluation of {0} not implemented: bypassing".format(
             format_minsn_t(ins)))
     return None
Exemple #10
0
 def check_if_possible_pattern(self, test_ast):
     patterns = get_possible_patterns(test_ast,
                                      min_nb_use=2,
                                      ref_ast_info_by_index=None,
                                      max_nb_pattern=64)
     for pattern in patterns:
         leaf_info_list, cst_leaf_values, opcodes = pattern.get_information(
         )
         leaf_nb_use = [
             leaf_info.number_of_use for leaf_info in leaf_info_list
         ]
         if not (self.min_nb_var <= len(leaf_info_list) <= self.max_nb_var):
             continue
         if not (self.min_nb_diff_opcodes <= len(set(opcodes)) <=
                 self.max_nb_diff_opcodes):
             continue
         if not (min(leaf_nb_use) >= 2):
             continue
         ins = pattern.mop.d
         self.log_info("IR: 0x{0:x} - {1}".format(ins.ea,
                                                  format_minsn_t(ins)))
         for leaf_info in leaf_info_list:
             self.log_info("  {0} -> {1}".format(
                 leaf_info.ast, format_mop_t(leaf_info.ast.mop)))
         self.log_info("Pattern: {0}".format(pattern))
         self.log_info("AstNode: {0}\n".format(pattern.get_pattern()))
         return True
     return False
Exemple #11
0
 def get_optimized_instruction(self, blk: mblock_t, ins: minsn_t):
     if blk is not None:
         self.cur_maturity = blk.mba.maturity
     # if self.cur_maturity not in self.maturities:
     #     return None
     for rule in self.rules:
         if self.cur_maturity not in rule.maturities:
             continue
         try:
             new_ins = rule.check_and_replace(blk, ins)
             if new_ins is not None:
                 self.rules_usage_info[rule.name] += 1
                 optimizer_logger.info("Rule {0} matched:".format(rule.name))
                 optimizer_logger.info("  orig: {0}".format(format_minsn_t(ins)))
                 optimizer_logger.info("  new : {0}".format(format_minsn_t(new_ins)))
                 return new_ins
         except RuntimeError as e:
             optimizer_logger.error("Runtime error during rule {0} for instruction {1}: {2}".format(rule, format_minsn_t(ins), e))
         except D810Exception as e:
             optimizer_logger.error("D810Exception during rule {0} for instruction {1}: {2}".format(rule, format_minsn_t(ins), e))
     return None
Exemple #12
0
    def _eval_control_flow_instruction(
            self, ins: minsn_t, environment: MicroCodeEnvironment) -> bool:
        if ins.opcode not in CONTROL_FLOW_OPCODES:
            return False
        cur_blk = environment.cur_blk
        if cur_blk is None:
            raise EmulationException(
                "Can't evaluate control flow instruction with null block:  '{0}'"
                .format(format_minsn_t(ins)))

        next_blk_serial = self._eval_conditional_jump(ins, environment)
        if next_blk_serial is not None:
            next_blk = cur_blk.mba.get_mblock(next_blk_serial)
            next_ins = next_blk.head
            environment.set_next_flow(next_blk, next_ins)
            return True

        if ins.opcode == m_goto:
            next_blk_serial = self._get_blk_serial(ins.l)
        elif ins.opcode == m_jtbl:
            left_value = self.eval(ins.l, environment)
            cases = ins.r.c
            # Initialize to default case
            next_blk_serial = [x for x in cases.targets][-1]
            for possible_values, target_block_serial in zip(
                    cases.values, cases.targets):
                for test_value in possible_values:
                    if left_value == test_value:
                        next_blk_serial = target_block_serial
                        break
        elif ins.opcode == m_ijmp:
            ijmp_dest_ea = self.eval(ins.d, environment)
            dest_block_serials = get_block_serials_by_address(
                environment.cur_blk.mba, ijmp_dest_ea)
            if len(dest_block_serials) == 0:
                raise EmulationIndirectJumpException(
                    "No blocks found at address {0:x}".format(ijmp_dest_ea),
                    ijmp_dest_ea, dest_block_serials)

            if len(dest_block_serials) > 1:
                raise EmulationIndirectJumpException(
                    "Multiple blocks at address {0:x}: {1}".format(
                        ijmp_dest_ea, dest_block_serials), ijmp_dest_ea,
                    dest_block_serials)
            next_blk_serial = dest_block_serials[0]

        if next_blk_serial is None:
            return False
        next_blk = cur_blk.mba.get_mblock(next_blk_serial)
        next_ins = next_blk.head
        environment.set_next_flow(next_blk, next_ins)
        return True
Exemple #13
0
def log_z3_instructions(original_ins: minsn_t, new_ins: minsn_t):
    if not Z3_INSTALLED:
        raise D810Z3Exception("Z3 is not installed")
    orig_mba_tree = minsn_to_ast(original_ins)
    new_mba_tree = minsn_to_ast(new_ins)
    if orig_mba_tree is None or new_mba_tree is None:
        return None
    orig_leaf_list = orig_mba_tree.get_leaf_list()
    new_leaf_list = new_mba_tree.get_leaf_list()

    var_def_list = rename_leafs(orig_leaf_list + new_leaf_list)

    z3_file_logger.info("print('Testing: {0} == {1}')".format(
        format_minsn_t(original_ins), format_minsn_t(new_ins)))
    for var_def in var_def_list:
        z3_file_logger.info("{0}".format(var_def))

    removed_xdu = "{0}".format(orig_mba_tree).replace("xdu", "")
    z3_file_logger.info("original_expr = {0}".format(removed_xdu))
    removed_xdu = "{0}".format(new_mba_tree).replace("xdu", "")
    z3_file_logger.info("new_expr = {0}".format(removed_xdu))
    z3_file_logger.info("prove(original_expr == new_expr)\n")
Exemple #14
0
 def analyze_instruction(self, blk, ins):
     if self.cur_maturity not in self.maturities:
         return None
     formatted_ins = str(format_minsn_t(ins))
     if formatted_ins in self.cur_ins_guessed:
         return False
     tmp = minsn_to_ast(ins)
     if tmp is None:
         return False
     is_good_candidate = self.check_if_possible_pattern(tmp)
     if is_good_candidate:
         self.cur_ins_guessed[self.cur_index] = formatted_ins
         self.cur_index = (self.cur_index + 1) % self.max_index
     return is_good_candidate
Exemple #15
0
 def optimize(self, blk: mblock_t) -> bool:
     if not is_conditional_jump(blk):
         return False
     left_ast = mop_to_ast(blk.tail.l)
     right_ast = mop_to_ast(blk.tail.r)
     for rule in self.rules:
         try:
             new_ins = rule.check_pattern_and_replace(blk, blk.tail, left_ast, right_ast)
             if new_ins:
                 optimizer_logger.info("Rule {0} matched:".format(rule.name))
                 optimizer_logger.info("  orig: {0}".format(format_minsn_t(blk.tail)))
                 optimizer_logger.info("  new : {0}".format(format_minsn_t(new_ins)))
                 if new_ins.opcode == m_goto:
                     make_2way_block_goto(blk, new_ins.d.b)
                 else:
                     change_2way_block_conditional_successor(blk, new_ins.d.b)
                     blk.make_nop(blk.tail)
                     blk.insert_into_block(new_ins, blk.tail)
                     return True
         except RuntimeError as e:
             optimizer_logger.error("Error during rule {0} for instruction {1}: {2}"
                                    .format(rule, format_minsn_t(blk.tail), e))
     return False
Exemple #16
0
    def analyze(self, blk: mblock_t, ins: minsn_t):
        if blk is not None:
            self.cur_maturity = blk.mba.maturity

        if self.cur_maturity not in self.maturities:
            return None

        for rule in self.rules:
            try:
                rule.analyze_instruction(blk, ins)
            except RuntimeError:
                optimizer_logger.error(
                    "error during rule {0} for instruction {1}".format(
                        rule, format_minsn_t(ins)))
        return None
Exemple #17
0
 def set_cur_flow(self, cur_blk: mblock_t, cur_ins: minsn_t):
     self.cur_blk = cur_blk
     self.cur_ins = cur_ins
     self.next_blk = cur_blk
     if self.cur_ins is None:
         self.next_blk = self.cur_blk.mba.get_mblock(self.cur_blk.serial +
                                                     1)
         self.next_ins = self.next_blk.head
     else:
         self.next_ins = self.cur_ins.next
         if self.next_ins is None:
             self.next_blk = self.cur_blk.mba.get_mblock(
                 self.cur_blk.serial + 1)
             self.next_ins = self.next_blk.head
     emulator_log.debug("Setting next block {0} and next ins {1}".format(
         self.next_blk.serial, format_minsn_t(self.next_ins)))
Exemple #18
0
    def simplify(self, ins):
        self.res_mop_size = ins.d.size
        if ins.opcode != self.opcode:
            return None

        self.formatted_ins = format_minsn_t(ins)
        self.non_cst_mop_list = []
        self.cst_mop_list = []
        self.add_mop(ins.l)
        self.add_mop(ins.r)

        self._is_instruction_simplified = False
        final_mop_list = self.do_simplification()
        if not self._is_instruction_simplified:
            return None

        return self.create_new_chain(ins, final_mop_list)
Exemple #19
0
 def analyze_blk(self, blk: mblock_t) -> int:
     if (blk.tail is None) or blk.tail.opcode not in JMP_OPCODE_HANDLED:
         return 0
     if blk.tail.r.t != mop_n:
         return 0
     unflat_logger.info(
         "Checking if block {0} can be simplified: {1}".format(
             blk.serial, format_minsn_t(blk.tail)))
     pred_jmp_always_taken, pred_jmp_never_taken, pred_jmp_unk = self.sort_predecessors(
         blk)
     unflat_logger.info(
         "Block {0} has {1} preds: {2} always jmp, {3} never jmp, {4} unk".
         format(blk.serial, blk.npred(), len(pred_jmp_always_taken),
                len(pred_jmp_never_taken), len(pred_jmp_unk)))
     nb_change = 0
     if len(pred_jmp_always_taken) > 0:
         dump_microcode_for_debug(
             self.mba, self.log_dir,
             "{0}_{1}_before_jmp_always_fix".format(self.cur_maturity_pass,
                                                    blk.serial))
         for pred_blk in pred_jmp_always_taken:
             new_jmp_block, new_default_block = duplicate_block(blk)
             make_2way_block_goto(new_jmp_block, blk.tail.d.b)
             update_blk_successor(pred_blk, blk.serial,
                                  new_jmp_block.serial)
         dump_microcode_for_debug(
             self.mba, self.log_dir,
             "{0}_{1}_after_jmp_always_fix".format(self.cur_maturity_pass,
                                                   blk.serial))
         nb_change += len(pred_jmp_always_taken)
     if len(pred_jmp_never_taken) > 0:
         dump_microcode_for_debug(
             self.mba, self.log_dir,
             "{0}_{1}_before_jmp_never_fix".format(self.cur_maturity_pass,
                                                   blk.serial))
         for pred_blk in pred_jmp_never_taken:
             new_jmp_block, new_default_block = duplicate_block(blk)
             make_2way_block_goto(new_jmp_block, blk.serial + 1)
             update_blk_successor(pred_blk, blk.serial,
                                  new_jmp_block.serial)
         dump_microcode_for_debug(
             self.mba, self.log_dir,
             "{0}_{1}_after_jmp_never_fix".format(self.cur_maturity_pass,
                                                  blk.serial))
         nb_change += len(pred_jmp_never_taken)
     return nb_change
Exemple #20
0
 def _execute_microcode(self) -> bool:
     if not self._is_dirty:
         return True
     formatted_mop_searched_list = "['" + "', '".join(
         [format_mop_t(x) for x in self.searched_mop_list]) + "']"
     logger.debug("Computing: {0} for path {1}".format(
         formatted_mop_searched_list, self.block_serial_path))
     self._mc_current_environment = self._mc_initial_environment.get_copy()
     for blk_info in self.history:
         for blk_ins in blk_info.ins_list:
             logger.debug("Executing: {0}.{1}".format(
                 blk_info.blk.serial, format_minsn_t(blk_ins)))
             if not self._mc_interpreter.eval_instruction(
                     blk_info.blk, blk_ins, self._mc_current_environment):
                 self._is_dirty = False
                 return False
     self._is_dirty = False
     return True
Exemple #21
0
    def update_history(self, blk: mblock_t, ins_def: minsn_t) -> bool:
        logger.debug("Updating history with {0}.{1}".format(
            blk.serial, format_minsn_t(ins_def)))
        self.history.insert_ins_in_block(blk, ins_def, before=True)
        if ins_def.opcode == m_call:
            self.call_detected = True
            return False
        ins_mop_info = InstructionDefUseCollector()
        ins_def.for_all_ops(ins_mop_info)

        for target_mop in ins_mop_info.target_mops:
            resolved_mop_index = get_mop_index(target_mop,
                                               self._unresolved_mops)
            if resolved_mop_index != -1:
                logger.debug("Removing {0} from unresolved mop".format(
                    format_mop_t(target_mop)))
                self._unresolved_mops.pop(resolved_mop_index)
        cleaned_unresolved_ins_mops = remove_segment_registers(
            ins_mop_info.unresolved_ins_mops)
        for ins_def_mop in cleaned_unresolved_ins_mops:
            ins_def_mop_index = get_mop_index(ins_def_mop,
                                              self._unresolved_mops)
            if ins_def_mop_index == -1:
                logger.debug("Adding {0} in unresolved mop".format(
                    format_mop_t(ins_def_mop)))
                self._unresolved_mops.append(ins_def_mop)

        for target_mop in ins_mop_info.target_mops:
            resolved_mop_index = get_mop_index(target_mop,
                                               self._memory_unresolved_mops)
            if resolved_mop_index != -1:
                logger.debug("Removing {0} from memory unresolved mop".format(
                    format_mop_t(target_mop)))
                self._memory_unresolved_mops.pop(resolved_mop_index)
        for ins_def_mem_mop in ins_mop_info.memory_unresolved_ins_mops:
            ins_def_mop_index = get_mop_index(ins_def_mem_mop,
                                              self._memory_unresolved_mops)
            if ins_def_mop_index == -1:
                logger.debug("Adding {0} in memory unresolved mop".format(
                    format_mop_t(ins_def_mem_mop)))
                self._memory_unresolved_mops.append(ins_def_mem_mop)
        return True
    def analyze_blk(self, blk: mblock_t) -> int:
        if (blk.tail is None) or blk.tail.opcode not in FAKE_LOOP_OPCODES:
            return 0
        if blk.get_reginsn_qty() != 1:
            return 0
        if blk.tail.r.t != mop_n:
            return 0
        unflat_logger.info("Checking if block {0} is fake loop: {1}".format(
            blk.serial, format_minsn_t(blk.tail)))
        op_compared = mop_t(blk.tail.l)
        blk_preset_list = [x for x in blk.predset]
        nb_change = 0
        for pred_serial in blk_preset_list:
            cmp_variable_tracker = MopTracker([op_compared],
                                              max_nb_block=100,
                                              max_path=1000)
            cmp_variable_tracker.reset()
            pred_blk = blk.mba.get_mblock(pred_serial)
            pred_histories = cmp_variable_tracker.search_backward(
                pred_blk, pred_blk.tail)

            father_is_resolvable = all([
                father_history.is_resolved()
                for father_history in pred_histories
            ])
            if not father_is_resolvable:
                return 0
            pred_values = get_all_possibles_values(pred_histories,
                                                   [op_compared])
            pred_values = [x[0] for x in pred_values]
            if None in pred_values:
                unflat_logger.info(
                    "Some path are not resolved, can't fix jump")
                return 0
            unflat_logger.info(
                "Pred {0} has {1} possible path ({2} different cst): {3}".
                format(pred_blk.serial, len(pred_values),
                       len(set(pred_values)), pred_values))
            if self.fix_successor(blk, pred_blk, pred_values):
                nb_change += 1
        return nb_change
Exemple #23
0
def minsn_to_ast(instruction: minsn_t) -> Union[None, AstNode, AstLeaf]:
    try:
        if instruction.opcode in MINSN_TO_AST_FORBIDDEN_OPCODES:
            # To avoid error 50278
            return None

        ins_mop = mop_t()
        ins_mop.create_from_insn(instruction)

        if instruction.opcode == m_mov:
            tmp = AstNode(m_mov, mop_to_ast(ins_mop))
            tmp.mop = ins_mop
            tmp.dest_size = instruction.d.size
            tmp.ea = instruction.ea
            tmp.dst_mop = instruction.d
            return tmp

        tmp = mop_to_ast(ins_mop)
        tmp.dst_mop = instruction.d
        return tmp
    except RuntimeError as e:
        logger.error("Error while transforming instruction {0}: {1}".format(
            format_minsn_t(instruction), e))
        return None
Exemple #24
0
 def _eval_instruction(
         self, ins: minsn_t,
         environment: MicroCodeEnvironment) -> Union[None, int]:
     if ins is None:
         return None
     is_flow_instruction = self._eval_control_flow_instruction(
         ins, environment)
     if is_flow_instruction:
         return None
     call_helper_res = self._eval_call_helper(ins, environment)
     if call_helper_res is not None:
         return call_helper_res
     if ins.opcode == m_call:
         return self._eval_call(ins, environment)
     elif ins.opcode == m_icall:
         return self._eval_call(ins, environment)
     res_mask = AND_TABLE[ins.d.size]
     if ins.opcode == m_ldx:
         return self._eval_load(ins, environment)
     elif ins.opcode == m_stx:
         return self._eval_store(ins, environment)
     elif ins.opcode == m_mov:
         return (self.eval(ins.l, environment)) & res_mask
     elif ins.opcode == m_neg:
         return (-self.eval(ins.l, environment)) & res_mask
     elif ins.opcode == m_lnot:
         return self.eval(ins.l, environment) != 0
     elif ins.opcode == m_bnot:
         return (self.eval(ins.l, environment) ^ res_mask) & res_mask
     elif ins.opcode == m_xds:
         left_value_signed = unsigned_to_signed(
             self.eval(ins.l, environment), ins.l.size)
         return signed_to_unsigned(left_value_signed, ins.d.size) & res_mask
     elif ins.opcode == m_xdu:
         return (self.eval(ins.l, environment)) & res_mask
     elif ins.opcode == m_low:
         return (self.eval(ins.l, environment)) & res_mask
     elif ins.opcode == m_add:
         return (self.eval(ins.l, environment) +
                 self.eval(ins.r, environment)) & res_mask
     elif ins.opcode == m_sub:
         return (self.eval(ins.l, environment) -
                 self.eval(ins.r, environment)) & res_mask
     elif ins.opcode == m_mul:
         return (self.eval(ins.l, environment) *
                 self.eval(ins.r, environment)) & res_mask
     elif ins.opcode == m_udiv:
         return (self.eval(ins.l, environment) //
                 self.eval(ins.r, environment)) & res_mask
     elif ins.opcode == m_sdiv:
         return (self.eval(ins.l, environment) //
                 self.eval(ins.r, environment)) & res_mask
     elif ins.opcode == m_umod:
         return (self.eval(ins.l, environment) %
                 self.eval(ins.r, environment)) & res_mask
     elif ins.opcode == m_smod:
         return (self.eval(ins.l, environment) %
                 self.eval(ins.r, environment)) & res_mask
     elif ins.opcode == m_or:
         return (self.eval(ins.l, environment)
                 | self.eval(ins.r, environment)) & res_mask
     elif ins.opcode == m_and:
         return (self.eval(ins.l, environment)
                 & self.eval(ins.r, environment)) & res_mask
     elif ins.opcode == m_xor:
         return (self.eval(ins.l, environment)
                 ^ self.eval(ins.r, environment)) & res_mask
     elif ins.opcode == m_shl:
         return (self.eval(ins.l, environment) << self.eval(
             ins.r, environment)) & res_mask
     elif ins.opcode == m_shr:
         return (self.eval(ins.l, environment) >> self.eval(
             ins.r, environment)) & res_mask
     elif ins.opcode == m_sar:
         res_signed = unsigned_to_signed(self.eval(ins.l, environment),
                                         ins.l.size) >> self.eval(
                                             ins.r, environment)
         return signed_to_unsigned(res_signed, ins.d.size) & res_mask
     elif ins.opcode == m_cfadd:
         tmp = get_add_cf(self.eval(ins.l, environment),
                          self.eval(ins.r, environment), ins.l.size)
         return tmp & res_mask
     elif ins.opcode == m_ofadd:
         tmp = get_add_of(self.eval(ins.l, environment),
                          self.eval(ins.r, environment), ins.l.size)
         return tmp & res_mask
     elif ins.opcode == m_sets:
         left_value_signed = unsigned_to_signed(
             self.eval(ins.l, environment), ins.l.size)
         res = 1 if left_value_signed < 0 else 0
         return res & res_mask
     elif ins.opcode == m_seto:
         left_value_signed = unsigned_to_signed(
             self.eval(ins.l, environment), ins.l.size)
         right_value_signed = unsigned_to_signed(
             self.eval(ins.r, environment), ins.r.size)
         sub_overflow = get_sub_of(left_value_signed, right_value_signed,
                                   ins.l.size)
         return sub_overflow & res_mask
     elif ins.opcode == m_setnz:
         res = 1 if self.eval(ins.l, environment) != self.eval(
             ins.r, environment) else 0
         return res & res_mask
     elif ins.opcode == m_setz:
         res = 1 if self.eval(ins.l, environment) == self.eval(
             ins.r, environment) else 0
         return res & res_mask
     elif ins.opcode == m_setae:
         res = 1 if self.eval(ins.l, environment) >= self.eval(
             ins.r, environment) else 0
         return res & res_mask
     elif ins.opcode == m_setb:
         res = 1 if self.eval(ins.l, environment) < self.eval(
             ins.r, environment) else 0
         return res & res_mask
     elif ins.opcode == m_seta:
         res = 1 if self.eval(ins.l, environment) > self.eval(
             ins.r, environment) else 0
         return res & res_mask
     elif ins.opcode == m_setbe:
         res = 1 if self.eval(ins.l, environment) <= self.eval(
             ins.r, environment) else 0
         return res & res_mask
     elif ins.opcode == m_setg:
         left_value = unsigned_to_signed(self.eval(ins.l, environment),
                                         ins.l.size)
         right_value = unsigned_to_signed(self.eval(ins.r, environment),
                                          ins.r.size)
         res = 1 if left_value > right_value else 0
         return res & res_mask
     elif ins.opcode == m_setge:
         left_value = unsigned_to_signed(self.eval(ins.l, environment),
                                         ins.l.size)
         right_value = unsigned_to_signed(self.eval(ins.r, environment),
                                          ins.r.size)
         res = 1 if left_value >= right_value else 0
         return res & res_mask
     elif ins.opcode == m_setl:
         left_value = unsigned_to_signed(self.eval(ins.l, environment),
                                         ins.l.size)
         right_value = unsigned_to_signed(self.eval(ins.r, environment),
                                          ins.r.size)
         res = 1 if left_value < right_value else 0
         return res & res_mask
     elif ins.opcode == m_setle:
         left_value = unsigned_to_signed(self.eval(ins.l, environment),
                                         ins.l.size)
         right_value = unsigned_to_signed(self.eval(ins.r, environment),
                                          ins.r.size)
         res = 1 if left_value <= right_value else 0
         return res & res_mask
     elif ins.opcode == m_setp:
         res = get_parity_flag(self.eval(ins.l, environment),
                               self.eval(ins.r, environment), ins.l.size)
         return res & res_mask
     raise EmulationException(
         "Unsupported instruction opcode '{0}': '{1}'".format(
             opcode_to_string(ins.opcode), format_minsn_t(ins)))
Exemple #25
0
 def _eval_conditional_jump(
         self, ins: minsn_t,
         environment: MicroCodeEnvironment) -> Union[None, int]:
     if ins.opcode not in CONDITIONAL_JUMP_OPCODES:
         return None
     if ins.opcode == m_jtbl:
         # This is not handled the same way
         return None
     cur_blk = environment.cur_blk
     direct_child_serial = cur_blk.serial + 1
     if ins.opcode == m_jcnd:
         jump_taken = self.eval(ins.l, environment) != 0
     elif ins.opcode == m_jnz:
         jump_taken = self.eval(ins.l, environment) != self.eval(
             ins.r, environment)
     elif ins.opcode == m_jz:
         jump_taken = self.eval(ins.l, environment) == self.eval(
             ins.r, environment)
     elif ins.opcode == m_jae:
         jump_taken = self.eval(ins.l, environment) >= self.eval(
             ins.r, environment)
     elif ins.opcode == m_jb:
         jump_taken = self.eval(ins.l, environment) < self.eval(
             ins.r, environment)
     elif ins.opcode == m_ja:
         jump_taken = self.eval(ins.l, environment) > self.eval(
             ins.r, environment)
     elif ins.opcode == m_jbe:
         jump_taken = self.eval(ins.l, environment) <= self.eval(
             ins.r, environment)
     elif ins.opcode == m_jg:
         left_value = unsigned_to_signed(self.eval(ins.l, environment),
                                         ins.l.size)
         right_value = unsigned_to_signed(self.eval(ins.r, environment),
                                          ins.r.size)
         jump_taken = left_value > right_value
     elif ins.opcode == m_jge:
         left_value = unsigned_to_signed(self.eval(ins.l, environment),
                                         ins.l.size)
         right_value = unsigned_to_signed(self.eval(ins.r, environment),
                                          ins.r.size)
         jump_taken = left_value >= right_value
     elif ins.opcode == m_jl:
         left_value = unsigned_to_signed(self.eval(ins.l, environment),
                                         ins.l.size)
         right_value = unsigned_to_signed(self.eval(ins.r, environment),
                                          ins.r.size)
         jump_taken = left_value < right_value
     elif ins.opcode == m_jle:
         left_value = unsigned_to_signed(self.eval(ins.l, environment),
                                         ins.l.size)
         right_value = unsigned_to_signed(self.eval(ins.r, environment),
                                          ins.r.size)
         jump_taken = left_value <= right_value
     else:
         # This should never happen
         raise EmulationException(
             "Unhandled conditional jump:  '{0}'".format(
                 format_minsn_t(ins)))
     return self._get_blk_serial(
         ins.d) if jump_taken else direct_child_serial