예제 #1
0
 def eval(self, mop: mop_t,
          environment: MicroCodeEnvironment) -> Union[None, int]:
     if mop.t == mop_n:
         return mop.nnn.value
     elif mop.t in [mop_r, mop_S]:
         return environment.lookup(mop)
     elif mop.t == mop_d:
         return self._eval_instruction(mop.d, environment)
     elif mop.t == mop_a:
         if mop.a.t == mop_v:
             emulator_log.debug("Reading a mop_a '{0}' -> {1:x}".format(
                 format_mop_t(mop), mop.a.g))
             return mop.a.g
         elif mop.a.t == mop_S:
             emulator_log.debug("Reading a mop_a '{0}' -> {1:x}".format(
                 format_mop_t(mop), mop.a.s.off))
             return mop.a.s.off
         raise UnresolvedMopException(
             "Calling get_cst with unsupported mop type {0} - {1}: '{2}'".
             format(mop.t, mop.a.t, format_mop_t(mop)))
     elif mop.t == mop_v:
         mem_seg = getseg(mop.g)
         seg_perm = mem_seg.perm
         if (seg_perm & SEGPERM_WRITE) != 0:
             emulator_log.debug("Reading a (writable) mop_v {0}".format(
                 format_mop_t(mop)))
             return environment.lookup(mop)
         else:
             memory_value = get_qword(mop.g)
             emulator_log.debug(
                 "Reading a mop_v {0:x} (non writable -> return {1:x})".
                 format(mop.g, memory_value))
             return mop.g
     raise EmulationException("Unsupported mop type '{0}': '{1}'".format(
         mop_type_to_string(mop.t), format_mop_t(mop)))
예제 #2
0
 def _eval_load(self, ins: minsn_t,
                environment: MicroCodeEnvironment) -> Union[None, int]:
     res_mask = AND_TABLE[ins.d.size]
     if ins.opcode == m_ldx:
         load_address = self.eval(ins.r, environment)
         formatted_seg_register = format_mop_t(ins.l)
         if formatted_seg_register == "ss.2":
             stack_mop = mop_t()
             stack_mop.erase()
             stack_mop._make_stkvar(environment.cur_blk.mba, load_address)
             emulator_log.debug("Searching for stack mop {0}".format(
                 format_mop_t(stack_mop)))
             stack_mop_value = environment.lookup(stack_mop)
             emulator_log.debug("  stack mop {0} value : {1}".format(
                 format_mop_t(stack_mop), stack_mop_value))
             return stack_mop_value & res_mask
         else:
             mem_seg = getseg(load_address)
             seg_perm = mem_seg.perm
             if (seg_perm & SEGPERM_WRITE) != 0:
                 raise WritableMemoryReadException(
                     "ldx {0:x} (writable -> return None)".format(
                         load_address))
             else:
                 memory_value = get_qword(load_address)
                 emulator_log.debug(
                     "ldx {0:x} (non writable -> return {1:x})".format(
                         load_address, memory_value & res_mask))
                 return memory_value & res_mask
예제 #3
0
 def eval_mop(self,
              mop: mop_t,
              environment: Union[None, MicroCodeEnvironment] = None,
              raise_exception: bool = False) -> Union[None, int]:
     try:
         if environment is None:
             environment = self.global_environment
         res = self.eval(mop, environment)
         return res
     except EmulationException as e:
         emulator_log.warning(
             "Can't get constant mop value: '{0}': {1}".format(
                 format_mop_t(mop), e))
         if raise_exception:
             raise e
         else:
             return None
     except Exception as e:
         emulator_log.error(
             "Unexpected exception while computing constant mop value: '{0}': {1}"
             .format(format_mop_t(mop), e))
         if raise_exception:
             raise e
         else:
             return None
예제 #4
0
 def visit_mop(self, op: mop_t, op_type: int, is_target: bool):
     if is_target:
         append_mop_if_not_in_list(op, self.target_mops)
     else:
         # TODO whatever the case, in the end we will always return 0. May be this code can be better optimized.
         # TODO handle other special case (e.g. ldx ins, ...)
         if op.t == mop_S:
             append_mop_if_not_in_list(op, self.unresolved_ins_mops)
         elif op.t == mop_r:
             append_mop_if_not_in_list(op, self.unresolved_ins_mops)
         elif op.t == mop_v:
             append_mop_if_not_in_list(op, self.memory_unresolved_ins_mops)
         elif op.t == mop_a:
             if op.a.t == mop_v:
                 return 0
             elif op.a.t == mop_S:
                 return 0
             helper_logger.warning(
                 "Calling visit_mop with unsupported mop type {0} - {1}: '{2}'"
                 .format(mop_type_to_string(op.t),
                         mop_type_to_string(op.a.t), format_mop_t(op)))
             return 0
         elif op.t == mop_n:
             return 0
         elif op.t == mop_d:
             return 0
         elif op.t == mop_h:
             return 0
         elif op.t == mop_b:
             return 0
         else:
             helper_logger.warning(
                 "Calling visit_mop with unsupported mop type {0}: '{1}'".
                 format(mop_type_to_string(op.t), format_mop_t(op)))
     return 0
