def getEq(self): #print self.read_operands[1] sdir = "" src1, src2 = self.getOperands(self.read_operands) dst = self.getOperands(self.write_operands)[0] n = self.read_operands[1].getValue() if n > 0: sdir = "left" elif n < 0: sdir = "right" #self.read_operands[1].name = self.read_operands[1].name.replace("-","") #ugly hack! else: sdir = "null" #print self.read_operands[1].name #print sdir, src2.as_long() if sdir == "right": return [(z3.Extract(self.write_operands[0].getSizeInBits() - 1, 0, z3.LShR(src1, -n)) == dst)] elif sdir == "left": return [(z3.Extract(self.write_operands[0].getSizeInBits() - 1, 0, (src1 << n)) == dst)] elif sdir == "null": return [(src1 == dst)] else: assert (False)
def itoa_helper(state, value, string, base, sign=True): addr = state.evalcon(string).as_long() # ok so whats going on here is... uhh it works data = [BZERO] nvalue = z3.SignExt(96, z3.Extract(31, 0, value)) pvalue = z3.ZeroExt(64, value) do_neg = z3.And(nvalue < 0, base == 10, z3.BoolVal(sign)) base = z3.ZeroExt(64, base) new_value = z3.If(do_neg, -nvalue, pvalue) shift = BV(0, 128) for i in range(32): d = (new_value % bvpow(base, i + 1)) / bvpow(base, i) c = z3.Extract(7, 0, d) shift = z3.If(c == BZERO, shift + BV(8, 128), BV(0, 128)) data.append(z3.If(c < 10, c + BV_0, (c - 10) + BV_a)) pbv = z3.Concat(*data) szdiff = pbv.size() - shift.size() pbv = pbv >> z3.ZeroExt(szdiff, shift) nbv = z3.simplify(z3.Concat(pbv, BV(ord("-"), 8))) pbv = z3.simplify(z3.Concat(BV(0, 8), pbv)) # oof state.memory[addr] = z3.If(do_neg, nbv, pbv) return string
def eval(self, ctx): expr = self.expr.eval(ctx) hi, lo = self.hi.eval(ctx), self.lo.eval(ctx) width = hi - lo + 1 if is_z3(expr): shifted = match_width_fn(expr, lo, lambda l, r: l >> r) # Big hack! Simplify (x+y)-x -> y to get the width when we don't # know x. This is pretty common, e.g. a[index*8+7:index*8] if (isinstance(self.hi, BinaryOp) and self.hi.op == '+' and self.hi.lhs == self.lo): width1 = try_simplify(self.hi.rhs.eval(ctx)) return z3.Extract(width1, 0, shifted) # HACK!! Z3 will complain if we try to Extract with a non-constant # range [lo, hi], since it can't determine if lo <= hi. Well, it # actually can, but the Z3 python wrapper doesn't simplify that # expression before checking it. So, as a special case, see if we # can at least determine that lo == hi (which is common because Slice # is used for single-bit indexing like a[i]), then replace the # expression with a variable shift and a single-bit extract. if is_z3(hi) and is_z3(lo) and try_bool(hi == lo): return z3.Extract(0, 0, shifted) return z3.Extract(width - 1, 0, shifted) # Slice integers with normal bit ops assert width > 0 mask = ((1 << width) - 1) return (expr >> lo) & mask
def getEq(self): sdir = "" if self.read_operands[1].getValue() > 0: sdir = "left" elif self.read_operands[1].getValue() < 0: sdir = "right" self.read_operands[1].name = self.read_operands[1].name.replace( "-", "") #ugly hack! else: sdir = "null" #print self.read_operands[1].name src1, src2 = self.getOperands(self.read_operands) dst = self.getOperands(self.write_operands)[0] #print sdir, src2.as_long() if sdir == "right": return [(z3.Extract(self.write_operands[0].size * 8 - 1, 0, z3.LShR(src1, src2)) == dst)] elif sdir == "left": return [(z3.Extract(self.write_operands[0].size * 8 - 1, 0, (src1 << src2)) == dst)] elif sdir == "null": return [(src1 == dst)] else: assert (False)
def from_ExprOp(self, expr): args = 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 == "a<<": res = res << arg elif expr.op == "idiv": res = res / arg 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 xrange(8): res = res ^ z3.Extract(i, i, arg) elif expr.op == '-': res = -res else: raise NotImplementedError("Unsupported OP yet: %s" % expr.op) return res
def _(src, tgt, v): w = z3.fpToIEEEBV(v) i = z3.If(z3.Or(z3.fpIsZero(v), z3.fpIsSubnormal(v)), z3.BitVecVal(0,1), z3.BitVecVal(1,1)) return z3.Concat(z3.Extract(78,63,w), i, z3.Extract(62,0,w))
def eval(self, ctx): [name, lo, hi, scale, result_width] = get_range(self, ctx) expr = ctx.get(name) if isinstance(name, str) else name.eval(ctx) [expr, _, width, signed] = match_types(expr, lo) assert is_z3(expr) # Weird: always treat the low index (shift value) as unsigned. Shifting # by negative values doesn't make sense, and shifting a signed value by # an unknown-signedness value shouldn't sign extend the shift value lo = extend(lo, width, signed=False) expr = expr >> lo # Unwrap the value. Should be fine, we have signed/width from the old value if isinstance(expr, Value): expr = expr.value # Big hack! Simplify (x+y)-x -> y to get the width when we don't # know x. This is pretty common, e.g. a[index*8+7:index*8] if (isinstance(self.hi, BinaryOp) and self.hi.op == '+' and equal(self.hi.lhs, self.lo)): width1 = try_simplify(self.hi.rhs.eval(ctx)) result = z3.Extract(width1, 0, expr) else: result = z3.Extract(result_width - 1, 0, expr) return Value(result, signed=signed, width=result_width)
def fn(self, inp, sbox, key): assert inp.size() == 8 assert key.size() == 24 # Get the symbolic expressions for the key parts. k1 = z3.Extract( 5, 0, key) k2 = z3.Extract(11, 6, key) k3 = z3.Extract(17, 12, key) k4 = z3.Extract(23, 18, key) # Get symbolic expressions for different 6-bit input sets. i1 = sbox.inputs_z3(inp, 0) i2 = sbox.inputs_z3(inp, 1) i3 = sbox.inputs_z3(inp, 2) i4 = sbox.inputs_z3(inp, 3) # Get symbolic expressions for all sboxes. s1 = self.sboxes[sbox][0] s2 = self.sboxes[sbox][1] s3 = self.sboxes[sbox][2] s4 = self.sboxes[sbox][3] # Get the output variables as separate 8-bit quantities. o1 = sbox.outputs_z3(s1[i1 ^ k1], 0) o2 = sbox.outputs_z3(s2[i2 ^ k2], 1) o3 = sbox.outputs_z3(s3[i3 ^ k3], 2) o4 = sbox.outputs_z3(s4[i4 ^ k4], 3) # Compose and simplify them. return z3.simplify(o1 | o2 | o3 | o4)
def set_slice(self, ctx, lval, rval): slice_l = ctx.resolve_expr(lval.slice_l) slice_r = ctx.resolve_expr(lval.slice_r) lval = lval.val lval, slice_l, slice_r = self.find_nested_slice(lval, slice_l, slice_r) # need to resolve everything first, these can be members lval_expr = ctx.resolve_expr(lval) # z3 requires the extract value to be a bitvector, so we must cast ints # actually not sure where this could happen... if isinstance(lval_expr, int): lval_expr = lval_expr.as_bitvec rval_expr = ctx.resolve_expr(rval) lval_expr_max = lval_expr.size() - 1 if slice_l == lval_expr_max and slice_r == 0: # slice is full lval, nothing to do ctx.set_or_add_var(lval, rval_expr) return assemble = [] if slice_l < lval_expr_max: # left slice is smaller than the max, leave that chunk unchanged assemble.append(z3.Extract(lval_expr_max, slice_l + 1, lval_expr)) # fill the rval_expr into the slice # this cast is necessary to match the margins and to handle integers rval_expr = z3_cast(rval_expr, slice_l + 1 - slice_r) assemble.append(rval_expr) if slice_r > 0: # right slice is larger than zero, leave that chunk unchanged assemble.append(z3.Extract(slice_r - 1, 0, lval_expr)) rval_expr = z3.Concat(*assemble) ctx.set_or_add_var(lval, rval_expr) return
def __getitem__(self, index): size = self.size if isinstance(index, slice): start, stop, step = index.start, index.stop, index.step if start is None: start = 0 elif start < 0: start = size + start if stop is None: stop = size elif stop < 0: stop = size + stop stop = min(stop, size) if step is None: step = 1 elif step != 1: raise IndexError('SMT extract does not support step != 1') v = z3.Extract(stop - 1, start, self.value) return type(self).unsized_t[v.sort().size()](v) elif isinstance(index, int): if index < 0: index = size + index if not (0 <= index < size): raise IndexError() v = z3.Extract(index, index, self.value) return self.get_family().Bit(v == z3.BitVecVal(1, 1)) else: raise TypeError()
def createIf(index): if index == msb: return z3.Extract(msb, msb, wz3) else: return z3.If( bz3 == z3.BitVecVal(index, self.bsz), z3.Extract(index, index, wz3), createIf(index+1))
def from_ExprOp(self, expr): args = 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 == "idiv": res = self._idivC(res, arg) elif expr.op == "udiv": res = z3.UDiv(res, arg) elif expr.op == "imod": res = res - (arg * (self._idivC(res, arg))) elif expr.op == "umod": res = z3.URem(res, arg) 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 xrange(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 xrange(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 xrange(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
def eval(self, ctx): expr = self.expr.eval(ctx) # Handle assignment to slices if isinstance(self.target, Slice): [name, lo, hi, scale, width] = get_range(self.target, ctx) assert isinstance( name, str), 'slice assignment to non-identifier: %s' % name old = ctx.get(name) # Get the old signedness value if it has one signed = None if isinstance(old, Value): signed = old.signed old = old.value if not is_z3(old): old = z3.BitVec('undef', width) # Hack around Z3 API to get a bit vector of the expected width if isinstance(expr, Value): if signed is None: signed = expr.signed expr = extend(expr.value, width, signed=expr.signed) if is_z3(expr): expr = z3.Extract(width - 1, 0, expr) elif width > 0: expr = z3.BitVecVal(expr, width) if hi is None: hi = lo + scale - 1 # Append the unassigned and assigned portions of this vector args = [] if old.size() - 1 >= hi + 1: args.append(z3.Extract(old.size() - 1, hi + 1, old)) if width > 0: args.append(expr) if lo - 1 >= 0: args.append(z3.Extract(lo - 1, 0, old)) new = z3.Concat(*args) if len(args) > 1 else args[0] # XXX we can't always rely on this, think of a better way to check #assert new.size() == old.size() value = try_simplify(ctx.predicate(new, old)) value = Value(value, width=new.size(), signed=signed) ctx.set(name, value) # Assigning to a raw variable. Only need to deal with predication. else: assert isinstance(self.target, Identifier) name = self.target.name ctx.set(name, ctx.predicate(expr, ctx.get(name))) return None
def test1(self): b = multiagent.Board('b1', 3, 3) s = b.sum_of_adj(1, 1) logger.debug(s) smt = z3.BV2Int(z3.Extract(1, 1, b.BV)) +\ z3.BV2Int(z3.Extract(7, 7, b.BV)) +\ z3.BV2Int(z3.Extract(3, 3, b.BV)) +\ z3.BV2Int(z3.Extract(5, 5, b.BV)) self.assertTrue(z3.simplify(smt == s))
def pack_f32(n: f32): if utils.is_all_real(n): float_bytes = struct.pack('<f', n) return [float_bytes for float_byte in float_bytes] f32_bv = z3.fpToIEEEBV(n) return [ z3.Extract(7, 0, f32_bv), z3.Extract(15, 8, f32_bv), z3.Extract(23, 16, f32_bv), z3.Extract(31, 24, f32_bv) ]
def hash2(name): h = z3.BitVecVal(0, 16) assert len(name) % 2 == 0 # for simplicity for i in range(0, len(name), 2): a = z3.BitVecVal(0, 16) a |= z3.Extract(15, 0, name[i]) a |= z3.Extract(15, 0, name[i + 1]) << 8 h ^= a a = z3.LShR(h, 10) b = z3.ZeroExt(8, z3.Extract(7, 0, h ^ z3.LShR(h, 5))) h = (a ^ b) & 0x1f return h
def __init__(self, nbits, key): self.nbits = nbits self.slvr = z3.Goal() self.init = z3.BitVec('init', nbits) tmp = z3.BitVec('tmp', nbits) # make sure Goal() start with `init` (at step 2) for i in range(nbits): self.slvr.add(z3.Extract(i, i, tmp) == z3.Extract(i, i, self.init)) self.state = self.init self.poly = z3.BitVecVal(key, nbits) self.zero = z3.BitVecVal(0, nbits) self.one = z3.BitVecVal(1, nbits)
def from_ExprOp(self, expr): args = 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 == "a<<": res = res << arg elif expr.op == "<<<": res = z3.RotateLeft(res, arg) elif expr.op == ">>>": res = z3.RotateRight(res, arg) elif expr.op == "idiv": res = res / arg elif expr.op == "udiv": res = z3.UDiv(res, arg) elif expr.op == "imod": res = res % arg elif expr.op == "umod": res = z3.URem(res, arg) 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 xrange(8): res = res ^ z3.Extract(i, i, arg) elif expr.op == '-': res = -res elif expr.op == "bsf": size = expr.size src = res res = z3.If((src & (1 << (size - 1))) != 0, size - 1, src) for i in xrange(size - 2, -1, -1): res = z3.If((src & (1 << i)) != 0, i, res) elif expr.op == "bsr": size = expr.size src = res res = z3.If((src & 1) != 0, 0, src) for i in xrange(size - 1, 0, -1): index = -i % size res = z3.If((src & (1 << index)) != 0, index, res) else: raise NotImplementedError("Unsupported OP yet: %s" % expr.op) return res
def invariants(self): constraint = [] if self._is_x_pow2: ix = self.fabric.cols.bit_length() constraint.append(z3.Extract(ix, ix, self.x) == 0) else: constraint.append(z3.ULT(self.x, self.fabric.cols)) if self._is_y_pow2: iy = self.fabric.rows.bit_length() constraint.append(z3.Extract(iy, iy, self.y) == 0) else: constraint.append(z3.ULT(self.y, self.fabric.rows)) return z3.And(constraint)
def pack_u32(n: u32): if utils.is_all_real(n): return [ n & 0xFF, (n & 0xFF00) >> 8, (n & 0xFF0000) >> 16, (n & 0xFF000000) >> 24 ] else: return [ z3.Extract(7, 0, n), z3.Extract(15, 8, n), z3.Extract(23, 16, n), z3.Extract(31, 24, n) ]
def constrain_bytes(self, bv, regex: Union[str, bytes]): # if its a bytes expr just constrain beginning to those values if type(regex) == bytes: for i in range(len(regex)): self.constrain(z3.Extract(7 + i * 8, i * 8, bv) == regex[i]) return all_bytes = "".join([chr(x) for x in range(256)]) if z3.is_bv(bv): bv = [ z3.Extract(b * 8 + 7, b * 8, bv) for b in range(int(bv.size() / 8)) ] # this is gross and could probably break opts = [] new_regex = regex[:] negate = False if len(regex) > 2 and regex[:2] == "[^": negate = True new_regex = new_regex.replace("[^", "[") dashes = [i for i, c in enumerate(regex) if c == "-"] for d in dashes: if regex[d - 1] != "\\" and len(regex) > d: x = ord(regex[d - 1]) y = ord(regex[d + 1]) opts.append([x, y]) new_regex = new_regex.replace(regex[d - 1:d + 2], "") vals = [] if new_regex != "[]": vals = [ ord(x) for x in re.findall(new_regex, all_bytes, re.DOTALL) ] for b in bv: or_vals = [] for val in vals: or_vals.append(b == val) for opt in opts: or_vals.append(z3.And(b >= opt[0], b <= opt[1])) if negate: self.constrain(z3.Not(z3.Or(*or_vals))) else: self.constrain(z3.Or(*or_vals))
def createIf(i): if i < len(self.choiceBools): cvi = self.choiceBools[i] starti = self.rangeStarts[i] stopi = starti - self.width + 1 assert starti >= stopi expri = z3.Extract(starti, stopi, rfun(self.bitvec, prefix)) return z3.If(cvi, expri, createIf(i+1)) else: starti = self.width - 1 stopi = 0 assert starti >= stopi expri = z3.Extract(starti, stopi, rfun(self.bitvec, prefix)) return expri
def feistel(self, inp, key): assert key.size() == 96 # Partition the key into batches of 24 bits. k1 = z3.Extract(23, 0, key) k2 = z3.Extract(47, 24, key) k3 = z3.Extract(71, 48, key) k4 = z3.Extract(95, 72, key) l = [ z3.Extract(b, b, inp) for b in reversed(fn2_groupB) ] l = z3.Concat(l) r = [ z3.Extract(a, a, inp) for a in reversed(fn2_groupA) ] r = z3.Concat(r) l ^= self.fn(r, self.f2_sbox[0], k1) r ^= self.fn(l, self.f2_sbox[1], k2) l ^= self.fn(r, self.f2_sbox[2], k3) r ^= self.fn(l, self.f2_sbox[3], k4) # Collect all bits for the return value. ret_in = [ z3.Extract(i, i, l) for i in range(8) ] ret_in += [ z3.Extract(i, i, r) for i in range(8) ] # Apply the shuffle from groupA and B. ret = [None] * 16 for i, b in enumerate(fn2_groupA + fn2_groupB): ret[b] = ret_in[i] return z3.simplify(z3.Concat(*reversed(ret)))
def pte64(value): if value.size() != 64: raise Exception("pte64 requires a bitvector of size 64") v = simplify(z3.Extract(0, 0, value) == z3.BitVecVal(1, 1)) r = simplify(z3.Extract(1, 1, value) == z3.BitVecVal(1, 1)) w = simplify(z3.Extract(2, 2, value) == z3.BitVecVal(1, 1)) x = simplify(z3.Extract(3, 3, value) == z3.BitVecVal(1, 1)) u = simplify(z3.Extract(4, 4, value) == z3.BitVecVal(1, 1)) g = simplify(z3.Extract(5, 5, value) == z3.BitVecVal(1, 1)) a = simplify(z3.Extract(6, 6, value) == z3.BitVecVal(1, 1)) d = simplify(z3.Extract(7, 7, value) == z3.BitVecVal(1, 1)) n = simplify(z3.Extract(62, 62, value) == z3.BitVecVal(1, 1)) ppn = z3.Extract(53, 10, value) return PTE64(ppn=ppn, d=d, a=a, g=g, u=u, x=x, w=w, r=r, v=v, n=n)
def Extract(self, high: int, low: int): assert high >= low new_interval = self.interval.Extract(high, low) if new_interval.high == new_interval.low: # extract is concrete return BVV(new_interval.high, high-low+1) return BVExpr(high-low+1, z3.Extract(high, low, self.z3obj), new_interval)
def int2i64(i: int) -> i64: if utils.is_all_real(i): i = i & 0xFFFFFFFFFFFFFFFF if i & 0x8000000000000000: return i - 0x10000000000000000 return i return z3.Extract(63, 0, i)
def int2i32(i: int) -> i32: if utils.is_all_real(i): i = i & 0xFFFFFFFF if i & 0x80000000: return i - 0x100000000 return i return z3.Extract(31, 0, i)
def _op_raw_Reverse(a): if a.size() == 8: return a elif a.size() % 8 != 0: raise ClaripyOperationError("can't reverse non-byte sized bitvectors") else: return z3.Concat(*[z3.Extract(i+7, i, a) for i in range(0, a.size(), 8)])
def EXTRACT(s, offset, size): if isinstance(s, Symbol): retv = BitVec(z3.Extract(offset + size - 1, offset, s.symbol)) return retv.simplify() if isInt(s): return (s >> offset) & ((1 << size) - 1) raise Exception("!@#$")
def int2i16(i: int) -> i16: if utils.is_all_real(i): i = i & 0xFFFF if i & 0x8000: return i - 0x10000 return i return z3.Extract(15, 0, i)