def _constraints_to_z3(self): across_variables = {k: (z3.BitVec("{}-across({})".format(k, len(v)), len(self.words_by_length[len(v)])), v) for k, v in self.acrosses.items()} down_variables = {k: (z3.BitVec("{}-down({})".format(k, len(v)), len(self.words_by_length[len(v)])), v) for k, v in self.downs.items()} self.s = z3.Solver() for variable, info in list(across_variables.values()) + list(down_variables.values()): # n & -n == n iff n has exactly one bit set. So this constraint just says # each variable represents one exactly one index into the lexicographic ordering. # of words of that length. self.s.add(variable & -variable == variable) for restriction, indices in self.restrictions.items(): across, across_info = across_variables[restriction[0]] down, down_info = down_variables[restriction[1]] across_ix, down_ix = indices across_letters = [] down_letters = [] for letter in string.ascii_uppercase: across_bitarray = self.lexicon_bitarrays[len(across_info)][across_ix][letter] across_ok = z3.BVRedOr(across_bitarray & across) #) != 0 # TODO check if n & -n == n is faster since we know there is exactly one or 0 set down_bitarray = self.lexicon_bitarrays[len(down_info)][down_ix][letter] down_ok = z3.BVRedOr(down_bitarray & down) # != 0 # z3.BVRedOr(down_bitarray & down) across_letters.append(across_ok) down_letters.append(down_ok) # for each restriction, the bitarray representing the letter # chosen must be the same. self.s.add(z3.Concat(across_letters) & z3.Concat(down_letters) != 0)
def get_norm_cons_bvArray(varValList, var2dim_dict, minDist): normConsList = [] for (var, val) in varValList: n = var2dim_dict[str(var)] for i in range(n): c_upper_bound = -z3.Concat(var[INT_SIZE * i + 3], var[INT_SIZE * i + 2], var[INT_SIZE * i + 1], var[INT_SIZE * i + 0]) + val[i] >= minDist c_lower_bound = z3.Concat(var[INT_SIZE * i + 3], var[INT_SIZE * i + 2], var[INT_SIZE * i + 1], var[INT_SIZE * i + 0]) - val[i] >= minDist # c_ne = z3.Concat(var[INT_SIZE * i + 3], # var[INT_SIZE * i + 2], # var[INT_SIZE * i + 1], # var[INT_SIZE * i + 0])\ # != val[i] normConsList.append(c_upper_bound) normConsList.append(c_lower_bound) # normConsList.append(c_ne) # return (c_ne) return z3.Or(*normConsList)
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 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 z3_get_memory(memory, address, size, arch): value = z3.Select(memory, address) for i in range(1, size / 8): new_byte = z3.Select(memory, address + i) if arch.memory_endness == 'Iend_LE': value = z3.Concat(new_byte, value) else: value = z3.Concat(value, new_byte) return value
def opcode_call_data(calldata, data_offset, data_length=32): parts = [] if not is_z3_express(data_length): for i in range(format_to_int(data_length)): index = opcode_add(data_offset, i) parts.append(calldata[index]) return z3.simplify(z3.Concat(parts)) print data_length exit() return z3.Concat(parts)
def getValue(self, op): assert (self.m <> None) if (op.isReg()): #if (literal): # # var = map(lambda b: z3.BitVec(b, 8), op.get_bytes()) var = map(lambda b: self.m[b], var) if (len(var) > 1): return z3.simplify(z3.Concat(var)).as_signed_long() else: return z3.simplify(var[0]).as_signed_long() elif (op.isMem()): array = z3.Array(op.mem_source, z3.BitVecSort(16), z3.BitVecSort(8)) #print "debug getValue:" #print op, op.mem_offset ,"->", array f = self.m[array] #print f # #var = map(lambda b: z3.BitVec(b,8), op.get_bytes()) #var = map(lambda b: self.m[b], var) # ##if (self.m): #print "eax:" #print "%x" % self.m[eax].as_unsigned() #assert(0) ##print op.mem_source ##print op.mem_offset es = f.as_list()[:-1] var = [] for i in range(op.size): byte = None for entry in es: if op.mem_offset + i == entry[0].as_signed_long(): byte = entry[1] #.as_signed_long() break if (byte == None): byte = f.else_value() var.append(byte) var.reverse() if (len(var) > 1): return z3.simplify(z3.Concat(var)).as_signed_long() else: return z3.simplify(var[0]).as_signed_long()
def opcode_get_memory(memory, offset, length=32): parts = [] if not is_z3_express(length): for i in range(format_to_int(length)): index = opcode_add(offset, i) parts.append(memory[index]) return z3.simplify(z3.Concat(parts)) # delete tail zero for i in range(opcode_memory.LENGTH): check_get_express = z3.And(i >= offset, i < offset + length) parts.append(z3.If(check_get_express, memory[i], z3.BitVecVal(0, 8))) return z3.simplify(z3.Concat(parts))
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 Concat(*args: Union[BitVec, List[BitVec]]) -> BitVec: """Create a concatenation expression. :param args: :return: """ # The following statement is used if a list is provided as an argument to concat if len(args) == 1 and isinstance(args[0], list): bvs = args[0] # type: List[BitVec] else: bvs = cast(List[BitVec], args) nraw = z3.Concat([a.raw for a in bvs]) annotations = [] # type: Annotations bitvecfunc = False for bv in bvs: annotations += bv.annotations if isinstance(bv, BitVecFunc): bitvecfunc = True if bitvecfunc: # Is there a better value to set func_name and input to in this case? return BitVecFunc(raw=nraw, func_name=None, input_=None, annotations=annotations) return BitVec(nraw, annotations)
def ZConcat32(a, b): # Z3 concat of 32 bit numbers # Since the implementation only uses uint64's # we have to know the the sizes for the numbers being concated. assert a.size() == 32 assert b.size() == 32 return z3.Concat(a, b)
def Concat(*args: Union[BitVec, List[BitVec]]) -> BitVec: """Create a concatenation expression. :param args: :return: """ # The following statement is used if a list is provided as an argument to concat if len(args) == 1 and isinstance(args[0], list): bvs = args[0] # type: List[BitVec] else: bvs = cast(List[BitVec], args) nraw = z3.Concat([a.raw for a in bvs]) annotations = set() # type: Annotations nested_functions = [] # type: List[BitVecFunc] for bv in bvs: annotations = annotations.union(bv.annotations) if isinstance(bv, BitVecFunc): nested_functions += bv.nested_functions nested_functions += [bv] if nested_functions: return BitVecFunc( raw=nraw, func_name="Hybrid", input_=BitVec(z3.BitVec("", 256), annotations=annotations), nested_functions=nested_functions, ) return BitVec(nraw, annotations)
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 _padded_operation(a: z3.BitVec, b: z3.BitVec, operator): if a.size() == b.size(): return operator(a, b) if a.size() < b.size(): a, b = b, a b = z3.Concat(z3.BitVecVal(0, a.size() - b.size()), b) return operator(a, b)
def Concat(*args: Union[BitVec, List[BitVec]]) -> BitVec: """Create a concatenation expression. :param args: :return: """ # The following statement is used if a list is provided as an argument to concat if len(args) == 1 and isinstance(args[0], list): bvs = args[0] # type: List[BitVec] else: bvs = cast(List[BitVec], args) nraw = z3.Concat([a.raw for a in bvs]) annotations = set() # type: Annotations bitvecfunc = False for bv in bvs: annotations = annotations.union(bv.annotations) if isinstance(bv, BitVecFunc): bitvecfunc = True if bitvecfunc: # Added this not so good and misleading NOTATION to help with this str_hash = ",".join(["hashed({})".format(hash(bv)) for bv in bvs]) input_string = "MisleadingNotationConcat({})".format(str_hash) return BitVecFunc(raw=nraw, func_name="Hybrid", input_=BitVec(z3.BitVec(input_string, 256), annotations=annotations)) return BitVec(nraw, annotations)
def mkByteVar(op): locs = op.getLocations() if (len(locs) > 1): return z3.Concat(map(lambda b: z3.BitVec(str(b), 8), locs)) else: return z3.BitVec(str(locs[0]), 8)
def u16(r: list): if utils.is_all_real(r[0], r[1]): return ctypes.c_uint16(r[0] + (r[1] << 8)).value else: for i in range(len(r)): r[i] = utils.to_symbolic(r[i], 8) return z3.Concat(r[1], r[0])
def Concat(self, other: BV): if isinstance(other, BVV): new_value = (self.value << other.size) + other.value new_size = self.size + other.size new_mask = 2**new_size-1 return BVV(new_value & new_mask, new_size) return BVExpr(self.size + other.size, z3.Concat(self.z3obj, other.z3obj), self.interval.Concat(other.interval))
def read_bv(self, addr, length): if type(addr) != int: addr = self.bv_to_int(addr) data = self.read(addr, length) bve = [] if all(type(x) == int for x in data): bv = self.pack_bv(data) return bv for datum in data: if type(datum) == int: bve.append(z3.BitVecVal(datum, BYTE)) else: bve.append(datum) if self.endian == "little": bve.reverse() #print(bve) if len(bve) > 1: bv = z3.simplify(z3.Concat(*bve)) else: bv = z3.simplify(bve[0]) return bv
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 zpad_bv_left(bv, target_len): bv_len = bv.size() if bv_len == target_len: return bv elif bv_len < target_len: return z3.Concat(bv, z3.BitVecVal(0, target_len - bv_len)) else: raise ValueError('Target length is less then vector size!')
def i32(r: list): if utils.is_all_real(r[0], r[1], r[2], r[3]): return ctypes.c_int32(r[0] + (r[1] << 8) + (r[2] << 16) + (r[3] << 24)).value else: for i in range(len(r)): r[i] = utils.to_symbolic(r[i], 8) return z3.Concat(r[3], r[2], r[1], r[0])
def string_concat(x, args): cc = x if z3.is_string(x): for y in args: cc = z3.Concat(cc, createZ3ExpressionFromConstraint(y, {})) return cc else: raise NotSupportedException('We only support concat on stirngs as arrays are difficult in z3.')
def comp_to_z3(e,solver=None): e.simplify() parts = [x.to_smtlib(solver) for x in e] parts.reverse() if len(parts)>1: return z3.Concat(*parts) else: return parts[0]
def __getitem__(self, op): if (op | iss | InputOp): r = "" for loc in op.getLocations(): var = z3.BitVec(str(loc), 8) var = self.m[var] r = r + ("\\x%.2x" % var.as_long()) return r if (op | iss | RegOp): var = map(lambda b: z3.BitVec(str(b), 8), op.getLocations()) var = map(lambda b: self.m[b], var) if (len(var) > 1): return z3.simplify(z3.Concat(var)).as_signed_long() else: return z3.simplify(var[0]).as_signed_long() elif (op.isMem()): array = z3.Array(op.name, z3.BitVecSort(16), z3.BitVecSort(8)) f = self.m[array] #print self.m es = f.as_list()[:-1] var = [] for loc in op.getLocations(): byte = None for entry in es: #print entry if loc.getIndex() == entry[0].as_signed_long(): byte = entry[1] #.as_signed_long() break if (byte == None): byte = f.else_value() var.append(byte) r = "" for v in var: r = r + ("\\x%.2x" % v.as_long()) return r #var.reverse() #if (len(var) > 1): # return z3.simplify(z3.Concat(var)).as_signed_long() #else: # return z3.simplify(var[0]).as_signed_long() else: assert (0) r = [] for loc in i.getLocations(): r.append(self.vars[str(loc)]) return r
def ZEXTEND(s, size): if isinstance(s, Symbol): assert s.size <= size if s.size != size: return BitVec(z3.Concat(z3.BitVecVal(0, size - s.size), s.symbol)) return s.simplify() if isInt(s): return s assert False
def do_POPCOUNT(op, stack, state): b, = pop_values(stack, state) n = b.size() bits = [z3.Extract(i, i, b) for i in range(n)] bvs = [z3.Concat(z3.BitVecVal(0, n - 1), b) for b in bits] nb = z3.Sum(*bvs) stack.append(z3.simplify(nb))
def from_ExprCompose(self, expr): res = None for arg in expr.args: e = z3.Extract(arg.size - 1, 0, self.from_expr(arg)) if res != None: res = z3.Concat(e, res) else: res = e return res
def i64(r: list): if utils.is_all_real(r[0], r[1], r[2], r[3], r[4], r[5], r[6], r[7]): return ctypes.c_int64(r[0] + (r[1] << 8) + (r[2] << 16) + (r[3] << 24) + (r[4] << 32) + (r[5] << 40) + (r[6] << 48) + (r[7] << 56)).value else: for i in range(len(r)): r[i] = utils.to_symbolic(r[i], 8) return z3.Concat(r[7], r[6], r[5], r[4], r[3], r[2], r[1], r[0])
def comp_to_z3(e, slv=None): "translate comp expression into its z3 Concat form" e.simplify() parts = [x.to_smtlib(slv) for x in e] parts.reverse() if len(parts) > 1: return z3.Concat(*parts) else: return parts[0]