예제 #5
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
예제 #6
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)))
예제 #7
0
    def check_candidate(self, candidate):
        # IDA does not do constant propagation for pattern such as:
        # mov     #0x65A4.2, r6.2
        # mov     #0x210F.2, r6^2.2
        # jz      r0.4, r6.4
        # Thus, we try to detect mov to r6^2 and replace by (or #0x210F0000.4, r6.4 & 0x0000ffff.4, r6.4
        # By doing that, IDA constant propagation will work again.

        if candidate.dst_mop.t != mop_r:
            return False
        dst_reg_name = format_mop_t(candidate.dst_mop)
        if dst_reg_name is None:
            return False
        if "^2" in dst_reg_name:
            if candidate["c_0"].mop.size != 2:
                return False
            candidate.add_constant_leaf("new_c_0",
                                        candidate["c_0"].value << 16, 4)
            candidate.add_constant_leaf("mask", 0xffff, 4)
            new_dst_reg = mop_t()
            new_dst_reg.make_reg(candidate.dst_mop.r - 2, 4)
            candidate.add_leaf("new_reg", new_dst_reg)
            candidate.dst_mop = new_dst_reg
            return True
        else:
            return False
예제 #8
0
 def assign(self, mop: mop_t, value: int, auto_define=True) -> int:
     if mop.t == mop_r:
         return self._lookup_mop(mop, self.mop_r_record, value, auto_define)
     elif mop.t == mop_S:
         return self._lookup_mop(mop, self.mop_S_record, value, auto_define)
     raise EmulationException(
         "Assigning an unsupported mop type '{0}': '{1}'".format(
             mop_type_to_string(mop.t), format_mop_t(mop)))
예제 #9
0
def get_segment_register_indexes(mop_list: List[mop_t]) -> List[int]:
    # This is a very dirty and probably buggy
    segment_register_indexes = []
    for i, mop in enumerate(mop_list):
        if mop.t == mop_r:
            formatted_mop = format_mop_t(mop)
            if formatted_mop in ["ds.2", "cs.2", "es.2", "ss.2"]:
                segment_register_indexes.append(i)
    return segment_register_indexes
예제 #10
0
 def define(self, mop: mblock_t, value: int) -> int:
     if mop.t == mop_r:
         self.mop_r_record[mop] = value
         return value
     elif mop.t == mop_S:
         self.mop_S_record[mop] = value
         return value
     raise EmulationException(
         "Defining an unsupported mop type '{0}': '{1}'".format(
             mop_type_to_string(mop.t), format_mop_t(mop)))
예제 #11
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
예제 #12
0
 def __str__(self):
     try:
         if self.is_constant():
             return "{0}".format(self.mop.nnn.value)
         if self.z3_var_name is not None:
             return self.z3_var_name
         if self.ast_index is not None:
             return "x_{0}".format(self.ast_index)
         if self.mop is not None:
             return format_mop_t(self.mop)
         return self.name
     except RuntimeError as e:
         logger.info(
             "Error while calling __str__ on AstLeaf: {0}".format(e))
         return "Error_AstLeaf"
예제 #13
0
def get_standard_and_memory_mop_lists(
        mop_in: mop_t) -> Tuple[List[mop_t], List[mop_t]]:
    if mop_in.t in [mop_r, mop_S]:
        return [mop_in], []
    elif mop_in.t == mop_v:
        return [], [mop_in]
    elif mop_in.t == mop_d:
        ins_mop_info = InstructionDefUseCollector()
        mop_in.d.for_all_ops(ins_mop_info)
        return remove_segment_registers(
            ins_mop_info.unresolved_ins_mops
        ), ins_mop_info.memory_unresolved_ins_mops
    else:
        logger.warning(
            "Calling get_standard_and_memory_mop_lists with unsupported mop type {0}: '{1}'"
            .format(mop_in.t, format_mop_t(mop_in)))
        return [], []
예제 #14
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
예제 #15
0
 def _lookup_mop(self,
                 searched_mop: mop_t,
                 mop_value_dict: Dict[mop_t, int],
                 new_mop_value: Union[None, int] = None,
                 auto_define=True,
                 raise_exception=True) -> int:
     for known_mop, mop_value in mop_value_dict.items():
         if equal_mops_ignore_size(searched_mop, known_mop):
             if new_mop_value is not None:
                 mop_value_dict[searched_mop] = new_mop_value
                 return new_mop_value
             return mop_value
     if (new_mop_value is not None) and auto_define:
         self.define(searched_mop, new_mop_value)
         return new_mop_value
     if raise_exception:
         raise EmulationException("Variable '{0}' is not defined".format(
             format_mop_t(searched_mop)))
     else:
         return None
