Esempio n. 1
0
    def _gen_path_constraints(self, translator, expr, expected):
        """Generate path constraint from @expr. Handle special case with
        generated loc_keys
        """
        out = []
        expected = canonize_to_exprloc(self._ircfg.loc_db, expected)
        expected_is_loc_key = expected.is_loc()
        for consval in possible_values(expr):
            value = canonize_to_exprloc(self._ircfg.loc_db, consval.value)
            if expected_is_loc_key and value != expected:
                continue
            if not expected_is_loc_key and value.is_loc_key():
                continue

            conds = z3.And(*[
                translator.from_expr(cond.to_constraint())
                for cond in consval.constraints
            ])
            if expected != value:
                conds = z3.And(
                    conds, translator.from_expr(ExprAssign(value, expected)))
            out.append(conds)

        if out:
            conds = z3.Or(*out)
        else:
            # Ex: expr: lblgen1, expected: 0x1234
            # -> Avoid inconsistent solution lblgen1 = 0x1234
            conds = translator.from_expr(self.unsat_expr)
        return conds
Esempio n. 2
0
 def solve_for_memory_access(self, expr_mem, access_type, additional_constraints=set()):
   # Check that input has effect on memory referenced
   if get_expr_ids(expr_mem.ptr) & self.symbolized_mem_ids:
     for possibility in possible_values(expr_mem.ptr):
       address_expr = possibility.value
       access_len = int(expr_mem.size/8)
       # 5 sec timeout
       #self.dse.cur_solver.set('timeout', 5000)
       # Save solver state
       self.dse.cur_solver.push()
       # Add constraints from the expr itself
       for cons in possibility.constraints.union(additional_constraints):
         eaff = cons.to_constraint()
         #print '\tADDING CONSTRAINT: ' + str(eaff)
         self.dse.cur_solver.add(self.dse.z3_trans.from_expr(eaff))
       # Add memory constraints
       for mem_range in self.dse.valid_ranges:
         # Add range constraint
         rc = z3.Not(z3.And(z3.UGE(self.dse.z3_trans.from_expr(address_expr), self.dse.z3_trans.from_expr(mem_range[0])),
                            z3.ULE(self.dse.z3_trans.from_expr(address_expr), self.dse.z3_trans.from_expr(mem_range[1]-ExprInt(access_len-1, 64)))
                           )
                    )
         self.dse.cur_solver.add(rc)
       #print solver
       #import pdb; pdb.set_trace()
       if self.dse.cur_solver.check()==z3.sat:
         model = self.dse.cur_solver.model()
         #import pdb; pdb.set_trace()
         log.debug('SYMB 0x{:08X}: {:s} -> {}AV[{:s}]  '.format(self.dse.jitter.pc, \
                                                         str(model), access_type, \
                                                         str(self.dse.symb.eval_expr(address_expr, eval_cache={})))
                 )
         # Evaluate the buffer that would cause the crash
         crashbuf = self.derive_crashbuf(model)
         # Evaluate the AV adress
         values = self.get_values_from_model(model)
         self.dse.crashes.append(crash( self.dse.jitter.pc, \
                                     self.dse.symb.eval_expr(address_expr, eval_cache=values), \
                                     access_type, \
                                     crashbuf, \
                                     int(self.dse.callsite)
                                   )
                             )
       # Reset the solver
       self.dse.cur_solver.pop()
   return
