Exemplo n.º 1
0
    def run(self, this_ref, key_ref):
        log.debug('Called SimProcedure java.util.Map.containsKey with args: {} {}'.format(this_ref, key_ref))

        if this_ref.symbolic:
            return claripy.BoolS('contains_key')

        try:
            this_ref.load_field(self.state, get_map_key(self.state, key_ref), 'java.lang.Object')
            return claripy.BoolV(1)

        except (KeyError, AttributeError):
            return claripy.BoolV(0)
Exemplo n.º 2
0
    def _store_fully_symbolic(self, address, addresses, size, data, endness, condition):
        stored_values = [ ]
        byte_dict = defaultdict(list)
        max_bytes = data.length//self.state.arch.byte_width

        if condition is None:
            condition = claripy.BoolV(True)

        # chop data into byte-chunks
        original_values = [self._read_from(a, max_bytes) for a in addresses]
        if endness == "Iend_LE" or (endness is None and self.endness == "Iend_LE"):
            original_values = [ ov.reversed  for ov in original_values ]
        data_bytes = data.chop(bits=self.state.arch.byte_width)

        for a, fv in zip(addresses, original_values):
            original_bytes = fv.chop(self.state.arch.byte_width)
            for index, (d_byte, o_byte) in enumerate(zip(data_bytes, original_bytes)):
                # create a dict of all all possible values for a certain address
                byte_dict[a+index].append((a, index, d_byte, o_byte))

        for byte_addr in sorted(byte_dict.keys()):
            write_list = byte_dict[byte_addr]
            # If this assertion fails something is really wrong!
            assert all(v[3] is write_list[0][3] for v in write_list)
            conditional_value = write_list[0][3]
            for a, index, d_byte, o_byte in write_list:
                # create the ast for each byte
                conditional_value = self.state.solver.If(self.state.se.And(address == a, size > index, condition), d_byte, conditional_value)

            stored_values.append(dict(value=conditional_value, addr=byte_addr, size=1))

        return stored_values
Exemplo n.º 3
0
    def _store_symbolic_addr(self, address,  addresses, size, data, endness, condition):
        size = self.state.solver.eval(size)
        segments = self._get_segments(addresses, size)

        if condition is None:
            condition = claripy.BoolV(True)

        original_values = [ self._read_from(segment['start'], segment['size']) for segment in segments ]
        if endness == "Iend_LE" or (endness is None and self.endness == "Iend_LE"):
            original_values = [ ov.reversed  for ov in original_values ]

        stored_values = []
        for segment, original_value  in zip(segments, original_values):
            conditional_value = original_value

            for opt in segment['options']:

                if endness == "Iend_LE" or (endness is None and self.endness == "Iend_LE"):
                    high = ((opt['idx']+segment['size']) * self.state.arch.byte_width)-1
                    low = opt['idx']*self.state.arch.byte_width
                else:
                    high = len(data) - 1 - (opt['idx']*self.state.arch.byte_width)
                    low = len(data) - ((opt['idx']+segment['size']) *self.state.arch.byte_width)

                data_slice = data[high:low]
                conditional_value = self.state.solver.If(self.state.solver.And(address == segment['start']-opt['idx'], condition), data_slice, conditional_value)

            stored_values.append(dict(value=conditional_value, addr=segment['start'], size=segment['size']))

        return stored_values
Exemplo n.º 4
0
 def syscall_hook(state):
     # FIXME maybe we need to fix transmit/receive to handle huge vals properly
     # kill path that try to read/write large amounts
     syscall_name = state.inspect.syscall_name
     if syscall_name == "transmit":
         count = state.se.eval(state.regs.edx)
         if count > 0x10000:
             state.regs.edx = 0
             state.add_constraints(claripy.BoolV(False))
     if syscall_name == "receive":
         count = state.se.eval(state.regs.edx)
         if count > 0x10000:
             state.regs.edx = 0
             state.add_constraints(claripy.BoolV(False))
     if syscall_name == "random":
         count = state.se.eval(state.regs.ecx)
         if count > 0x1000:
             state.regs.ecx = 0
             state.add_constraints(claripy.BoolV(False))
Exemplo n.º 5
0
def test_concrete():
    a = claripy.BVV(10, 32)
    b = claripy.BoolV(True)
    #c = claripy.BVS('x', 32)

    nose.tools.assert_is(type(claripy.backends.concrete.convert(a)), claripy.bv.BVV)
    nose.tools.assert_is(type(claripy.backends.concrete.convert(b)), bool)

    a = claripy.BVV(1337, 32)
    b = a[31:16]
    c = claripy.BVV(0, 16)
    nose.tools.assert_is(b, c)
Exemplo n.º 6
0
    def run(self, this_ref):
        log.debug(
            'Called SimProcedure java.util.Iterator.hasNext with args: {}'.
            format(this_ref))

        if this_ref.symbolic:
            return claripy.BoolS('iterator.hasNext')

        iterator_size = this_ref.load_field(self.state, SIZE, 'int')
        iterator_index = this_ref.load_field(self.state, INDEX, 'int')

        has_next = self.state.solver.eval(
            iterator_index) < self.state.solver.eval(iterator_size)

        return claripy.BoolV(has_next)
Exemplo n.º 7
0
 def merge_path_to_same_lib_call_together(self):
     res = dict()
     for libcall_addr in self.all_lib_calls.keys():
         try:
             res[libcall_addr] = []
             all_paths = self.all_lib_calls[libcall_addr]
             all_formulas = dict()
             all_cons = []
             for path in all_paths:
                 fs, cs, inputs = self.fe.get_formulas_from(path)
                 if cs:
                     all_cons.extend(cs)
                 for f in fs:
                     v_name, ast = f
                     if v_name not in all_formulas:
                         all_formulas[v_name] = []
                     all_formulas[v_name].append((ast, cs))
             if len(all_formulas.keys()) > 0:
                 # here is a libcall with arguments
                 for v_name, fc_list in all_formulas.items():
                     tmp_f, tmp_cons = merge_fe_formulas(
                         fc_list, self.fe.ptr_size)
                     tmp_f = claripy.simplify(tmp_f)
                     if len(tmp_cons) == 0:
                         # no constraints is equivalent to always True
                         tmp_cons = None
                     else:
                         tmp_cons = claripy.simplify(claripy.Or(*tmp_cons))
                         if tmp_cons.depth == 1 and tmp_cons.args == (
                                 True, ):
                             tmp_cons = None
                     res[libcall_addr].append((v_name, tmp_f, tmp_cons))
             else:
                 # here is a libcall with no argument
                 if len(all_cons) == 0:
                     tmp_cons = claripy.BoolV(True)
                 else:
                     tmp_cons = claripy.simplify(claripy.Or(*all_cons))
                 res[libcall_addr].append((None, all_paths, tmp_cons))
         except Exception:
             log.error(
                 'meets error in merge_path_to_same_lib_call_together base_entry=0x%x'
                 % self.base_entry)
             # if this lib call meets error, we skip merging formulas of it
             if libcall_addr in res.keys():
                 res.pop(libcall_addr)
     return res
