Esempio n. 1
0
    def _max(self,
             expr,
             extra_constraints=(),
             solver=None,
             model_callback=None):
        global solve_count

        lo = 0
        hi = 2**expr.size() - 1
        vals = set()

        numpop = 0
        if len(extra_constraints) > 0:
            solver.push()
            numpop += 1
            solver.add(*[self.convert(e) for e in extra_constraints])

        # TODO: Can only deal with bitvectors, not floats
        while hi - lo > 1:
            middle = (lo + hi) // 2
            #l.debug("h/m/l/d: %d %d %d %d", hi, middle, lo, hi-lo)

            solver.push()
            solver.add(z3.UGT(expr, middle), z3.ULE(expr, hi))
            numpop += 1

            solve_count += 1
            l.debug("Doing a check!")
            if solver.check() == z3.sat:
                l.debug("... still sat")
                lo = middle
                vals.add(self._primitive_from_model(solver.model(), expr))
                if model_callback is not None:
                    model_callback(self._generic_model(solver.model()))
            else:
                l.debug("... now unsat")
                hi = middle
                solver.pop()
                numpop -= 1
            #l.debug("          now: %d %d %d %d", hi, middle, lo, hi-lo)

        for _ in range(numpop):
            solver.pop()

        if hi == lo:
            vals.add(hi)
        else:
            solver.push()
            solver.add(expr == hi)
            l.debug("Doing a check!")
            if solver.check() == z3.sat:
                if model_callback is not None:
                    model_callback(self._generic_model(solver.model()))
                vals.add(hi)
                solver.pop()
            else:
                vals.add(lo)
                solver.pop()

        return max(vals)
Esempio n. 2
0
    def _z3Clauses(self, prefix):
        self.bitvec = z3.BitVec('_bv_in_range_%s_%s_' % (prefix, self.name), self.width)
        exprs = []

        loz3 = self.lo.toZ3(prefix)
        hiz3 = self.hi.toZ3(prefix)

        r1 = self.lo.z3Clauses(prefix)
        r2 = self.hi.z3Clauses(prefix)
        if r1: exprs.append(r1)
        if r2: exprs.append(r2)

        exprs.append(z3.ULE(loz3, self.bitvec))
        exprs.append(z3.ULE(self.bitvec, hiz3))

        return z3.And(*exprs)
Esempio n. 3
0
 def ULE(self, other):
     if isinstance(other, int):
         other = BVV(other, self.size)
     else:
         assert isinstance(other, BV)
         assert self.size == other.size
     return BoolExpr(z3.ULE(self.z3obj, other.z3obj))
Esempio n. 4
0
    def _min(self,
             expr,
             extra_constraints=(),
             solver=None,
             model_callback=None):
        global solve_count

        lo = 0
        hi = 2**expr.size() - 1
        vals = set()

        numpop = 0
        if len(extra_constraints) > 0:
            solver.push()
            numpop += 1
            solver.add(*[self.convert(e) for e in extra_constraints])

        while hi - lo > 1:
            middle = (lo + hi) / 2
            #l.debug("h/m/l/d: %d %d %d %d", hi, middle, lo, hi-lo)

            solver.push()
            solver.add(z3.UGE(expr, lo), z3.ULE(expr, middle))
            numpop += 1

            solve_count += 1
            l.debug("Doing a check!")
            if solver.check() == z3.sat:
                l.debug("... still sat")
                if model_callback is not None:
                    model_callback(self._generic_model(solver.model()))
                vals.add(self._primitive_from_model(solver.model(), expr))
                hi = middle
            else:
                l.debug("... now unsat")
                lo = middle
                solver.pop()
                numpop -= 1

        for _ in range(numpop):
            solver.pop()

        #l.debug("final hi/lo: %d, %d", hi, lo)

        if hi == lo: return lo
        else:
            solver.push()
            solver.add(expr == lo)
            l.debug("Doing a check!")
            if solver.check() == z3.sat:
                if model_callback is not None:
                    model_callback(self._generic_model(solver.model()))
                vals.add(lo)
                solver.pop()
            else:
                vals.add(hi)
                solver.pop()

        return min(vals)
Esempio n. 5
0
def _signbits(term, smt):
    x = smt.eval(term._args[0])
    ty = smt.type(term)

    #b = ComputeNumSignBits(smt.fresh_bv(size), size)
    b = smt.fresh_var(ty, 'ana_')

    smt.add_defs(z3.ULE(b, ComputeNumSignBits(ty.width, x)))

    return b