Esempio n. 3
0
def compute_cst_propagation_states(ir_arch, ircfg, init_addr, init_infos):
    """
    Propagate "constant expressions" in a function.
    The attribute "constant expression" is true if the expression is based on
    constants or "init" regs values.

    @ir_arch: IntermediateRepresentation instance
    @init_addr: analysis start address
    @init_infos: dictionary linking expressions to their values at @init_addr
    """

    done = set()
    state = SymbExecState.StateEngine(init_infos)
    lbl = ircfg.get_loc_key(init_addr)
    todo = set([lbl])
    states = {lbl: state}

    while todo:
        if not todo:
            break
        lbl = todo.pop()
        state = states[lbl]
        if (lbl, state) in done:
            continue
        done.add((lbl, state))
        if lbl not in ircfg.blocks:
            continue

        symbexec_engine = SymbExecState(ir_arch, ircfg, state)
        addr = symbexec_engine.run_block_at(ircfg, lbl)
        symbexec_engine.del_mem_above_stack(ir_arch.sp)

        for dst in possible_values(addr):
            value = dst.value
            if value.is_mem():
                LOG_CST_PROPAG.warning('Bad destination: %s', value)
                continue
            elif value.is_int():
                value = ircfg.get_loc_key(value)
            add_state(
                ircfg, todo, states, value,
                symbexec_engine.get_state()
            )

    return states
Esempio n. 4
0
def compute_cst_propagation_states(ir_arch, ircfg, init_addr, init_infos):
    """
    Propagate "constant expressions" in a function.
    The attribute "constant expression" is true if the expression is based on
    constants or "init" regs values.

    @ir_arch: IntermediateRepresentation instance
    @init_addr: analysis start address
    @init_infos: dictionary linking expressions to their values at @init_addr
    """

    done = set()
    state = SymbExecState.StateEngine(init_infos)
    lbl = ircfg.get_loc_key(init_addr)
    todo = set([lbl])
    states = {lbl: state}

    while todo:
        if not todo:
            break
        lbl = todo.pop()
        state = states[lbl]
        if (lbl, state) in done:
            continue
        done.add((lbl, state))
        if lbl not in ircfg.blocks:
            continue

        symbexec_engine = SymbExecState(ir_arch, ircfg, state)
        addr = symbexec_engine.run_block_at(ircfg, lbl)
        symbexec_engine.del_mem_above_stack(ir_arch.sp)

        for dst in possible_values(addr):
            value = dst.value
            if value.is_mem():
                LOG_CST_PROPAG.warning('Bad destination: %s', value)
                continue
            elif value.is_int():
                value = ircfg.get_loc_key(value)
            add_state(ircfg, todo, states, value, symbexec_engine.get_state())

    return states
Esempio n. 5
0
    def handle(self, cur_addr):
        cur_addr = canonize_to_exprloc(self.ir_arch.loc_db, cur_addr)
        symb_pc = self.eval_expr(self.ir_arch.IRDst)
        possibilities = possible_values(symb_pc)
        cur_path_constraint = set()  # path_constraint for the concrete path
        if len(possibilities) == 1:
            dst = next(iter(possibilities)).value
            dst = canonize_to_exprloc(self.ir_arch.loc_db, dst)
            assert dst == cur_addr
        else:
            for possibility in possibilities:
                target_addr = canonize_to_exprloc(self.ir_arch.loc_db,
                                                  possibility.value)
                path_constraint = set(
                )  # Set of ExprAssign for the possible path

                # Get constraint associated to the possible path
                memory_to_add = ModularIntervals(symb_pc.size)
                for cons in possibility.constraints:
                    eaff = cons.to_constraint()
                    # eaff.get_r(mem_read=True) is not enough
                    # ExprAssign consider a Memory access in dst as a write
                    mem = eaff.dst.get_r(mem_read=True)
                    mem.update(eaff.src.get_r(mem_read=True))
                    for expr in mem:
                        if expr.is_mem():
                            addr_range = expr_range(expr.ptr)
                            # At upper bounds, add the size of the memory access
                            # if addr (- [a, b], then @size[addr] reachables
                            # values are in @8[a, b + size[
                            for start, stop in addr_range:
                                stop += expr.size // 8 - 1
                                full_range = ModularIntervals(
                                    symb_pc.size, [(start, stop)])
                                memory_to_add.update(full_range)
                    path_constraint.add(eaff)

                if memory_to_add.length > self.MAX_MEMORY_INJECT:
                    # TODO re-croncretize the constraint or z3-try
                    raise RuntimeError("Not implemented: too long memory area")

                # Inject memory
                for start, stop in memory_to_add:
                    for address in range(start, stop + 1):
                        expr_mem = ExprMem(
                            ExprInt(address, self.ir_arch.pc.size), 8)
                        value = self.eval_expr(expr_mem)
                        if not value.is_int():
                            raise TypeError("Rely on a symbolic memory case, " \
                                            "address 0x%x" % address)
                        path_constraint.add(ExprAssign(expr_mem, value))

                if target_addr == cur_addr:
                    # Add path constraint
                    cur_path_constraint = path_constraint

                elif self.produce_solution(target_addr):
                    # Looking for a new solution
                    self.cur_solver.push()
                    for cons in path_constraint:
                        trans = self.z3_trans.from_expr(cons)
                        trans = z3.simplify(trans)
                        self.cur_solver.add(trans)

                    result = self.cur_solver.check()
                    if result == z3.sat:
                        model = self.cur_solver.model()
                        self.handle_solution(model, target_addr)
                    self.cur_solver.pop()

        self.handle_correct_destination(cur_addr, cur_path_constraint)