Exemplo n.º 8
0
    def _bool_variable_from_ail_condition(self, condition):

        # Unpack a condition all the way to the leaves

        _mapping = {
            'LogicalAnd': lambda expr, conv: claripy.And(conv(expr.operands[0]), conv(expr.operands[1])),
            'LogicalOr': lambda expr, conv: claripy.Or(conv(expr.operands[0]), conv(expr.operands[1])),
            'CmpEQ': lambda expr, conv: conv(expr.operands[0]) == conv(expr.operands[1]),
            'CmpLE': lambda expr, conv: conv(expr.operands[0]) <= conv(expr.operands[1]),
            'CmpLT': lambda expr, conv: conv(expr.operands[0]) < conv(expr.operands[1]),
            'Add': lambda expr, conv: conv(expr.operands[0]) + conv(expr.operands[1]),
            'Not': lambda expr, conv: claripy.Not(conv(expr.operand)),
            'Xor': lambda expr, conv: conv(expr.operands[0]) ^ conv(expr.operands[1]),
            'And': lambda expr, conv: conv(expr.operands[0]) & conv(expr.operands[1]),
            'Shr': lambda expr, conv: claripy.LShR(conv(expr.operands[0]), expr.operands[1])
        }

        if isinstance(condition, (ailment.Expr.Load, ailment.Expr.Register, ailment.Expr.DirtyExpression)):
            var = claripy.BVS('ailexpr_%s' % repr(condition), condition.bits, explicit_name=True)
            self._condition_mapping[var] = condition
            return var
        elif isinstance(condition, ailment.Expr.Convert):
            # convert is special. if it generates a 1-bit variable, it should be treated as a BVS
            if condition.to_bits == 1:
                var = claripy.BoolS('ailcond_%s' % repr(condition), explicit_name=True)
            else:
                var = claripy.BVS('ailexpr_%s' % repr(condition), condition.to_bits, explicit_name=True)
            self._condition_mapping[var] = condition
            return var
        elif isinstance(condition, ailment.Expr.Const):
            var = claripy.BVV(condition.value, condition.bits)
            return var
        elif isinstance(condition, ailment.Expr.Tmp):
            l.warning("Left-over ailment.Tmp variable %s.", condition)
            if condition.bits == 1:
                var = claripy.BoolV('ailtmp_%d' % condition.tmp_idx)
            else:
                var = claripy.BVS('ailtmp_%d' % condition.tmp_idx, condition.bits)
            self._condition_mapping[var] = condition
            return var

        lambda_expr = _mapping.get(condition.op, None)
        if lambda_expr is None:
            raise NotImplementedError("Unsupported AIL expression operation %s. Consider implementing." % condition.op)
        return lambda_expr(condition, self._bool_variable_from_ail_condition)
Exemplo n.º 9
0
def test_concrete():
    a = claripy.BVV(10, 32)
    b = claripy.BoolV(True)
    #c = claripy.BVS('x', 32)

    nose.tools.assert_is(type(claripy.backends.concrete.convert(a)),
                         claripy.bv.BVV)
    nose.tools.assert_is(type(claripy.backends.concrete.convert(b)), bool)

    a = claripy.BVV(1337, 32)
    b = a[31:16]
    c = claripy.BVV(0, 16)
    nose.tools.assert_is(b, c)

    bc = claripy.backends.concrete
    d = claripy.BVV(-1, 32)
    nose.tools.assert_equal(bc.convert(d), 0xffffffff)

    e = claripy.BVV(2**32 + 1337, 32)
    nose.tools.assert_equal(bc.convert(e), 1337)
Exemplo n.º 10
0
    def run(self, this_ref, obj_ref):
        log.debug(
            'Called SimProcedure java.util.List.add with args: {} {}'.format(
                this_ref, obj_ref))

        if this_ref.symbolic:
            return claripy.BoolS('list.append')

        try:
            array_ref = this_ref.load_field(self.state, ELEMS,
                                            'java.lang.Object[]')
            array_len = this_ref.load_field(self.state, SIZE, 'int')
            self.state.javavm_memory.store_array_element(
                array_ref, array_len, obj_ref)
            # Update size
            new_array_len = claripy.BVV(
                self.state.solver.eval(array_len) + 1, 32)
            this_ref.store_field(self.state, SIZE, 'int', new_array_len)
        except KeyError:
            log.warning('Could not add element to list {}'.format(this_ref))

        return claripy.BoolV(1)