Esempio n. 6
0
    def _max_values(self,
                    expr,
                    extra_constraints=(),
                    result=None,
                    solver=None):
        global solve_count

        lo = 0
        hi = 2**expr.size() - 1
        vals = set()

        numpop = 0
        if len(extra_constraints) > 0:
            solver.push()
            numpop += 1
            solver.add(*[self.convert(e) for e in extra_constraints])

        while hi - lo > 1:
            middle = (lo + hi) / 2
            #l.debug("h/m/l/d: %d %d %d %d", hi, middle, lo, hi-lo)

            solver.push()
            solver.add(z3.UGT(expr, middle), z3.ULE(expr, hi))
            numpop += 1

            solve_count += 1
            l.debug("Doing a check!")
            if solver.check() == z3.sat:
                l.debug("... still sat")
                lo = middle
                vals.add(self._primitive_from_model(solver.model(), expr))
            else:
                l.debug("... now unsat")
                hi = middle
                solver.pop()
                numpop -= 1
            #l.debug("        now: %d %d %d %d", hi, middle, lo, hi-lo)

        for _ in range(numpop):
            solver.pop()

        if hi == lo:
            vals.add(hi)
        else:
            solver.push()
            solver.add(expr == hi)
            l.debug("Doing a check!")
            if solver.check() == z3.sat:
                vals.add(hi)
                solver.pop()
            else:
                vals.add(lo)
                solver.pop()

        return vals
Esempio n. 7
0
            def newf(*args):
                assert len(args) == len(dst_end_args)
                cond = []
                for a, b in zip(args[:-1], dst_start_args[:-1]):
                    cond.append(a == b)

                cond.append(z3.UGE(args[-1], dst_start_args[-1]))
                cond.append(z3.ULE(args[-1], dst_end_args[-1]))

                cond = z3.And(*cond)

                return util.If(cond, z3.BitVecVal(0, write_size), dstfn(*args))
Esempio n. 8
0
def main():
    global dse, todo, current
    sys.setrecursionlimit(2000)  # oof
    # Parse arguments
    parser = Sandbox_Win_x86_64.parser(description="PE sandboxer")
    parser.add_argument("filename", help="PE Filename")
    options = parser.parse_args()
    options.dependencies = True  # So we dont need to reimplement qt
    sb = Sandbox_Win_x86_64(LocationDB(),
                            options.filename,
                            options,
                            custom_methods=qt_methods)
    sb.jitter.add_breakpoint(end_ptr, stop_exec)  # End condition
    # Setup the qt string memory and a pointer to it
    sb.jitter.vm.add_memory_page(0x10000018, PAGE_READ | PAGE_WRITE,
                                 pck64(0x20000000))  # Hooking in here
    sb.jitter.vm.add_memory_page(0x20000000, PAGE_READ | PAGE_WRITE,
                                 qtstring)  # The initial qstring
    sb.jitter.vm.add_memory_page(0x10000020, PAGE_READ | PAGE_WRITE,
                                 b'\x00')  # The result
    sb.jitter.cpu.R15 = 0x10000000
    sb.jitter.cpu.RSP = sb.jitter.stack_base + 0x8000
    # Setup and attach the DSE
    dse = DSEPC(sb.machine,
                sb.loc_db,
                produce_solution=DSEPC.PRODUCE_SOLUTION_PATH_COV)
    sb.jitter.init_run(0x140004B61)
    dse.attach(sb.jitter)
    dse.update_state_from_concrete()
    dse.symbolize_memory(interval([(flag_ptr, flag_ptr + 0x20)]))
    # Printable unicode only
    for address in range(flag_ptr, flag_ptr + 0x20, 0x2):
        z3_mem = dse.z3_trans.from_expr(
            dse.eval_expr(ExprMem(ExprInt(address, 64), 16)))
        unicode_constraint = z3.And( \
                                z3.UGE(z3_mem, dse.z3_trans.from_expr(ExprInt(0x0020, 16))), \
                                z3.ULE(z3_mem, dse.z3_trans.from_expr(ExprInt(0x007E, 16))) \
                                )
        dse.cur_solver.add(unicode_constraint)
    snapshot = dse.take_snapshot()
    # Begin run
    todo = [b'\x41\x00' * 0x10]
    while todo:
        dse.restore_snapshot(snapshot)
        current = todo.pop()
        sb.jitter.vm.set_mem(flag_ptr,
                             current)  # Update the password in jitter memory
        print('-' * 40 + f' CONCRETE: {unicode_string(current)}')
        sb.jitter.continue_run()
Esempio n. 9
0
def sys_send(old, pid, val, pn, size, fd):
    cond = z3.And(
        is_pid_valid(pid),
        old.procs[pid].state == dt.proc_state.PROC_SLEEPING,

        is_pn_valid(pn),
        old.pages[pn].owner == old.current,

        z3.ULE(size, dt.PAGE_SIZE),

        z3.Implies(is_fd_valid(fd),
                   is_fn_valid(old.procs[old.current].ofile(fd))),
    )

    new = old.copy()

    new.procs[pid].ipc_from = old.current
    new.procs[pid].ipc_val = val
    new.procs[pid].ipc_size = size

    # memcpy
    new.pages.data = lambda pn0, idx0, oldfn: \
        util.If(z3.And(pn0 == old.procs[pid].ipc_page, z3.ULT(idx0, size)),
                oldfn(pn, idx0),
                oldfn(pn0, idx0))

    ########
    new2 = new.copy()

    cond2 = z3.And(is_fd_valid(fd), is_fd_valid(new2.procs[pid].ipc_fd))

    fn = old.procs[old.current].ofile(fd)
    fd = old.procs[pid].ipc_fd

    new2.procs[pid].ofile[fd] = fn

    # bump proc nr_fds
    new2.procs[pid].nr_fds[fd] += 1

    # bump file refcnt
    new2.files[fn].refcnt[(pid, fd)] += 1

    new3 = util.If(cond2, new2, new)

    new3.procs[pid].state = dt.proc_state.PROC_RUNNING
    new3.procs[old.current].state = dt.proc_state.PROC_RUNNABLE
    new3.current = pid

    return cond, util.If(cond, new3, old)