예제 #16
0
def mop_to_ast_internal(
        mop: mop_t,
        ast_list: List[Union[AstNode,
                             AstLeaf]]) -> Union[None, AstNode, AstLeaf]:
    if mop is None:
        return None

    if mop.t != mop_d or (mop.d.opcode not in MBA_RELATED_OPCODES):
        tree = AstLeaf(format_mop_t(mop))
        tree.mop = mop
        dest_size = mop.size if mop.t != mop_d else mop.d.d.size
        tree.dest_size = dest_size
    else:
        left_ast = mop_to_ast_internal(mop.d.l, ast_list)
        right_ast = mop_to_ast_internal(mop.d.r, ast_list)
        dst_ast = mop_to_ast_internal(mop.d.d, ast_list)
        tree = AstNode(mop.d.opcode, left_ast, right_ast, dst_ast)
        tree.mop = mop
        tree.dest_size = mop.d.d.size
        tree.ea = mop.d.ea

    check_and_add_to_list(tree, ast_list)
    return tree
예제 #17
0
 def __str__(self):
     return "{0} used {1} times: {2}".format(self.ast, self.number_of_use,
                                             format_mop_t(self.ast.mop))
예제 #18
0
 def _get_blk_serial(mop: mop_t) -> int:
     if mop.t == mop_b:
         return mop.b
     raise EmulationException(
         "Get block serial with an unsupported mop type '{0}': '{1}'".
         format(mop_type_to_string(mop.t), format_mop_t(mop)))
예제 #19
0
    def search_backward(self,
                        blk: mblock_t,
                        ins: minsn_t,
                        avoid_list=None,
                        must_use_pred=None,
                        stop_at_first_duplication=False) -> List[MopHistory]:
        logger.debug("Searching backward (reg): {0}".format(
            [format_mop_t(x) for x in self._unresolved_mops]))
        logger.debug("Searching backward (mem): {0}".format(
            [format_mop_t(x) for x in self._memory_unresolved_mops]))
        logger.debug("Searching backward (cst): {0}".format([
            "{0}: {1:x}".format(format_mop_t(x[0]), x[1])
            for x in self.constant_mops
        ]))
        self.mba = blk.mba
        self.avoid_list = avoid_list if avoid_list else []
        blk_with_multiple_pred = self.search_until_multiple_predecessor(
            blk, ins)
        if self.is_resolved():
            logger.debug("MopTracker is resolved:  {0}".format(
                self.history.block_serial_path))
            self.history.unresolved_mop_list = [
                x for x in self._unresolved_mops
            ]
            return [self.history]
        elif blk_with_multiple_pred is None:
            logger.debug(
                "MopTracker unresolved: (blk_with_multiple_pred): {0}".format(
                    self.history.block_serial_path))
            self.history.unresolved_mop_list = [
                x for x in self._unresolved_mops
            ]
            return [self.history]
        elif self.max_nb_block != -1 and len(
                self.history.block_serial_path) > self.max_nb_block:
            logger.debug("MopTracker unresolved: (max_nb_block): {0}".format(
                self.history.block_serial_path))
            self.history.unresolved_mop_list = [
                x for x in self._unresolved_mops
            ]
            return [self.history]
        elif self.max_path != -1 and cur_mop_tracker_nb_path > self.max_path:
            logger.debug("MopTracker unresolved: (max_path: {0}".format(
                cur_mop_tracker_nb_path))
            self.history.unresolved_mop_list = [
                x for x in self._unresolved_mops
            ]
            return [self.history]
        elif self.call_detected:
            logger.debug("MopTracker unresolved: (call): {0}".format(
                self.history.block_serial_path))
            self.history.unresolved_mop_list = [
                x for x in self._unresolved_mops
            ]
            return [self.history]

        if stop_at_first_duplication:
            self.history.unresolved_mop_list = [
                x for x in self._unresolved_mops
            ]
            return [self.history]
        logger.debug(
            "MopTracker creating child because multiple pred: {0}".format(
                self.history.block_serial_path))
        possible_histories = []
        if must_use_pred is not None and must_use_pred.serial in blk_with_multiple_pred.predset:
            new_tracker = self.get_copy()
            possible_histories += new_tracker.search_backward(
                must_use_pred, None, self.avoid_list, must_use_pred)
        else:
            for blk_pred_serial in blk_with_multiple_pred.predset:
                new_tracker = self.get_copy()
                possible_histories += new_tracker.search_backward(
                    self.mba.get_mblock(blk_pred_serial), None,
                    self.avoid_list, must_use_pred)
        return possible_histories