Exemplo n.º 11
0
    def claripy_ast_from_ail_condition(self, condition) -> claripy.ast.Base:

        # Unpack a condition all the way to the leaves
        if isinstance(condition, claripy.ast.Base):  # pylint:disable=isinstance-second-argument-not-valid-type
            return condition

        def _op_with_unified_size(op, conv, operand0, operand1):
            # ensure operand1 is of the same size as operand0
            if isinstance(operand1, ailment.Expr.Const):
                # amazing - we do the eazy thing here
                return op(conv(operand0), operand1.value)
            if operand1.bits == operand0.bits:
                return op(conv(operand0), conv(operand1))
            # extension is required
            assert operand1.bits < operand0.bits
            operand1 = ailment.Expr.Convert(None, operand1.bits, operand0.bits, False, operand1)
            return op(conv(operand0), conv(operand1))

        _mapping = {
            'LogicalAnd': lambda expr, conv: claripy.And(conv(expr.operands[0]), conv(expr.operands[1])),
            'LogicalOr': lambda expr, conv: claripy.Or(conv(expr.operands[0]), conv(expr.operands[1])),
            'CmpEQ': lambda expr, conv: conv(expr.operands[0]) == conv(expr.operands[1]),
            'CmpNE': lambda expr, conv: conv(expr.operands[0]) != conv(expr.operands[1]),
            'CmpLE': lambda expr, conv: conv(expr.operands[0]) <= conv(expr.operands[1]),
            'CmpLEs': lambda expr, conv: claripy.SLE(conv(expr.operands[0]), conv(expr.operands[1])),
            'CmpLT': lambda expr, conv: conv(expr.operands[0]) < conv(expr.operands[1]),
            'CmpLTs': lambda expr, conv: claripy.SLT(conv(expr.operands[0]), conv(expr.operands[1])),
            'CmpGE': lambda expr, conv: conv(expr.operands[0]) >= conv(expr.operands[1]),
            'CmpGEs': lambda expr, conv: claripy.SGE(conv(expr.operands[0]), conv(expr.operands[1])),
            'CmpGT': lambda expr, conv: conv(expr.operands[0]) > conv(expr.operands[1]),
            'CmpGTs': lambda expr, conv: claripy.SGT(conv(expr.operands[0]), conv(expr.operands[1])),
            'Add': lambda expr, conv: conv(expr.operands[0]) + conv(expr.operands[1]),
            'Sub': lambda expr, conv: conv(expr.operands[0]) - conv(expr.operands[1]),
            'Mul': lambda expr, conv: conv(expr.operands[0]) * conv(expr.operands[1]),
            'Not': lambda expr, conv: claripy.Not(conv(expr.operand)),
            'Xor': lambda expr, conv: conv(expr.operands[0]) ^ conv(expr.operands[1]),
            'And': lambda expr, conv: conv(expr.operands[0]) & conv(expr.operands[1]),
            'Or': lambda expr, conv: conv(expr.operands[0]) | conv(expr.operands[1]),
            'Shr': lambda expr, conv: _op_with_unified_size(claripy.LShR, conv, expr.operands[0], expr.operands[1]),
            'Shl': lambda expr, conv: _op_with_unified_size(operator.lshift, conv, expr.operands[0], expr.operands[1]),
            'Sar': lambda expr, conv: _op_with_unified_size(operator.rshift, conv, expr.operands[0], expr.operands[1]),
        }

        if isinstance(condition, (ailment.Expr.Load, ailment.Expr.DirtyExpression, ailment.Expr.BasePointerOffset,
                                  ailment.Expr.ITE, ailment.Stmt.Call)):
            var = claripy.BVS('ailexpr_%s' % repr(condition), condition.bits, explicit_name=True)
            self._condition_mapping[var.args[0]] = condition
            return var
        elif isinstance(condition, ailment.Expr.Register):
            var = claripy.BVS('ailexpr_%s-%d' % (repr(condition), condition.idx), condition.bits, explicit_name=True)
            self._condition_mapping[var.args[0]] = condition
            return var
        elif isinstance(condition, ailment.Expr.Convert):
            # convert is special. if it generates a 1-bit variable, it should be treated as a BVS
            if condition.to_bits == 1:
                var_ = self.claripy_ast_from_ail_condition(condition.operands[0])
                name = 'ailcond_Conv(%d->%d, %s)' % (condition.from_bits, condition.to_bits, repr(var_))
                var = claripy.BoolS(name, explicit_name=True)
            else:
                var_ = self.claripy_ast_from_ail_condition(condition.operands[0])
                name = 'ailexpr_Conv(%d->%d, %s)' % (condition.from_bits, condition.to_bits, repr(var_))
                var = claripy.BVS(name, condition.to_bits, explicit_name=True)
            self._condition_mapping[var.args[0]] = condition
            return var
        elif isinstance(condition, ailment.Expr.Const):
            var = claripy.BVV(condition.value, condition.bits)
            return var
        elif isinstance(condition, ailment.Expr.Tmp):
            l.warning("Left-over ailment.Tmp variable %s.", condition)
            if condition.bits == 1:
                var = claripy.BoolV('ailtmp_%d' % condition.tmp_idx)
            else:
                var = claripy.BVS('ailtmp_%d' % condition.tmp_idx, condition.bits, explicit_name=True)
            self._condition_mapping[var.args[0]] = condition
            return var

        lambda_expr = _mapping.get(condition.verbose_op, None)
        if lambda_expr is None:
            raise NotImplementedError("Unsupported AIL expression operation %s. Consider implementing." % condition.op)
        r = lambda_expr(condition, self.claripy_ast_from_ail_condition)
        if r is NotImplemented:
            r = claripy.BVS("ailexpr_%r" % condition, condition.bits, explicit_name=True)
            self._condition_mapping[r.args[0]] = condition
        else:
            # don't lose tags
            r = r.annotate(TagsAnnotation(**condition.tags))
        return r