Esempio n. 10
0
def _uitofp(term, smt):
  v = smt.eval(term.arg)
  src = smt.type(term.arg)
  tgt = smt.type(term)

  w = 2**(tgt.exp-1)

  if src.width >= w:
    m = 2**w
    conds = [z3.ULE(v, m)]
  else:
    conds = []

  return smt._conditional_conv_value(conds,
    z3.fpToFPUnsigned(z3.get_default_rounding_mode(), v, _ty_sort(tgt)),
    term.name)
Esempio n. 11
0
 def ComparisonToSmt(self):
     assert (VertexNode.OpCode.IsComparison(self.operator))
     lhs = self.operands[0].VertexNameToSmt()
     rhs = self.operands[1].VertexNameToSmt()
     if self.operator == VertexNode.OpCode.GT:
         return z3.UGT(lhs, rhs)
     elif self.operator == VertexNode.OpCode.GE:
         return z3.UGE(lhs, rhs)
     elif self.operator == VertexNode.OpCode.LT:
         return z3.ULT(lhs, rhs)
     elif self.operator == VertexNode.OpCode.LE:
         return z3.ULE(lhs, rhs)
     elif self.operator == VertexNode.OpCode.EQ:
         return (lhs == rhs)
     elif self.operator == VertexNode.OpCode.NE:
         return (lhs != rhs)
Esempio n. 12
0
    def _min(self, expr, extra_constraints=(), result=None, solver=None):
        global solve_count

        lo = 0
        hi = 2**expr.size()-1

        numpop = 0
        if len(extra_constraints) > 0:
            solver.push()
            numpop += 1
            solver.add(*[self.convert(e) for e in extra_constraints])

        while hi-lo > 1:
            middle = (lo + hi)/2
            #l.debug("h/m/l/d: %d %d %d %d", hi, middle, lo, hi-lo)

            solver.push()
            solver.add(z3.UGE(expr, lo), z3.ULE(expr, middle))
            numpop += 1

            solve_count += 1
            l.debug("Doing a check!")
            if solver.check() == z3.sat:
                l.debug("... still sat")
                hi = middle
            else:
                l.debug("... now unsat")
                lo = middle
                solver.pop()
                numpop -= 1

        for _ in range(numpop):
            solver.pop()

        #l.debug("final hi/lo: %d, %d", hi, lo)

        if hi == lo: return NativeBVV(lo, expr.size())
        else:
            solver.push()
            solver.add(expr == lo)
            l.debug("Doing a check!")
            if solver.check() == z3.sat:
                solver.pop()
                return NativeBVV(lo, expr.size())
            else:
                solver.pop()
        return NativeBVV(hi, expr.size())
Esempio n. 13
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. 14
0
    def from_ExprOp(self, expr):
        args = list(map(self.from_expr, expr.args))
        res = args[0]

        if len(args) > 1:
            for arg in args[1:]:
                if expr.op in self.trivial_ops:
                    res = eval("res %s arg" % expr.op)
                elif expr.op == ">>":
                    res = z3.LShR(res, arg)
                elif expr.op == "a>>":
                    res = res >> arg
                elif expr.op == "<<<":
                    res = z3.RotateLeft(res, arg)
                elif expr.op == ">>>":
                    res = z3.RotateRight(res, arg)
                elif expr.op == "sdiv":
                    res = self._sdivC(res, arg)
                elif expr.op == "udiv":
                    res = z3.UDiv(res, arg)
                elif expr.op == "smod":
                    res = res - (arg * (self._sdivC(res, arg)))
                elif expr.op == "umod":
                    res = z3.URem(res, arg)
                elif expr.op == "==":
                    res = z3.If(args[0] == args[1], z3.BitVecVal(1, 1),
                                z3.BitVecVal(0, 1))
                elif expr.op == "<u":
                    res = z3.If(z3.ULT(args[0], args[1]), z3.BitVecVal(1, 1),
                                z3.BitVecVal(0, 1))
                elif expr.op == "<s":
                    res = z3.If(args[0] < args[1], z3.BitVecVal(1, 1),
                                z3.BitVecVal(0, 1))
                elif expr.op == "<=u":
                    res = z3.If(z3.ULE(args[0], args[1]), z3.BitVecVal(1, 1),
                                z3.BitVecVal(0, 1))
                elif expr.op == "<=s":
                    res = z3.If(args[0] <= args[1], z3.BitVecVal(1, 1),
                                z3.BitVecVal(0, 1))
                else:
                    raise NotImplementedError("Unsupported OP yet: %s" %
                                              expr.op)
        elif expr.op == 'parity':
            arg = z3.Extract(7, 0, res)
            res = z3.BitVecVal(1, 1)
            for i in range(8):
                res = res ^ z3.Extract(i, i, arg)
        elif expr.op == '-':
            res = -res
        elif expr.op == "cnttrailzeros":
            size = expr.size
            src = res
            res = z3.If(src == 0, size, src)
            for i in range(size - 1, -1, -1):
                res = z3.If((src & (1 << i)) != 0, i, res)
        elif expr.op == "cntleadzeros":
            size = expr.size
            src = res
            res = z3.If(src == 0, size, src)
            for i in range(size, 0, -1):
                index = -i % size
                out = size - (index + 1)
                res = z3.If((src & (1 << index)) != 0, out, res)
        elif expr.op.startswith("zeroExt"):
            arg, = expr.args
            res = z3.ZeroExt(expr.size - arg.size, self.from_expr(arg))
        elif expr.op.startswith("signExt"):
            arg, = expr.args
            res = z3.SignExt(expr.size - arg.size, self.from_expr(arg))
        else:
            raise NotImplementedError("Unsupported OP yet: %s" % expr.op)

        return res
