Example #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)))
Example #2
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)))
Example #3
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)))
Example #4
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
Example #5
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
Example #6
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)))
Example #7
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
Example #8
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)))