Exemplo n.º 12
0
    def claripy_ast_from_ail_condition(self, condition):

        # Unpack a condition all the way to the leaves
        if isinstance(condition, claripy.ast.Base):
            return condition

        _mapping = {
            'LogicalAnd':
            lambda expr, conv: claripy.And(conv(expr.operands[0]),
                                           conv(expr.operands[1])),
            'LogicalOr':
            lambda expr, conv: claripy.Or(conv(expr.operands[0]),
                                          conv(expr.operands[1])),
            'CmpEQ':
            lambda expr, conv: conv(expr.operands[0]) == conv(expr.operands[1]
                                                              ),
            'CmpNE':
            lambda expr, conv: conv(expr.operands[0]) != conv(expr.operands[1]
                                                              ),
            'CmpLE':
            lambda expr, conv: conv(expr.operands[0]) <= conv(expr.operands[1]
                                                              ),
            'CmpLEs':
            lambda expr, conv: claripy.SLE(conv(expr.operands[0]),
                                           conv(expr.operands[1])),
            'CmpLT':
            lambda expr, conv: conv(expr.operands[0]) < conv(expr.operands[1]),
            'CmpLTs':
            lambda expr, conv: claripy.SLT(conv(expr.operands[0]),
                                           conv(expr.operands[1])),
            'CmpGE':
            lambda expr, conv: conv(expr.operands[0]) >= conv(expr.operands[1]
                                                              ),
            'CmpGEs':
            lambda expr, conv: claripy.SGE(conv(expr.operands[0]),
                                           conv(expr.operands[1])),
            'CmpGT':
            lambda expr, conv: conv(expr.operands[0]) > conv(expr.operands[1]),
            'CmpGTs':
            lambda expr, conv: claripy.SGT(conv(expr.operands[0]),
                                           conv(expr.operands[1])),
            'Add':
            lambda expr, conv: conv(expr.operands[0]) + conv(expr.operands[1]),
            'Sub':
            lambda expr, conv: conv(expr.operands[0]) - conv(expr.operands[1]),
            'Not':
            lambda expr, conv: claripy.Not(conv(expr.operand)),
            'Xor':
            lambda expr, conv: conv(expr.operands[0]) ^ conv(expr.operands[1]),
            'And':
            lambda expr, conv: conv(expr.operands[0]) & conv(expr.operands[1]),
            'Or':
            lambda expr, conv: conv(expr.operands[0]) | conv(expr.operands[1]),
            'Shr':
            lambda expr, conv: claripy.LShR(conv(expr.operands[0]), expr.
                                            operands[1].value)
        }

        if isinstance(condition,
                      (ailment.Expr.Load, ailment.Expr.DirtyExpression,
                       ailment.Expr.BasePointerOffset)):
            var = claripy.BVS('ailexpr_%s' % repr(condition),
                              condition.bits,
                              explicit_name=True)
            self._condition_mapping[var] = condition
            return var
        elif isinstance(condition, ailment.Expr.Register):
            var = claripy.BVS('ailexpr_%s-%d' %
                              (repr(condition), condition.idx),
                              condition.bits,
                              explicit_name=True)
            self._condition_mapping[var] = condition
            return var
        elif isinstance(condition, ailment.Expr.Convert):
            # convert is special. if it generates a 1-bit variable, it should be treated as a BVS
            if condition.to_bits == 1:
                var_ = self.claripy_ast_from_ail_condition(
                    condition.operands[0])
                name = 'ailcond_Conv(%d->%d, %s)' % (
                    condition.from_bits, condition.to_bits, repr(var_))
                var = claripy.BoolS(name, explicit_name=True)
            else:
                var_ = self.claripy_ast_from_ail_condition(
                    condition.operands[0])
                name = 'ailexpr_Conv(%d->%d, %s)' % (
                    condition.from_bits, condition.to_bits, repr(var_))
                var = claripy.BVS(name, condition.to_bits, explicit_name=True)
            self._condition_mapping[var] = condition
            return var
        elif isinstance(condition, ailment.Expr.Const):
            var = claripy.BVV(condition.value, condition.bits)
            return var
        elif isinstance(condition, ailment.Expr.Tmp):
            l.warning("Left-over ailment.Tmp variable %s.", condition)
            if condition.bits == 1:
                var = claripy.BoolV('ailtmp_%d' % condition.tmp_idx)
            else:
                var = claripy.BVS('ailtmp_%d' % condition.tmp_idx,
                                  condition.bits)
            self._condition_mapping[var] = condition
            return var

        lambda_expr = _mapping.get(condition.verbose_op, None)
        if lambda_expr is None:
            raise NotImplementedError(
                "Unsupported AIL expression operation %s. Consider implementing."
                % condition.op)
        r = lambda_expr(condition, self.claripy_ast_from_ail_condition)
        if r is NotImplemented:
            r = claripy.BVS("ailexpr_%r" % condition,
                            condition.bits,
                            explicit_name=True)
            self._condition_mapping[r] = condition
        return r
