def set_mem(self, address, value): unique_name = "mem_{}".format(self.mem_count) new_memory = z3.Array(unique_name, z3.BitVecSort(self.arch.bits), z3.BitVecSort(8)) self.mem_count += 1 self.memory = utils.z3_set_memory(self.memory, address, value, self.arch) self.append_assignment(new_memory, self.memory) self.memory = new_memory
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 __init__(self, name: str, domain: int, value_range: int): """Initializes a symbolic array. :param name: Name of the array :param domain: The domain for the array (10 -> all the values that a bv of size 10 could take) :param value_range: The range for the values in the array (10 -> all the values that a bv of size 10 could take) """ self.domain = z3.BitVecSort(domain) self.range = z3.BitVecSort(value_range) self.raw = z3.Array(name, self.domain, self.range)
def mem_to_z3(e,solver=None): e.simplify() M = z3.Array('M',z3.BitVecSort(e.a.size),z3.BitVecSort(8)) p = e.a.to_smtlib(solver) b = [] for i in range(0,e.length): b.insert(0,M[p+i]) if e._endian==-1: b.reverse() # big-endian case if len(b) > 1: return z3.Concat(*b) return b[0]
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 test_z3_to_array_doc(self): s = z3.BitVecSort(8) s2 = z3.BitVecSort(2) def bv(x): return z3.BitVecVal(x, s) def bv2(x): return z3.BitVecVal(x, s2) x = z3.Var(0, s) y = z3.Var(1, s) types = [primitives.TYPES['int4']] * 2 e1 = z3.Extract(3, 2, x) == bv2(3) e2 = z3.And( z3.Extract(3, 2, x) == bv2(3), z3.Extract(7, 6, x) == bv2(2)) e3 = z3.And( z3.Extract(3, 2, x) == bv2(3), z3.Extract(7, 6, x) == bv2(2), y == bv(4)) e4 = z3.And( z3.Extract(5, 4, x) == bv2(1), z3.Not( z3.And( z3.Extract(3, 2, x) == bv2(3), z3.Extract(7, 6, x) == bv2(2), y == bv(4)))) e5 = z3.And( True, z3.Not(z3.Extract(5, 4, x) == bv2(1)), z3.Not( z3.And( z3.Extract(3, 2, x) == bv2(3), z3.Extract(7, 6, x) == bv2(2), y == bv(4)))) r1 = [z3r.Cube({0: z3r.Masked(0xc, 0xc)}, 1)] r2 = [z3r.Cube({0: z3r.Masked(0x8c, 0xcc)}, 1)] r3 = [z3r.Cube({0: z3r.Masked(0x8c, 0xcc), 1: 4}, 1)] r4 = [ z3r.Doc(z3r.Cube({0: z3r.Masked(0x10, 0x30)}, 1), [z3r.Cube({ 0: z3r.Masked(0x8c, 0xcc), 1: 4 }, 1)]) ] r5 = [ z3r.Doc(z3r.Cube({}, 1), [ z3r.Cube({0: z3r.Masked(0x10, 0x30)}, 1), z3r.Cube({ 0: z3r.Masked(0x8c, 0xcc), 1: 4 }, 1) ]) ] for (r, e) in [(r1, e1), (r2, e2), (r3, e3), (r4, e4), (r5, e5)]: self.assertEqual(r, z3r.z3_to_array(e, types))
def _switch_to_symbolic(self): if self._conc_store is not None: assert self._z3obj is None self._z3obj = z3.Array(self.name, z3.BitVecSort(self.index_width), z3.BitVecSort(self.value_width)) for index in self._conc_store: self._z3obj = z3.Store(self._z3obj, z3.BitVecVal(index, self.index_width), self._conc_store[index].z3obj) self._conc_store = None
def sorts(name): if name.startswith('bv[') and name.endswith(']'): width = int(name[3:-1]) return z3.BitVecSort(width) if name.startswith('strbv[') and name.endswith(']'): width = int(name[6:-1]) return z3.BitVecSort(width) if name == 'int': return z3.IntSort() if name == 'strlit': return z3.StringSort() return None
def __init__(self, name, param_type, return_type): self.name = name self.param_type = param_type self.return_type = return_type key_sorts = [] for t in param_type: key_sorts.append(z3.BitVecSort(t * 8)) val_sort = None if val_sort == 'bool': val_sort = z3.BoolSort() else: val_sort = z3.BitVecSort(return_type * 8) self.uf = z3.Function(fresh_name(self.name), *key_sorts, val_sort)
def mem_to_z3(e, slv=None): "translate mem expression into z3 a Concat of BitVec bytes" e.simplify() M = z3.Array("M", z3.BitVecSort(e.a.size), z3.BitVecSort(8)) p = e.a.to_smtlib(slv) b = [] for i in range(0, e.length): b.insert(0, M[p + i]) if e.endian == -1: b.reverse() # big-endian case if len(b) > 1: return z3.Concat(*b) return b[0]
def _ty_sort(ty): 'Translate a Type expression to a Z3 Sort' if isinstance(ty, IntType): return z3.BitVecSort(ty.width) return { PtrType: z3.BitVecSort(64), HalfType: z3.FloatHalf(), SingleType: z3.Float32(), DoubleType: z3.Float64(), FP128Type: z3.Float128(), X86FP80Type: z3.FPSort(15, 64), }[type(ty)]
def _try_build_reduced_array(self, index_min, index_max): if self._z3obj is not None: # symbolic mode return self._z3obj if index_max - index_min >= 2**self.index_width: return self.z3obj res = z3.Array(self.name, z3.BitVecSort(self.index_width), z3.BitVecSort(self.value_width)) for i in range(index_min, index_max + 1): if i in self._conc_store: res = z3.Store(res, z3.BitVecVal(i, self.index_width), self._conc_store[i].z3obj) return res
def get_mem_array(self, size): """Returns a z3 Array used internally to represent memory for addresses of size @size. @size: integer, size in bit of addresses in the memory to get. Return a z3 Array: BitVecSort(size) -> BitVecSort(8). """ try: mem = self.mems[size] except KeyError: # Lazy instantiation self.mems[size] = z3.Array(self.name + str(size), z3.BitVecSort(size), z3.BitVecSort(8)) mem = self.mems[size] return mem
def wall2(): global p #setup the key to expand logger.info("setting up sym args") key = claripy.BVS('key', 8 * 16) keyarr = [key.get_byte(i) for i in range(16)] #Make sure angr only uses 1 solver s = p.factory.blank_state(remove_options={angr.options.COMPOSITE_SOLVER}) s.add_constraints(*[k != '\0' for k in keyarr]) logger.info("starting symbolic execution on aes") aes_addr = p.loader.find_symbol('malicious_aes_test').rebased_addr aes = p.factory.callable(aes_addr, base_state=s) #when calling the function, use the python list so angr makes a pointer r = aes(keyarr) s = aes.result_state s.add_constraints(r == 3) #now we are going to use the tuples generated by Te4_lookup # we will build a z3 function then use a symbolic index # this is much faster than state.memory.load with a symbolic addr z3_table = z3.Function("Te4", z3.BitVecSort(8), z3.BitVecSort(8)) #there is only one solver because we specified no composite solver option z3_solver = s.solver._solver._get_solver() #extract the Te4 table from program memory and turn it into a z3 func Te4 = p.loader.find_symbol("Te4").rebased_addr for i in range(256): z3_solver.add(z3_table(i) == s.mem[Te4 + i * 4].uint8_t.concrete) #for each tuple saved in Te4_lookup, convert to z3 bv then # assert that the index and result are related via the z3 function for e in s.globals['table_lookups']: idx, res = map(claripy.backends.z3.convert, e) z3_solver.add(z3_table(idx) == res) #ensure the problem is sat logger.info("Checking satisfiability") query = z3_solver.check() logger.info(query) assert (query == z3.sat) logger.info("Getting model") m = z3_solver.model() #make our function's input a z3 bv z3key = claripy.backends.z3.convert(key) def long_to_str(l): return hex(l)[2:].replace('L', '').decode('hex') resolved_key = long_to_str(m[z3key].as_long()) logger.info("KEY: %s", repr(resolved_key)) # KEY: 'ACHIEVEMENTAWARD' return [resolved_key]
def z3obj(self): if self._z3obj is not None: # symbolic mode return self._z3obj # concrete mode if self._z3objConcCache is not None: return self._z3objConcCache res = z3.Array(self.name, z3.BitVecSort(self.index_width), z3.BitVecSort(self.value_width)) for index in self._conc_store: res = z3.Store(res, z3.BitVecVal(index, self.index_width), self._conc_store[index].z3obj) self._z3objConcCache = res return res
def __init__(self, name, z3_args, parent_const=None): self.p4_attrs = {} self.name = name self.z3_type = z3.BitVecSort(32) for idx, enum_name in enumerate(z3_args): self.p4_attrs[enum_name] = z3.BitVecVal(idx, 32) self.z3_args = z3_args
def _populate_enums(): module = sys.modules[__name__] ctx = libirpy.newctx() import hv6py.kernel.impl as hv6 hv6._init_metadata(ctx) for k, v in ctx.metadata.items(): if isinstance(v, tuple) and v[0] == 'DICompositeType': if v[1].get('tag') == 'DW_TAG_enumeration_type': name = v[1].get('name') size = v[1].get('size') elements = v[1].get('elements') if name is None or size is None or elements is None: continue setattr(module, name + '_t', z3.BitVecSort(size)) enum = {} for element in ctx.metadata.get(elements): element = ctx.metadata.get(element) assert element[0] == 'DIEnumerator' element_name = element[1].get('name') element_value = element[1].get('value') enum[element_name] = z3.BitVecVal(element_value, size) setattr(module, name, type(name, (), enum))
def __init__(self, name, fields): self.locals = {} self.name = name self.z3_type = z3.BitVecSort(32) for idx, enum_name in enumerate(fields): self.locals[enum_name] = z3.BitVecVal(idx, 32) self.fields = fields
def __init__(self, arch): self.arch = arch self.stmt = [] self.out_regs = {} self.reg_count = collections.defaultdict(int, {}) # Make sure all the registers have initial BitVecs in the constraints for name, (num, size) in self.arch.registers.items(): real_name = self.arch.translate_register_name(num) # So we don't get both sp and rsp, ip and rip, etc. if real_name not in self.out_regs and real_name not in extra_archinfo.IGNORED_REGISTERS[self.arch.name]: self.out_regs[num] = z3.BitVec("{}_before".format(real_name), size * 8) # Setup the initial memory self.memory = z3.Array("mem_before", z3.BitVecSort(self.arch.bits), z3.BitVecSort(8)) self.mem_count = 0 self.first_mem = self.memory
def test_translate(self): fp = z3.Fixedpoint() atom1 = ast.Atom('p', [ ast.NumConstant(2, 'int4'), ast.NumConstant(3, 'int4'), ast.Variable('X', 'int4') ]) atom2 = ast.Atom('p', [ ast.NumConstant(2, 'int4'), ast.NumConstant(3, 'int4'), ast.Variable('Y', 'int4') ]) int4 = z3.BitVecSort(4) p = z3.Function('p', int4, int4, int4, z3.BoolSort()) a0 = z3.BitVecVal(2, int4) a1 = z3.BitVecVal(3, int4) a2 = z3.Const('X', int4) a3 = z3.Const('Y', int4) args1 = [a0, a1, a2] args2 = [a0, a1, a3] project = projection.Projection([], None) project.grounded = {'p': (0, 1)} project.items = {'p': {}} project.relations = {'p': p} result = project.translate(fp, atom1, args1) self.assertIn((0, 1), project.items['p']) self.assertIn((a0, a1), project.items['p'][(0, 1)]) p0 = project.items['p'][(0, 1)][(a0, a1)] self.assertIs(True, z3.is_true(z3.simplify(p0(a2) == result))) result2 = project.translate(fp, atom2, args2) self.assertIs(True, z3.is_true(z3.simplify(p0(a3) == result2)))
def do_F2I(op, stack, state): prev_type = state.esil["type"] state.esil["type"] = FLOAT val, = pop_values(stack, state) stack.append(z3.fpToUBV(FPM, val, z3.BitVecSort(SIZE))) state.esil["type"] = prev_type
def test_z3_to_array_fails(self): s = z3.BitVecSort(4) x = z3.Const('x', s) types = [primitives.TYPES['int4']] self.assertRaises(obase.Z3NotWellFormed, lambda: z3r.z3_to_array(x, types)) self.assertRaises(obase.Z3NotWellFormed, lambda: z3r.z3_to_array(z3.Or(x > 2, x < 1), types))
def z3BitVecSort(self, width): """Return the z3 BitVecSort for the given width.""" try: bvsort = self._z3BitVecSorts[width] except KeyError: bvsort = z3.BitVecSort(width) self._z3BitVecSorts[width] = bvsort return bvsort
def _fresh_ref(typ, tup, depth, name=None): if typ.is_pointer() and depth != 0: d[tup] = None if typ.is_int() or (typ.is_pointer() and depth != 0): args = [z3.BitVecSort(64)] * depth + [z3.BitVecSort(typ.size())] if name is None: name = ref._name else: name = ref._name + "->" + name d[tup] = z3.Function(util.fresh_name(name), *args) elif typ.is_struct(): for i in range(len(typ.fields())): _fresh_ref(typ.field(i), tup + (i, ), depth, typ.field_name(i)) elif typ.is_array() or typ.is_pointer(): _fresh_ref(typ.deref(), tup, depth + 1) else: assert False, "unhandled case"
def get_sym_bitvec(self, constraint_type, gen, bv_size=256, unique=False, **kwargs): vector_name = ConstraintType[constraint_type.name].value label_template = vector_name + '_gen{}' for k in kwargs: label_template += '_' + k + '{' + k + '}' label = label_template.format(gen, **kwargs) if unique: unique_id = self.unique_vector_name_counter.get(vector_name, 0) self.unique_vector_name_counter[vector_name] = unique_id + 1 label = label + '_uid' + str(unique_id) assert constraint_type != ConstraintType.CALLDATA or 'acc' not in kwargs if constraint_type == ConstraintType.CALLDATA_ARRAY: return z3.Array(label, z3.BitVecSort(bv_size), z3.BitVecSort(8)) elif constraint_type in [ConstraintType.CALLER, ConstraintType.ORIGIN, ConstraintType.ENTRY_ACCOUNT]: return svm_utils.zpad_bv_right(z3.BitVec(label, svm_utils.ADDRESS_LEN), svm_utils.VECTOR_LEN) else: return z3.BitVec(label, bv_size)
def createConstantArray(awidth, dwidth, mem_values): asize = z3.BitVecSort(awidth) arr = z3.K(asize, z3.BitVecVal(mem_values[-1], dwidth)) for [a, d] in mem_values[:-1]: az3 = z3.BitVecVal(a, awidth) dz3 = z3.BitVecVal(d, dwidth) arr = z3.Update(arr, az3, dz3) return arr
def __init__(self, domain: int, value_range: int, value: int): """Initializes an array with a default value. :param domain: The domain for the array (10 -> all the values that a bv of size 10 could take) :param value_range: The range for the values in the array (10 -> all the values that a bv of size 10 could take) :param value: The default value to use for this array """ self.domain = z3.BitVecSort(domain) self.value = z3.BitVecVal(value, value_range) self.raw = z3.K(self.domain, self.value)
def _type_to_z3(self, tp): if tp.is_bool_type(): return z3.BoolSort() elif tp.is_real_type(): return z3.RealSort() elif tp.is_int_type(): return z3.IntSort() else: assert tp.is_bv_type() , "Unsupported type '%s'" % tp return z3.BitVecSort(tp.width)
def __init__(self, name, key_type, val_type): self.name = name self.key_type = key_type self.val_type = val_type key_sorts = [] for t in key_type: key_sorts.append(z3.BitVecSort(t * 8)) self.ufs = [] uf_name_base = fresh_name(self.name) cnt = 0 contains_uf = z3.Function(uf_name_base + '!contains', *key_sorts, z3.BoolSort()) self.contains = lambda *keys, old_f=contains_uf: old_f(*keys) for t in val_type: val_sort = z3.BitVecSort(t * 8) uf = z3.Function(uf_name_base + '!' + str(cnt), *key_sorts, val_sort) lambda_f = lambda *keys, old_f=uf: old_f(*keys) self.ufs.append(lambda_f) cnt += 1
def __init__(self, name=None): # each instance of the element will get a unique name upon creation self.se = z3 self.unique_name = None if name is not None: self.unique_name = name else: self.unique_name = utils.fresh_name(self.name()) self.state = {} self.packet_format = None cls = self.__class__ if self.helper_funcs is not None and not hasattr(cls, '_ele_helpers'): for entry in self.helper_funcs: t = entry[1] if t == 'deter': key_sorts = [] for kt in entry[2]: key_sorts.append(z3.BitVecSort(kt * 8)) fs = [] cnt = 0 num_val = len(entry[3]) func_name = cls.__name__ + "!" + entry[0] for vt in entry[3]: v_sort = z3.BitVecSort(vt * 8) f = z3.Function(func_name + "!" + str(cnt), *key_sorts, v_sort) fs.append(f) cnt += 1 def helper_func(*params): result = [] if 'as_sexpr' not in dir(params[0]): for i in range(num_val): result.append(fs[i](*params)) else: for i in range(num_val): result.append(SpecAst(func_name, i, *params)) return tuple(result) setattr(cls, entry[0], helper_func) setattr(cls, '_ele_helpers', True)