Esempio n. 15
0
def send_recv(old, pid, val, inpn, size, infd, outpn, outfd):
    cond = z3.And(
        is_pid_valid(pid),

        old.procs[pid].state == dt.proc_state.PROC_SLEEPING,

        # inpn is a valid pn and belongs to current
        is_pn_valid(inpn),
        old.pages[inpn].owner == old.current,

        z3.ULE(size, dt.PAGE_SIZE),

        z3.Implies(is_fd_valid(infd),
                   is_fn_valid(old.procs[old.current].ofile(infd))),

        # outpn is a valid pn and belongs to current
        is_pn_valid(outpn),
        old.pages[outpn].owner == old.current,
        old.pages[outpn].type == dt.page_type.PAGE_TYPE_FRAME,

        z3.Implies(is_fd_valid(outfd),
                   z3.Not(is_fn_valid(old.procs[old.current].ofile(outfd)))),

        # if ipc from is set, it must be set to current
        z3.Implies(old.procs[pid].ipc_from != 0,
                   old.procs[pid].ipc_from == old.current)
    )

    new = old.copy()

    new.procs[old.current].ipc_page = outpn
    new.procs[old.current].ipc_fd = outfd

    new.procs[pid].ipc_from = old.current
    new.procs[pid].ipc_val = val

    # memcpy
    new.pages.data = lambda pn0, idx0, oldfn=new.pages.data: \
        util.If(z3.And(pn0 == old.procs[pid].ipc_page, z3.ULT(idx0, size)),
                oldfn(inpn, idx0),
                oldfn(pn0, idx0))

    new.procs[pid].ipc_size = size

    new2 = new.copy()

    cond2 = z3.And(is_fd_valid(infd), is_fd_valid(new2.procs[pid].ipc_fd))

    fn = old.procs[old.current].ofile(infd)
    fd = old.procs[pid].ipc_fd

    new2.procs[pid].ofile[fd] = fn

    # bump proc nr_fds
    new2.procs[pid].nr_fds[fd] += 1

    # bump file refcnt
    new2.files[fn].refcnt[(pid, fd)] += 1

    new3 = util.If(cond2, new2, new)

    new3.procs[old.current].state = dt.proc_state.PROC_SLEEPING
    new3.procs[pid].state = dt.proc_state.PROC_RUNNING

    return cond, util.If(cond, new3, old)
Esempio n. 16
0
        ExprOp(">>>", ExprInt8(4), a),
        ExprOp(">>>", a, ExprInt8(4)),
        ExprOp(">>>", a, a),
        ExprOp(">>>", a[1:2].zeroExtend(8) + ExprInt8(1), ExprCond(a[0:1], ExprInt8(5), ExprInt8(18))),

        # Fuzzed by ExprRandom, with previous bug
        ExprSlice(ExprSlice(ExprOp('<<<', ExprInt(0x7FBE84D6, 51), ExprId('WYBZj', 51)), 6, 48), 3, 35),
        ExprOp('>>>', ExprOp('-', ExprOp('&', ExprInt(0x347384F7, 32), ExprId('oIkka', 32), ExprId('jSfOB', 32), ExprId('dUXBp', 32), ExprInt(0x7169DEAA, 32))), ExprId('kMVuR', 32)),
        ExprOp('|', ExprInt(0x94A3AB47, 32), ExprCompose(ExprId('dTSkf', 21), ExprOp('>>', ExprInt(0x24, 8), ExprId('HTHES', 8)), ExprId('WHNIZ', 1), ExprMem(ExprInt(0x100, 9), 1), ExprId('kPQck', 1))),
        ExprOp('<<<', ExprOp('<<<', ExprCompose(ExprId('OOfuB', 6), ExprInt(0x24, 11), ExprInt(0xE8C, 12), ExprId('jbUWR', 1), ExprInt(0x2, 2)), ExprId('mLlTH', 32)), ExprInt(0xE600B6B2, 32)),

]:
    computed_range = expr_range(expr)
    print expr, computed_range

    # Trivia checks
    assert all(x[1] < (1 << expr.size) for x in computed_range)

    # Check against z3
    s = z3.Solver()
    cond = []

    ## Constraint expr to be in computed intervals
    z3_expr = trans.from_expr(expr)
    for mini, maxi in computed_range:
        cond.append(z3.And(z3.ULE(mini, z3_expr), z3.ULE(z3_expr, maxi)))

    ## Ask for a solution outside intervals (should not exists)
    s.add(z3.Not(z3.Or(*cond)))
    assert s.check() == z3.unsat