Exemplo n.º 13
0
def raw_solver(solver_type):
    #bc = claripy.backends.BackendConcrete(clrp)
    #bz = claripy.backends.BackendZ3(clrp)
    #claripy.expression_backends = [ bc, bz, ba ]

    s = solver_type()

    s.simplify()

    x = claripy.BVS('x', 32)
    y = claripy.BVS('y', 32)
    z = claripy.BVS('z', 32)

    l.debug("adding constraints")

    s.add(x == 10)
    s.add(y == 15)
    l.debug("checking")
    nose.tools.assert_true(s.satisfiable())
    nose.tools.assert_false(s.satisfiable(extra_constraints=[x == 5]))
    nose.tools.assert_equal(s.eval(x + 5, 1)[0], 15)
    nose.tools.assert_true(s.solution(x + 5, 15))
    nose.tools.assert_true(s.solution(x, 10))
    nose.tools.assert_true(s.solution(y, 15))
    nose.tools.assert_false(s.solution(y, 13))

    # Batch evaluation
    results = s.batch_eval([x + 5, x + 6, 3], 2)
    nose.tools.assert_equal(len(results), 1)
    nose.tools.assert_equal(results[0][0], 15) # x + 5
    nose.tools.assert_equal(results[0][1], 16) # x + 6
    nose.tools.assert_equal(results[0][2], 3)  # constant

    shards = s.split()
    nose.tools.assert_equal(len(shards), 2)
    nose.tools.assert_equal(len(shards[0].variables), 1)
    nose.tools.assert_equal(len(shards[1].variables), 1)
    nose.tools.assert_equal({ len(shards[0].constraints), len(shards[1].constraints) }, { 2, 1 }) # adds the != from the solution() check

    # test result caching
    s = solver_type()
    s.add(x == 10)
    s.add(y == 15)
    nose.tools.assert_is(s.result, None)
    nose.tools.assert_false(s.satisfiable(extra_constraints=(x==5,)))
    nose.tools.assert_is(s.result, None)
    nose.tools.assert_true(s.satisfiable())
    nose.tools.assert_is_not(s.result, None)

    s = solver_type()
    #claripy.expression_backends = [ bc, ba, bz ]
    s.add(claripy.UGT(x, 10))
    s.add(claripy.UGT(x, 20))
    s.simplify()
    nose.tools.assert_equal(len(s.constraints), 1)
    #nose.tools.assert_equal(str(s.constraints[0]._obj), "Not(ULE(x <= 20))")

    s.add(claripy.UGT(y, x))
    s.add(claripy.ULT(z, 5))

    # test that duplicate constraints are ignored
    old_count = len(s.constraints)
    s.add(claripy.ULT(z, 5))
    nose.tools.assert_equal(len(s.constraints), old_count)

    #print "========================================================================================"
    #print "========================================================================================"
    #print "========================================================================================"
    #print "========================================================================================"
    #a = s.eval(z, 100)
    #print "ANY:", a
    #print "========================================================================================"
    #mx = s.max(z)
    #print "MAX",mx
    #print "========================================================================================"
    #mn = s.min(z)
    #print "MIN",mn
    #print "========================================================================================"
    #print "========================================================================================"
    #print "========================================================================================"
    #print "========================================================================================"

    print "CONSTRATINT COUNTS:", [ len(_.constraints) for _ in s.split() ]

    nose.tools.assert_equal(s.max(z), 4)
    nose.tools.assert_equal(s.min(z), 0)
    nose.tools.assert_equal(s.min(y), 22)
    nose.tools.assert_equal(s.max(y), 2**y.size()-1)

    print "CONSTRATINT COUNTS:", [ len(_.constraints) for _ in s.split() ]

    ss = s.split()
    nose.tools.assert_equal(len(ss), 2)
    if isinstance(s, claripy.FullFrontend):
        nose.tools.assert_equal({ len(_.constraints) for _ in ss }, { 2, 3 }) # constraints from min or max
    elif isinstance(s, claripy.CompositeFrontend):
        #nose.tools.assert_equal({ len(_.constraints) for _ in ss }, { 3, 3 }) # constraints from min or max
        print "TODO: figure out why this is different now"
        nose.tools.assert_equal({ len(_.constraints) for _ in ss }, { 2, 2 }) # constraints from min or max

    # Batch evaluation
    s.add(y < 24)
    s.add(z < x) # Just to make sure x, y, and z belong to the same solver, since batch evaluation does not support the
                 # situation where expressions belong to more than one solver
    results = s.batch_eval([x, y, z], 20)
    nose.tools.assert_set_equal(
        set(results),
        {(21L, 23L, 1L), (22L, 23L, 3L), (22L, 23L, 2L), (22L, 23L, 4L), (21L, 22L, 4L), (21L, 23L, 4L), (22L, 23L, 0L),
         (22L, 23L, 1L), (21L, 22L, 1L), (21L, 22L, 3L), (21L, 22L, 2L), (21L, 22L, 0L), (21L, 23L, 0L), (21L, 23L, 2L),
         (21L, 23L, 3L)
        }
    )

    # test that False makes it unsat
    s = solver_type()
    s.add(claripy.BVV(1,1) == claripy.BVV(1,1))
    nose.tools.assert_true(s.satisfiable())
    s.add(claripy.BVV(1,1) == claripy.BVV(0,1))
    nose.tools.assert_false(s.satisfiable())

    # test extra constraints
    s = solver_type()
    x = claripy.BVS('x', 32)
    nose.tools.assert_equal(s.eval(x, 2, extra_constraints=[x==10]), ( 10, ))
    s.add(x == 10)
    nose.tools.assert_false(s.solution(x, 2))
    nose.tools.assert_true(s.solution(x, 10))

    # test result caching

    s = solver_type()
    nose.tools.assert_true(s.satisfiable())
    s.add(claripy.BoolV(False))
    nose.tools.assert_false(s.satisfiable())
    s.result = None
    nose.tools.assert_false(s.satisfiable())

    s = solver_type()
    x = claripy.BVS('x', 32)
    s.add(x == 10)
    nose.tools.assert_true(s.satisfiable())
    nose.tools.assert_true(s.result is not None)
    nose.tools.assert_equals(s.eval(x, 1)[0], 10)
    nose.tools.assert_true(s.result is not None)
    s.add(x == 10)
    nose.tools.assert_true(s.result is not None)
    s.add(x > 9)
    nose.tools.assert_true(s.result is not None)
    s.add(x <= 11)
    nose.tools.assert_true(s.result is not None)