Esempio n. 6
0
File: dse.py Progetto: cea-sec/miasm
    def handle(self, cur_addr):
        cur_addr = self.ir_arch.loc_db.canonize_to_exprloc(cur_addr)
        symb_pc = self.eval_expr(self.ir_arch.IRDst)
        possibilities = possible_values(symb_pc)
        cur_path_constraint = set() # path_constraint for the concrete path
        if len(possibilities) == 1:
            dst = next(iter(possibilities)).value
            dst = self.ir_arch.loc_db.canonize_to_exprloc(dst)
            assert dst == cur_addr
        else:
            for possibility in possibilities:
                target_addr = self.ir_arch.loc_db.canonize_to_exprloc(
                    possibility.value
                )
                path_constraint = set() # Set of ExprAssign for the possible path

                # Get constraint associated to the possible path
                memory_to_add = ModularIntervals(symb_pc.size)
                for cons in possibility.constraints:
                    eaff = cons.to_constraint()
                    # eaff.get_r(mem_read=True) is not enough
                    # ExprAssign consider a Memory access in dst as a write
                    mem = eaff.dst.get_r(mem_read=True)
                    mem.update(eaff.src.get_r(mem_read=True))
                    for expr in mem:
                        if expr.is_mem():
                            addr_range = expr_range(expr.ptr)
                            # At upper bounds, add the size of the memory access
                            # if addr (- [a, b], then @size[addr] reachables
                            # values are in @8[a, b + size[
                            for start, stop in addr_range:
                                stop += expr.size // 8 - 1
                                full_range = ModularIntervals(
                                    symb_pc.size,
                                    [(start, stop)]
                                )
                                memory_to_add.update(full_range)
                    path_constraint.add(eaff)

                if memory_to_add.length > self.MAX_MEMORY_INJECT:
                    # TODO re-croncretize the constraint or z3-try
                    raise RuntimeError("Not implemented: too long memory area")

                # Inject memory
                for start, stop in memory_to_add:
                    for address in range(start, stop + 1):
                        expr_mem = ExprMem(ExprInt(address,
                                                   self.ir_arch.pc.size),
                                           8)
                        value = self.eval_expr(expr_mem)
                        if not value.is_int():
                            raise TypeError("Rely on a symbolic memory case, " \
                                            "address 0x%x" % address)
                        path_constraint.add(ExprAssign(expr_mem, value))

                if target_addr == cur_addr:
                    # Add path constraint
                    cur_path_constraint = path_constraint

                elif self.produce_solution(target_addr):
                    # Looking for a new solution
                    self.cur_solver.push()
                    for cons in path_constraint:
                        trans = self.z3_trans.from_expr(cons)
                        trans = z3.simplify(trans)
                        self.cur_solver.add(trans)

                    result = self.cur_solver.check()
                    if result == z3.sat:
                        model = self.cur_solver.model()
                        self.handle_solution(model, target_addr)
                    self.cur_solver.pop()

        self.handle_correct_destination(cur_addr, cur_path_constraint)