Esempio n. 17
0
 def bvule(self, other):
     return self.get_family().Bit(z3.ULE(self.value, other.value))
Esempio n. 18
0
 def ule(self, other):
     return Bool(z3.ULE(self.symbol, other.symbol))
Esempio n. 19
0
 def walk_bv_ule(self, formula, args, **kwargs):
     return z3.ULE(args[0], args[1])
Esempio n. 20
0
 def semantics(self, a, b):
     return z3.If(z3.ULE(a, b), z3.BitVecVal(-1, 32, self.ctx),
                  z3.BitVecVal(0, 32, self.ctx))
Esempio n. 21
0
    def VertexOperationToSmt(self):
        assert (self.type != VertexNode.VertexType.NONE)

        if self.type == VertexNode.VertexType.VAR:
            # Possible Vertex : input Variable, name = operand1
            # input variable: there is nothing to do.
            # assigned Variable: name = operands[0]

            # It's an input variable if there is no operand :
            if self.operands == None: return None
            # otherwise, it's an assigned variable, but make sure just in case
            assert (self.operator == VertexNode.OpCode.ASSIGN)
            return self.VertexNameToSmt() == self.operands[0].VertexNameToSmt()

        elif self.type == VertexNode.VertexType.TEMP:
            # Possible Vertex : Function Call, Array Load, Binary Operation, Comparison,
            #                   Conditional Assignment, Unary Operation
            # function call: name = func_name(arguments)
            # array load: name = array[index]
            # binary operation: name = operand1 op operand2
            # comparison: name = operand1 comp operand2
            # conditional assignment: name = ite(operand1, operand2, operand3)
            # unary operation: name = op operand1

            # It's a function call
            if self.operator == VertexNode.OpCode.FUNCCALL:
                assert (self.operands[0].type == VertexNode.VertexType.FUNC)
                # There are four possible functions that can last until now:
                if self.operands[0].name == "merge":
                    args = []
                    for op in self.operands[1:]:
                        args.append(op.VertexNameToSmt())
                    return self.VertexNameToSmt() == z3.Concat(args)
                elif self.operands[0].name == "split":
                    toSplit = self.operands[1].VertexNameToSmt()
                    # Extract requires actual numerical value.
                    lowerBound = self.operands[2].value
                    upperBound = self.operands[3].value
                    return self.VertexNameToSmt() == z3.Extract(
                        upperBound, lowerBound, toSplit)
                elif self.operands[0].name == "zeroext":
                    toExtend = self.operands[1].VertexNameToSmt()
                    # ZeroExt requires actual numerical value
                    n = self.operands[2].value
                    return self.VertexNameToSmt() == z3.ZeroExt(n, toExtend)
                elif self.operands[0].name == "concat":
                    args = []
                    for op in self.operands[1:]:
                        args.append(op.VertexNameToSmt())
                    return self.VertexNameToSmt() == z3.Concat(args)

            # It's an array load
            elif self.operator == VertexNode.OpCode.LOAD:
                array = self.operands[0].VertexNameToSmt()
                arrayIndex = self.operands[1].VertexNameToSmt()
                return self.VertexNameToSmt() == z3.Select(array, arrayIndex)

            # It's a conditional statement
            elif self.operator == VertexNode.OpCode.CONDITIONAL:
                cond = self.operands[0].VertexNameToSmt()
                truePath = self.operands[1].VertexNameToSmt()
                falsePath = self.operands[2].VertexNameToSmt()
                return self.VertexNameToSmt() == z3.If(cond, truePath,
                                                       falsePath)

            # It's a comparison (x < y)
            elif VertexNode.OpCode.IsComparison(self.operator):
                lhs = self.operands[0].VertexNameToSmt()
                rhs = self.operands[1].VertexNameToSmt()
                if self.operator == VertexNode.OpCode.GT:
                    return self.VertexNameToSmt() == z3.UGT(lhs, rhs)
                elif self.operator == VertexNode.OpCode.GE:
                    return self.VertexNameToSmt() == z3.UGE(lhs, rhs)
                elif self.operator == VertexNode.OpCode.LT:
                    return self.VertexNameToSmt() == z3.ULT(lhs, rhs)
                elif self.operator == VertexNode.OpCode.LE:
                    return self.VertexNameToSmt() == z3.ULE(lhs, rhs)
                elif self.operator == VertexNode.OpCode.EQ:
                    return self.VertexNameToSmt() == (lhs == rhs)
                elif self.operator == VertexNode.OpCode.NE:
                    return self.VertexNameToSmt() == (lhs != rhs)

            # It's a binary operation
            elif VertexNode.OpCode.IsBinaryOp(self.operator):
                lhs = self.operands[0].VertexNameToSmt()
                rhs = self.operands[1].VertexNameToSmt()
                if self.operator == VertexNode.OpCode.PLUS:
                    return self.VertexNameToSmt() == (lhs + rhs)
                elif self.operator == VertexNode.OpCode.MINUS:
                    return self.VertexNameToSmt() == (lhs - rhs)
                elif self.operator == VertexNode.OpCode.AND:
                    return self.VertexNameToSmt() == (lhs & rhs)
                elif self.operator == VertexNode.OpCode.OR:
                    return self.VertexNameToSmt() == (lhs | rhs)
                elif self.operator == VertexNode.OpCode.XOR:
                    return self.VertexNameToSmt() == (lhs ^ rhs)
                elif self.operator == VertexNode.OpCode.SHL:
                    return self.VertexNameToSmt() == (lhs << rhs)
                elif self.operator == VertexNode.OpCode.SHR:
                    return self.VertexNameToSmt() == (z3.LShR(lhs, rhs))
                elif self.operator == VertexNode.OpCode.ROL:
                    return self.VertexNameToSmt() == (z3.RotateLeft(lhs, rhs))
                elif self.operator == VertexNode.OpCode.ROR:
                    return self.VertexNameToSmt() == (z3.RotateRight(lhs, rhs))
                elif self.operator == VertexNode.OpCode.MUL:
                    return self.VertexNameToSmt() == (lhs * rhs)
                elif self.operator == VertexNnode.OpCode.DIV:
                    return self.VertexNameToSmt() == (lhs / rhs)

            # It's a unary operation
            elif VertexNode.OpCode.IsUnaryOp(self.operator):
                rhs = self.operands[0].VertexNameToSmt()
                if self.operator == VertexNode.OpCode.NOT:
                    return self.VertexNameToSmt() == ~rhs

        elif self.type == VertexNode.VertexType.IMM:
            # Possible Vertex : Immediate Value
            return None
        elif self.type == VertexNode.VertexType.ARR:
            # Possible Vertex : Input array, array store
            # input array: there is nothing to do
            # array store: newarray = store(array, index, value)

            # if operator == None, it's an "input" array
            if self.operator == None: return None
            if self.operator == VertexNode.OpCode.NONE: return None
            # Otherwise, it must be an array store operation vertex
            assert (self.operator == VertexNode.OpCode.STORE)
            oldArray = self.operands[0].VertexNameToSmt()
            index = self.operands[1].VertexNameToSmt()
            value = self.operands[2].VertexNameToSmt()
            newArray = self.VertexNameToSmt()
            return newArray == z3.Store(oldArray, index, value)

        elif self.type == VertexNode.VertexType.FUNC:
            # Possible Vertex : Name of the function
            return None