Exemplo n.º 14
0
    def exec_branch(self, state):  # pylint:disable=invalid-name
        """Execute forward from a state, queuing new states if needed."""
        logger.debug("Constraints: %s", state.solver.constraints)

        def solution(variable):
            """Returns the solution. There must be one or we fail."""
            solutions = state.solver.eval(variable, 2)
            if len(solutions) > 1:
                raise ValueError("Ambiguous solution for %s (%s)" %
                                 (variable, self.code[state.pc]))
            solution = solutions[0]
            return solution if isinstance(solution,
                                          numbers.Number) else solution.value

        state.score += 1
        self.code.pc = state.pc

        while True:
            if state.pc >= len(self.code):
                return True

            op = self.code.next()
            self.coverage[state.pc] += 1

            logger.debug("NEW STEP")
            logger.debug("Memory: %s", state.memory)
            logger.debug("Stack: %s", state.stack)
            logger.debug("PC: %i, %s", state.pc, op)

            assert self.code.pc == state.pc + 1
            assert isinstance(op, numbers.Number)
            assert all(
                hasattr(i, "symbolic") for i in
                state.stack), "The stack musty only contains claripy BV's"

            # Trivial operations first
            if not self.code.is_valid_opcode(state.pc):
                raise utils.CodeError("Trying to execute PUSH data")
            elif op == 254:  # INVALID opcode
                raise utils.CodeError("designed INVALID opcode")
            elif op == opcode_values.JUMPDEST:
                pass
            elif op == opcode_values.ADD:
                s0, s1 = (
                    not_bool(state.stack_pop()),
                    not_bool(state.stack_pop()),
                )  # pylint:disable=invalid-name
                state.stack_push(s0 + s1)
            elif op == opcode_values.SUB:
                s0, s1 = (
                    not_bool(state.stack_pop()),
                    not_bool(state.stack_pop()),
                )  # pylint:disable=invalid-name
                state.stack_push(s0 - s1)
            elif op == opcode_values.MUL:
                s0, s1 = (
                    not_bool(state.stack_pop()),
                    not_bool(state.stack_pop()),
                )  # pylint:disable=invalid-name
                state.stack_push(s0 * s1)
            elif op == opcode_values.DIV:
                # We need to use claripy.LShR instead of a division if possible,
                # because the solver is bad dealing with divisions, better
                # with shifts. And we need shifts to handle the solidity ABI
                # for function selection.
                s0, s1 = (
                    state.stack_pop(),
                    state.stack_pop(),
                )  # pylint:disable=invalid-name
                try:
                    s1 = solution(s1)  # pylint:disable=invalid-name
                except ValueError:
                    state.stack_push(claripy.If(s1 == 0, BVV_0, s0 / s1))
                else:
                    if s1 == 0:
                        state.stack_push(BVV_0)
                    elif s1 == 1:
                        state.stack_push(s0)
                    elif s1 & (s1 - 1) == 0:
                        exp = int(math.log(s1, 2))
                        state.stack_push(s0.LShR(exp))
                    else:
                        state.stack_push(s0 / s1)
            elif op == opcode_values.SDIV:
                s0, s1 = (
                    state.stack_pop(),
                    state.stack_pop(),
                )  # pylint:disable=invalid-name
                try:
                    s1 = solution(s1)
                except ValueError:
                    state.stack_push(claripy.If(s1 == 0, BVV_0, s0.SDiv(s1)))
                else:
                    state.stack_push(BVV_0 if s1 == 0 else s0.SDiv(s1))
            elif op == opcode_values.MOD:
                s0, s1 = (
                    state.stack_pop(),
                    state.stack_pop(),
                )  # pylint:disable=invalid-name
                try:
                    s1 = solution(s1)
                except ValueError:
                    state.stack_push(claripy.If(s1 == 0, BVV_0, s0 % s1))
                else:
                    state.stack_push(BVV_0 if s1 == 0 else s0 % s1)
            elif op == opcode_values.SMOD:
                s0, s1 = (
                    state.stack_pop(),
                    state.stack_pop(),
                )  # pylint:disable=invalid-name
                try:
                    s1 = solution(s1)
                except ValueError:
                    state.stack_push(claripy.If(s1 == 0, BVV_0, s0.SMod(s1)))
                else:
                    state.stack_push(BVV_0 if s1 == 0 else s0.SMod(s1))
            elif op == opcode_values.ADDMOD:
                s0, s1, s2 = state.stack_pop(), state.stack_pop(
                ), state.stack_pop()
                try:
                    s2 = solution(s2)
                except ValueError:
                    state.stack_push(claripy.If(s2 == 0, BVV_0,
                                                (s0 + s1) % s2))
                else:
                    state.stack_push(BVV_0 if s2 == 0 else (s0 + s1) % s2)
            elif op == opcode_values.MULMOD:
                s0, s1, s2 = state.stack_pop(), state.stack_pop(
                ), state.stack_pop()
                try:
                    s2 = solution(s2)
                except ValueError:
                    state.stack_push(claripy.If(s2 == 0, BVV_0,
                                                (s0 * s1) % s2))
                else:
                    state.stack_push(BVV_0 if s2 == 0 else (s0 * s1) % s2)
            elif op == opcode_values.EXP:
                base, exponent = solution(state.stack_pop()), state.stack_pop()
                if base == 2:
                    state.stack_push(1 << exponent)
                else:
                    exponent = solution(exponent)
                    state.stack_push(claripy.BVV(base**exponent, 256))
            elif op == opcode_values.LT:
                s0, s1 = (
                    not_bool(state.stack_pop()),
                    not_bool(state.stack_pop()),
                )  # pylint:disable=invalid-name
                state.stack_push(claripy.ULT(s0, s1))
            elif op == opcode_values.GT:
                s0, s1 = (
                    not_bool(state.stack_pop()),
                    not_bool(state.stack_pop()),
                )  # pylint:disable=invalid-name
                state.stack_push(claripy.UGT(s0, s1))
            elif op == opcode_values.SLT:
                s0, s1 = (
                    not_bool(state.stack_pop()),
                    not_bool(state.stack_pop()),
                )  # pylint:disable=invalid-name
                state.stack_push(claripy.SLT(s0, s1))
            elif op == opcode_values.SGT:
                s0, s1 = (
                    not_bool(state.stack_pop()),
                    not_bool(state.stack_pop()),
                )  # pylint:disable=invalid-name
                state.stack_push(claripy.SGT(s0, s1))
            elif op == opcode_values.SIGNEXTEND:
                s0, s1 = (
                    state.stack_pop(),
                    state.stack_pop(),
                )  # pylint:disable=invalid-name
                # s0 is the number of bits. s1 the number we want to extend.
                s0 = solution(s0)
                if s0 <= 31:
                    sign_bit = 1 << (s0 * 8 + 7)
                    state.stack_push(
                        claripy.If(
                            s1 & sign_bit == 0,
                            s1 & (sign_bit - 1),
                            s1 | ((1 << 256) - sign_bit),
                        ))
                else:
                    state.stack_push(s1)
            elif op == opcode_values.EQ:
                s0, s1 = state.stack_pop(), state.stack_pop()
                if isinstance(s0, claripy.ast.Bool) and isinstance(
                        s1, claripy.ast.Bool):
                    state.stack_push(s0 == s1)
                else:
                    state.stack_push(not_bool(s0) == not_bool(s1))
            elif op == opcode_values.ISZERO:
                condition = state.stack_pop()
                if isinstance(condition, claripy.ast.Bool):
                    state.stack_push(claripy.Not(condition))
                else:
                    state.stack_push(condition == BVV_0)
            elif op == opcode_values.AND:
                s0, s1 = make_consistent(state.stack_pop(), state.stack_pop())
                if isinstance(s0, claripy.ast.Bool) and isinstance(
                        s1, claripy.ast.Bool):
                    state.stack_push(s0 and s1)
                else:
                    state.stack_push(s0 & s1)
            elif op == opcode_values.OR:
                s0, s1 = make_consistent(state.stack_pop(), state.stack_pop())
                if isinstance(s0, claripy.ast.Bool) and isinstance(
                        s1, claripy.ast.Bool):
                    state.stack_push(s0 or s1)
                else:
                    state.stack_push(s0 | s1)
            elif op == opcode_values.XOR:
                s0, s1 = make_consistent(state.stack_pop(), state.stack_pop())
                state.stack_push(s0 ^ s1)
            elif op == opcode_values.NOT:
                state.stack_push(~state.stack_pop())
            elif op == opcode_values.BYTE:
                s0, s1 = (
                    state.stack_pop(),
                    state.stack_pop(),
                )  # pylint:disable=invalid-name
                state.stack_push(
                    s1.LShR(claripy.If(s0 > 31, 32, 31 - s0) * 8) & 0xFF)

            elif op == opcode_values.PC:
                state.stack_push(bvv(state.pc))
            elif op == opcode_values.GAS:
                state.stack_push(state.env.gas)
            elif op == opcode_values.ADDRESS:
                state.stack_push(state.env.address)
            elif op == opcode_values.BALANCE:
                addr = solution(state.stack_pop())
                if addr != solution(state.env.address):
                    raise utils.InterpreterError(
                        state,
                        "Can only query balance of the current contract for now"
                    )
                state.stack_push(state.env.balance)
            elif op == opcode_values.ORIGIN:
                state.stack_push(state.env.origin)
            elif op == opcode_values.CALLER:
                state.stack_push(state.env.caller)
            elif op == opcode_values.CALLVALUE:
                state.stack_push(state.env.value)
            elif op == opcode_values.BLOCKHASH:
                block_num = state.stack_pop()
                if block_num not in state.env.block_hashes:
                    state.env.block_hashes[block_num] = claripy.BVS(
                        "blockhash[%s]" % block_num, 256)
                state.stack_push(state.env.block_hashes[block_num])
            elif op == opcode_values.TIMESTAMP:
                state.stack_push(state.env.block_timestamp)
            elif op == opcode_values.NUMBER:
                state.stack_push(state.env.block_number)
            elif op == opcode_values.COINBASE:
                state.stack_push(state.env.coinbase)
            elif op == opcode_values.DIFFICULTY:
                state.stack_push(state.env.difficulty)
            elif op == opcode_values.POP:
                state.stack_pop()
            elif op == opcode_values.JUMP:
                addr = solution(state.stack_pop())
                if addr >= len(self.code
                               ) or self.code[addr] != opcode_values.JUMPDEST:
                    raise utils.CodeError("Invalid jump (%i)" % addr)
                state.pc = addr
                self.add_branch(state)
                return False
            elif op == opcode_values.JUMPI:
                addr, condition = solution(
                    state.stack_pop()), state.stack_pop()
                state_false = state.copy()
                if isinstance(condition, claripy.ast.Bool):
                    state.solver.add(condition)
                    state_false.solver.add(claripy.Not(condition))
                else:
                    state.solver.add(condition != 0)
                    state_false.solver.add(condition == 0)
                state_false.pc += 1
                self.add_branch(state_false)
                state.pc = addr
                if (state.pc >= len(self.code)
                        or self.code[state.pc] != opcode_values.JUMPDEST):
                    raise utils.CodeError("Invalid jump (%i)" % (state.pc - 1))
                self.add_branch(state)
                return False
            elif opcode_values.PUSH1 <= op <= opcode_values.PUSH32:
                pushnum = op - opcode_values.PUSH1 + 1
                raw_value = self.code.read(pushnum)
                state.pc += pushnum
                state.stack_push(
                    bvv(int.from_bytes(raw_value, byteorder="big")))
            elif opcode_values.DUP1 <= op <= opcode_values.DUP16:
                depth = op - opcode_values.DUP1 + 1
                state.stack_push(state.stack[-depth])
            elif opcode_values.SWAP1 <= op <= opcode_values.SWAP16:
                depth = op - opcode_values.SWAP1 + 1
                temp = state.stack[-depth - 1]
                state.stack[-depth - 1] = state.stack[-1]
                state.stack[-1] = temp
            elif opcode_values.LOG0 <= op <= opcode_values.LOG4:
                depth = op - opcode_values.LOG0
                mstart, msz = (state.stack_pop(), state.stack_pop())
                topics = [state.stack_pop() for x in range(depth)]
            elif op == opcode_values.SHA3:
                start, length = solution(state.stack_pop()), solution(
                    state.stack_pop())
                memory = state.memory.read(start, length)
                state.stack_push(Sha3(memory))
            elif op == opcode_values.STOP:
                return True
            elif op == opcode_values.RETURN:
                return True

            elif op == opcode_values.CALLDATALOAD:
                indexes = state.stack_pop()
                try:
                    index = solution(indexes)
                except ValueError:  # Multiple solutions, let's fuzz.
                    state.stack_push(indexes)  # restore the stack
                    self.add_for_fuzzing(state, indexes, CALLDATASIZE_FUZZ)
                    return False
                state.solver.add(state.env.calldata_size >= index + 32)
                state.stack_push(state.env.calldata.read(index, 32))
            elif op == opcode_values.CALLDATASIZE:
                state.stack_push(state.env.calldata_size)
            elif op == opcode_values.CALLDATACOPY:
                old_state = state.copy()
                mstart, dstart, size = (
                    state.stack_pop(),
                    state.stack_pop(),
                    state.stack_pop(),
                )
                mstart, dstart = solution(mstart), solution(dstart)
                try:
                    size = solution(size)
                except ValueError:
                    self.add_for_fuzzing(old_state, size, CALLDATASIZE_FUZZ)
                    return False
                state.memory.copy_from(state.env.calldata, mstart, dstart,
                                       size)
                state.solver.add(state.env.calldata_size >= dstart + size)
            elif op == opcode_values.CODESIZE:
                state.stack_push(bvv(len(self.code)))
            elif op == opcode_values.EXTCODESIZE:
                addr = state.stack_pop()
                if (addr == state.env.address).is_true():
                    state.stack_push(bvv(len(self.code)))
                else:
                    # TODO: Improve that... It's clearly not constraining enough.
                    state.stack_push(claripy.BVS("EXTCODESIZE[%s]" % addr,
                                                 256))
            elif op == opcode_values.CODECOPY:
                mem_start, code_start, size = [
                    solution(state.stack_pop()) for _ in range(3)
                ]
                for i in range(size):
                    if code_start + i < len(state.env.code):
                        state.memory.write(
                            mem_start + i,
                            1,
                            claripy.BVV(state.env.code[code_start + i], 8),
                        )
                    else:
                        state.memory.write(mem_start + i, 1, claripy.BVV(0, 8))

            elif op == opcode_values.MLOAD:
                index = solution(state.stack_pop())
                state.stack_push(state.memory.read(index, 32))
            elif op == opcode_values.MSTORE:
                index, value = solution(state.stack_pop()), not_bool(
                    state.stack_pop())
                state.memory.write(index, 32, value)
            elif op == opcode_values.MSTORE8:
                index, value = solution(state.stack_pop()), not_bool(
                    state.stack_pop())
                state.memory.write(index, 1, value[7:0])
            elif op == opcode_values.MSIZE:
                state.stack_push(bvv(state.memory.size()))
            elif op == opcode_values.SLOAD:
                # TODO: This is inaccurate, because the storage can change
                # in a single transaction.
                # See commit d98cab834f8f359f01ef805256d179f5529ebe30.
                key = state.stack_pop()
                if key in state.storage_written:
                    state.stack_push(state.storage_written[key])
                else:
                    if key not in state.storage_read:
                        state.storage_read[key] = claripy.BVS(
                            "storage[%s]" % key, 256)
                    state.stack_push(state.storage_read[key])
            elif op == opcode_values.SSTORE:
                # TODO: This is inaccurate, because the storage can change
                # in a single transaction.
                # See commit d98cab834f8f359f01ef805256d179f5529ebe30.
                key = state.stack_pop()
                value = state.stack_pop()
                state.storage_written[key] = value

            elif op == opcode_values.CALL:
                state.pc += 1

                # First possibility: the call fails
                # (always possible with a call stack big enough)
                state_fail = state.copy()
                state_fail.stack_push(claripy.BoolV(False))
                self.add_branch(state_fail)

                # Second possibility: success.
                state.calls.append(state.stack[-7:])

                # pylint:disable=unused-variable
                gas, to_, value, meminstart, meminsz, memoutstart, memoutsz = (
                    state.stack_pop() for _ in range(7))

                if solution(memoutsz) != 0:
                    raise utils.InterpreterError(state,
                                                 "CALL seems to return data")
                if solution(meminsz) != 0:
                    raise utils.InterpreterError(state,
                                                 "CALL seems to take data")

                state.stack_push(claripy.BoolV(True))
                self.add_branch(state)
                return False

            elif op == opcode_values.SELFDESTRUCT:
                state.selfdestruct_to = state.stack[-1]
                return True

            elif op == opcode_values.REVERT:
                return False
            else:
                raise utils.InterpreterError(state, "Unknown opcode %s" % op)

            state.pc += 1