Esempio n. 22
0
    x1 = ExprId("x1", 32)
    x2 = ExprId("x2", 32)
    i1_tmp = ExprInt(1, 1)

    x1_z3 = trans.from_expr(x1)
    x2_z3 = trans.from_expr(x2)
    i1_z3 = trans.from_expr(i1_tmp)

    # (Assumptions, function(arg1, arg2) -> True/False (= i1/i0) to check)
    tests = [
        (x1_z3 == x2_z3, expr_is_equal),
        (x1_z3 != x2_z3, expr_is_not_equal),
        (z3.UGT(x1_z3, x2_z3), expr_is_unsigned_greater),
        (z3.UGE(x1_z3, x2_z3), expr_is_unsigned_greater_or_equal),
        (z3.ULT(x1_z3, x2_z3), expr_is_unsigned_lower),
        (z3.ULE(x1_z3, x2_z3), expr_is_unsigned_lower_or_equal),
        (x1_z3 > x2_z3, expr_is_signed_greater),
        (x1_z3 >= x2_z3, expr_is_signed_greater_or_equal),
        (x1_z3 < x2_z3, expr_is_signed_lower),
        (x1_z3 <= x2_z3, expr_is_signed_lower_or_equal),
    ]

    for assumption, func in tests:
        solver = z3.Solver()
        solver.add(assumption)
        solver.add(trans.from_expr(func(x1, x2)) != i1_z3)
        assert solver.check() == z3.unsat

x = ExprId('x', 32)
y = ExprId('y', 32)
z = ExprId('z', 32)
Esempio n. 23
0
    def sym_call_address(self, address, wstate, method=None, arguments=None, amount=None, timestamp=None):
        # Initialize the execution environment
        account = wstate.address_to_account[address]
        if account.typ == AccountType.LIBRARY:
            return []
        child_wstate = wstate.child()
        logging.debug(BColors.GREEN + BColors.REVERSED + 'Starting SVM execution' + BColors.ENDC
                      + ' with address: ' + hex(address)
                      + ' contract: ' + account.contract.name)

        caller_vec = self.sym_bv_generator.get_sym_bitvec(constraints.ConstraintType.CALLER,
                                                          child_wstate.gen)

        caller_constraint = z3.Or([caller_vec == p for p in self.possible_caller_addresses])
        child_wstate.constraints.append(caller_constraint)

        calldata = self.sym_bv_generator.get_sym_bitvec(constraints.ConstraintType.CALLDATA_ARRAY,
                                                        child_wstate.gen,
                                                        acc=account.id)
        if method is not None and method.name != Method.FALLBACK:
            calldata_0 = self.sym_bv_generator.get_sym_bitvec(constraints.ConstraintType.CALLDATA,
                                                              child_wstate.gen,
                                                              index=0)
            calldata_4bytes, _  = svm_utils.split_bv(calldata_0, calldata_0.size() - 32)
            calldatasize = self.sym_bv_generator.get_sym_bitvec(constraints.ConstraintType.CALLDATASIZE,
                                                                child_wstate.gen,
                                                                acc=account.id)
            entry_account = self.sym_bv_generator.get_sym_bitvec(constraints.ConstraintType.ENTRY_ACCOUNT,
                                                                 child_wstate.gen)
            method_constraint = z3.And(calldata_4bytes == method.idd, z3.ULE(4, calldatasize), entry_account == address)
            child_wstate.constraints.append(method_constraint)
            if arguments is not None and len(arguments):
                encoded_args = utils.abi_encode(method.inputs, arguments)
                for i, arg in enumerate(encoded_args):
                    if arg is None:
                        continue
                    calldata_i = self.sym_bv_generator.get_sym_bitvec(constraints.ConstraintType.CALLDATA,
                                                                      child_wstate.gen,
                                                                      index=4+32*i)
                    child_wstate.constraints.append(calldata_i == z3.BitVecVal(arg, 256))
        gasprice_vec = self.sym_bv_generator.get_sym_bitvec(constraints.ConstraintType.GASPRICE,
                                                            child_wstate.gen)
        callvalue_vec = self.sym_bv_generator.get_sym_bitvec(constraints.ConstraintType.CALLVALUE,
                                                             child_wstate.gen)
        origin_vec = self.sym_bv_generator.get_sym_bitvec(constraints.ConstraintType.ORIGIN,
                                                          child_wstate.gen)
        timestamp_vec = self.sym_bv_generator.get_sym_bitvec(constraints.ConstraintType.TIMESTAMP,
                                                             child_wstate.gen)
        parent_timestamp_vec = self.sym_bv_generator.get_sym_bitvec(constraints.ConstraintType.TIMESTAMP,
                                                                    wstate.gen)
        callvalue_constraint = ULT(callvalue_vec, svm_utils.ETHER_LIMIT)
        timestamp_constraint = ULT(parent_timestamp_vec, timestamp_vec)

        entry_account = self.sym_bv_generator.get_sym_bitvec(constraints.ConstraintType.ENTRY_ACCOUNT,
                                                             child_wstate.gen)
        child_wstate.constraints.append(callvalue_constraint)
        child_wstate.constraints.append(timestamp_constraint)
        child_wstate.constraints.append(entry_account == account.address)
        environment = Environment(active_address=address,
                                  sender=caller_vec,
                                  calldata=calldata,
                                  gasprice=gasprice_vec,
                                  callvalue=callvalue_vec,
                                  origin=origin_vec,
                                  calldata_type=CalldataType.UNDEFINED,
                                  disassembly=account.contract.disassembly,
                                  runtime_bytecode_bytes=list(account.contract.disassembly.bytecode),
                                  timestamp=timestamp_vec)

        gstate = GlobalState(child_wstate, environment)
        return self.executor.execute_gstate(gstate)
Esempio n. 24
0
def parse_int_params(name):
    things = name.split('[')[1:]
    #    print "things:".format(things)
    if not all(t.endswith(']') for t in things):
        raise SyntaxError()
    return [int(t[:-1]) for t in things]


def is_solver_sort(name):
    return name.startswith('bv[') and name.endswith(']') or name == 'int'


relations_dict = {
    '<': (lambda x, y: z3.ULT(x, y) if z3.is_bv(x) else x < y),
    '<=': (lambda x, y: z3.ULE(x, y) if z3.is_bv(x) else x <= y),
    '>': (lambda x, y: z3.UGT(x, y) if z3.is_bv(x) else x > y),
    '>=': (lambda x, y: z3.UGE(x, y) if z3.is_bv(x) else x >= y),
}


def relations(name):
    return relations_dict.get(name)


functions_dict = {
    "+": (lambda x, y: x + y),
    "-": my_minus,
    "*": (lambda x, y: x * y),
    "concat": (lambda x, y: z3.Concat(x, y)),
}
Esempio n. 25
0
 def ule(self, ctx, return_type, a, atype, b, btype, **kwargs):
     assert atype == btype
     return z3.ULE(a, b)