Exemplo n.º 15
0
def ast_prove_f1_in_f2(f1, f2, c1=None, c2=None):
    # we merely prove the f1==f2 in the interval of join(c1, c2)
    input1 = get_expression_input(f1)
    input2 = get_expression_input(f2)
    if c1:
        for tmp in c1:
            input1.update(get_expression_input(tmp))
    if c2:
        for tmp in c2:
            input2.update(get_expression_input(tmp))
    input1 = list(input1)
    input2 = list(input2)

    print("f0:=%s\nf1:=%s\ninput0:=%s\ninput1:=%s\ncons0:=%s\ncons1:=%s" %
          (str(f1), str(f2), str(input1), str(input2), str(c1), str(c2)))
    print("%d / %d\n" % (len(input1), len(input2)))

    # we think f2 is always more complex than f1
    if len(input2) < len(input1):
        return False

    # compute the number of permutations
    permute_variables = len(input1)
    num_permutations = len(input2)
    for _i in range(len(input1)):
        num_permutations *= len(input2) - _i
    if len(input1) > 3 or num_permutations > 1000:
        # too many permutations, it wastes too much time
        # assigning same value to several input sources
        # merely permute the first 3 variables
        permute_variables = 3
    unsat_expr = claripy.ast.Bool(op='__ne__', args=(f1, f2))
    sat_expr = claripy.ast.Bool(op='__eq__', args=(f1, f2))
    ec2 = claripy.And(*[claripy.ast.Bool(op='__eq__', args=(claripy.Or(*c1), claripy.BoolV(True))),
                        claripy.ast.Bool(op='__eq__', args=(claripy.Or(*c2), claripy.BoolV(True)))])

    for in2 in permutations(input2, permute_variables):
        ec1 = []
        try:
            solver = claripy.Solver(backend=_MyBackendZ3())
            # symbolic input constraints
            for idx in range(len(in2)):
                ec1.append(claripy.ast.Bool(op='__eq__', args=(input1[idx], in2[idx])))
            ec1 = claripy.And(*ec1)
            solver.add(ec2)
            solver.add(ec1)
            if permute_variables == len(input1):
                # we do not need to concrete symbolic values here
                if solver.satisfiable(extra_constraints=[sat_expr]):
                    solver.add(unsat_expr)
                    if not solver.satisfiable():
                        return True
            else:
                # permute_variables < len(input1), we concrete all other variables of f1 and f2 to same value
                for concrete_value in [0, 1, 0xffffff]:
                    ec3 = []
                    for i in range(permute_variables, len(input1)):
                        ec3.append(input1[i] == concrete_value)
                    in2_var_names = set([var._encoded_name for var in in2])
                    for i in range(len(input2)):
                        if input2[i]._encoded_name not in in2_var_names:
                            ec3.append(input2[i] == concrete_value)
                    ec3 = claripy.And(*ec3)
                    # finally solve here repeatedly
                    if solver.satisfiable(extra_constraints=[sat_expr, ec3]):
                        if not solver.satisfiable([unsat_expr, ec3]):
                            return True
        except Exception as e:
            log.warning('Meet Z3 solver error %s' % str(e))
    return False