Esempio n. 26
0
    def check(self, instance, conj, is_owner_valid, is_owned1_valid, is_owned2_valid, max_refs, ownerfn=None, ownedby=None):
        """Emit correctness definitions for this refcnt"""

        is_owned_valid = lambda a, b: z3.And(is_owned1_valid(a), is_owned2_valid(b))

        assert ownerfn != None or ownedby != None
        assert not (ownerfn and ownedby)

        if ownerfn:
            ownedby = lambda arg1, arg2: ownerfn(arg2) == arg1

        fn = instance._fields[self._name]
        owner = util.FreshBitVec('owner', self.get_types()[0])
        owned1 = util.FreshBitVec('owned1', self.get_types()[1][0])
        owned2 = util.FreshBitVec('owned2', self.get_types()[1][1])
        idx = util.FreshBitVec('idx', self.get_types()[2])

        ref, perm1, perm2, perm_inv = fn

        # 1) a valid input implies a valid owned output
        conj.append(z3.ForAll([owner, owned1, owned2], z3.Implies(
            z3.And(
                is_owner_valid(owner),
                is_owned_valid(owned1, owned2)),
            z3.ULT(perm_inv(owner, owned1, owned2), max_refs)
        )))

        conj.append(z3.ForAll([owner, idx], z3.Implies(
            z3.And(
                is_owner_valid(owner),
                z3.ULT(idx, max_refs)),
            z3.And(
                is_owned1_valid(perm1(owner, idx)),
                is_owned2_valid(perm2(owner, idx))))))

        # 2) The function function is a bijection
        conj.append(z3.ForAll([owner, owned1, owned2, idx],
            z3.Implies(z3.And(
                is_owner_valid(owner),
                is_owned_valid(owned1, owned2),
                z3.ULT(idx, max_refs)),
            z3.And(
                perm_inv(owner, perm1(owner, idx), perm2(owner, idx)) == idx,
                perm1(owner, perm_inv(owner, owned1, owned2)) == owned1,
                perm2(owner, perm_inv(owner, owned1, owned2)) == owned2,
        ))))

        # 3) if 'owner' owns 'owned', then f(owned) < ref, otherwise w(owned) >= ref
        conj.append(z3.ForAll([owner, owned1, owned2], z3.Implies(
            z3.And(
                is_owner_valid(owner),
                is_owned_valid(owned1, owned2),
            ),
            z3.And(
                z3.Implies(ownedby(owner, (owned1, owned2)),
                    z3.ULT(perm_inv(owner, owned1, owned2), ref(owner))),
                z3.Implies(z3.Not(ownedby(owner, (owned1, owned2))),
                    z3.UGE(perm_inv(owner, owned1, owned2), ref(owner)))
            ))))

        # Checks that the refcnt don't overflows, that if its
        # value is 0 that the owner owns nothing and if its value is max_refs that
        # process owns all the resources.

        # refcount is in the range 0 <= r <= max_refs
        conj.append(z3.ForAll([owner],
            z3.Implies(is_owner_valid(owner), z3.ULE(ref(owner), max_refs))))

        # if refcount is 0, then you own no pages
        conj.append(z3.ForAll([owner, owned1, owned2], z3.Implies(
            z3.And(
                is_owner_valid(owner),
                is_owned_valid(owned1, owned2),
                ref(owner) == z3.BitVecVal(0, self.get_types()[-1]),
            ),
            z3.Not(ownedby(owner, (owned1, owned2))),
        )))

        # if refcount is max_refs, then that owner owns all the resources
        conj.append(z3.ForAll([owner, owned1, owned2], z3.Implies(
            z3.And(
                is_owner_valid(owner),
                is_owned_valid(owned1, owned2),
                ref(owner) == max_refs
            ),
            ownedby(owner, (owned1, owned2)),
        )))
Esempio n. 27
0
  z = exact(x, ty)

  if isinstance(arg, Constant):
    return z

  r = smt.new_analysis(name, arg, type=ty)
  smt.add_aux(*mk_implies(nx, [restrict(r, z)]))
  # this allows the analysis to be incorrect if the argument is poison
  # if the argument has undefined behavior, then the result should be irrelevant
  return r

eval.register(SignBitsCnxp, BaseSMTEncoder,
  value_analysis('numsignbits',
    lambda x, ty: ComputeNumSignBits(ty.width, x),
    lambda r, z: z3.ULE(r, z)))

eval.register(OneBitsCnxp, BaseSMTEncoder,
  value_analysis('onebits',
    lambda x, ty: x,
    lambda r, z: r & ~z == 0))

eval.register(ZeroBitsCnxp, BaseSMTEncoder,
  value_analysis('zerobits',
    lambda x, ty: ~x,
    lambda r, z: r & ~z == 0))

eval.register(LeadingZerosCnxp, BaseSMTEncoder,
  lambda term,smt: ctlz(smt.type(term).width,
    smt.eval(term._args[0])))