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 test_dependence_map(): # Arrange x = z3.BitVec("x", 256) y = z3.BitVec("y", 256) z = z3.BitVec("z", 256) a = z3.BitVec("a", 256) b = z3.BitVec("b", 256) conditions = [x > y, y == z, a == b] dependence_map = DependenceMap() # Act for condition in conditions: dependence_map.add_condition(condition) # Assert assert 2 == len(dependence_map.buckets) assert x in dependence_map.buckets[0].variables assert y in dependence_map.buckets[0].variables assert z in dependence_map.buckets[0].variables assert len(set(dependence_map.buckets[0].variables)) == 3 assert conditions[0] in dependence_map.buckets[0].conditions assert conditions[1] in dependence_map.buckets[0].conditions assert a in dependence_map.buckets[1].variables assert b in dependence_map.buckets[1].variables assert len(set(dependence_map.buckets[1].variables)) == 2 assert conditions[2] in dependence_map.buckets[1].conditions
def mkByteList(op): locs = op.getLocations() if (len(locs) > 1): return map(lambda b: z3.BitVec(str(b), 8), locs) else: return [z3.BitVec(str(locs[0]), 8)]
def advance(self, n, i, first): # add all intermediate states for each step for x in range(0, n): p1 = z3.BitVec("part" + str(self.states), 32) p2 = z3.BitVec("part" + str(self.states + 1), 32) p3 = z3.BitVec("part" + str(self.states + 2), 32) self.solver.add(p1 == self.current ^ (self.current << 13)) self.solver.add(p2 == p1 ^ z3.LShR(p1, 14)) self.solver.add(p3 == p2 ^ (p2 << 15)) self.states += 3 self.current = p3 # if this is the "leak" at the beginning, add it directly if first > 0: self.solver.add((p3 & 0xFFFF) == first) # if this isn't, we've stopped on a stable state and should add constraints else: """ unsigned char n = (x & (0xFF << i)) >> i; if (n != 0 && n == (n & -n)) { """ n = z3.LShR(self.current & (0xFF << i), i) self.solver.add(n != 0) #self.solver.add(z3.LShR(self.current & (0xFF << i), i) != 0) self.solver.add(n == n & -n) #self.solver.add(z3.LShR(self.current & (0xFF << i), i) == (z3.LShR(self.current & (0xFF << i), i) & z3.LShR((-self.current) & (0xFF << i), i))) # update our guess if we're still SAT if self.check() != z3.sat: raise RuntimeError("UNSAT") else: print "NEW GUESS: %d" % self.get_seed()
def run_test_execution(self): for upper_bound in (0, 1, 50): x, y = z3.BitVec("x", 4), z3.BitVec("y", 8) formula: z3.BoolRef = z3.ULT(z3.ZeroExt(4, x) + y, z3.BitVecVal(upper_bound, 8)) self.assert_eamp_edge_scheduler_execution(100, 2, 0.99, FormulaParamsZ3(formula=formula, variables=[x, y])) x, y = z3.BitVec("x", 8), z3.BitVec("y", 8) formula: z3.BoolRef = z3.ULT(y, 100) model_count = (2 ** 8) * 100 for q in (1, 2, 3, 4) if RUN_MINI_BENCHMARK else (1,): t0 = perf_counter() self.assert_eamp_edge_scheduler_execution(100, q, 0.99, FormulaParamsZ3( formula=formula, variables=[x, y] ), model_count) print(f"Mini Benchmark {self.get_eamp_edge_scheduler_class()} q={q} took {perf_counter() - t0:.2f}") zs = [z3.BitVec(f"z{idx}", 1) for idx in range(50)] formula: z3.BoolRef = z3.And([zs[idx] == 1 for idx in range(25)]) model_count = 2 ** 25 self.assert_eamp_edge_scheduler_execution( 100, 1, 0.99, FormulaParamsZ3( formula=formula, variables=zs ), model_count)
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 solve(mask, compromise): shiftlen = 64 - popcount(mask) - compromise bb = z3.BitVec("bb", 64) masked_bb = [z3.BitVec(f"masked_bb_{i}", 64) for i in range(2 ** popcount(mask))] magic_number = z3.BitVec("magic_number", 64) imul_tmp = [z3.BitVec(f"imul_tmp_{i}", 64) for i in range(2 ** popcount(mask))] result_index_short = [z3.BitVec(f"result_index_{i}", popcount(mask) + compromise) for i in range(2 ** popcount(mask))] s = z3.Solver() for i in range(2 ** popcount(mask)): s.add(masked_bb[i] == pdep(i, mask)) s.add(imul_tmp[i] == masked_bb[i] * magic_number) s.add(result_index_short[i] == z3.Extract(63, 63 - popcount(mask) - compromise + 1, imul_tmp[i])) s.add(z3.Distinct(result_index_short)) # for i in range(2 ** popcount(mask)): # for j in range(i + 1, 2 ** popcount(mask)): # s.add(result_index_short[i] != result_index_short[j]) s.add(magic_number >= 1) time_start = time.time() result = s.check() time_end = time.time() print(f"mask = {hex64(mask)}") print(f"compromise = {compromise}") print(f"result = {result}") print(f"elapsed time = {int(time_end - time_start)} second") if result == z3.unsat: return False print(f"magic_number = {hex64(s.model()[magic_number].as_long())}") return True
def main(): x = z3.BitVec('x', 8) y = z3.BitVec('y', 8) s = z3.Solver() s.add(((x << 2) + (3 * y)) == z3.BitVecVal(0x41, 8)) s.add(((x >> 4) - (y << 2)) > z3.BitVecVal(0x10, 8)) s.add(((x * 5) - (y * 2)) > z3.BitVecVal(0x42, 8)) s.add(x != z3.BitVecVal(0, 8)) s.add(y != z3.BitVecVal(0, 8)) while s.check() == z3.sat: # Get a model satisfying the rules. model = s.model() # Do something with the model print model # Prevent the same model from showing up again. block = [] for instance in model: if instance.arity() > 0: raise z3.Z3Exception( "uninterpreted functions are not supported") constant = instance() if z3.is_array(constant) or constant.sort().kind( ) == z3.Z3_UNINTERPRETED_SORT: raise Z3Exception( "arrays and uninterpreted sorts are not supported") block.append(constant == model[instance]) inverted_block = z3.Not(z3.And(block)) s.add(inverted_block)
def make_constraints_next(n_constraints: int, slope: int = 0x5DEECE66D, intercept: int = 0xB, gen_bits=31): # Define some constants addend = z.BitVecVal(intercept, 64) multiplier = z.BitVecVal(slope, 64) mask = z.BitVecVal((1 << 48) - 1, 64) # Define symbolic variables for the seed variable seeds = { f'seed_{i}': z.BitVec(f'seed_{i}', 64) for i in range(n_constraints) } constraints = [] # Build constraints for the relation in row 175 for i in range(1, n_constraints): constraints.append(seeds[f'seed_{i}'] == z.simplify( (seeds[f'seed_{i - 1}'] * multiplier + addend) & mask)) # Define symbolic variables for the output from next() next_outputs = { f'next_output_{i}': z.BitVec(f'output{i}', 32) for i in range(1, n_constraints) } # Build the constraints for the relation in row 176 for i in range(1, n_constraints): constraints.append(next_outputs[f'next_output_{i}'] == z.simplify( z.Extract(31, 0, z.LShR(seeds[f'seed_{i}'], 48 - gen_bits)))) return constraints, seeds, next_outputs
def break_rand(nums: list, next_num: int): n_nums = len(nums) # print(f'len nums: {n_nums}') states = { f'state_{i}': z.BitVec(f'state_{i}', 32) for i in range(1, n_nums + 2) } # print(states) output_next = z.BitVec('output_next', 32) s = z.Solver() for i in range(2, n_nums + 2): s.add(states[f'state_{i}'] == states[f'state_{i - 1}'] * 214013 + 2531011) for i in range(1, n_nums + 1): s.add( z.URem((states[f'state_{i}'] >> 16) & 0x7FFF, 100) == nums[i - 1]) s.add(output_next == z.URem((states[f'state_{n_nums + 1}'] >> 16) & 0x7FFF, 100)) # print(s) if s.check() == z.sat: print(f'For the sequence: {nums}, problem is satisfiable') print( f'We were expecting: {next_num} and got: {s.model()[output_next]}\n' ) else: print(f'For the sequence: {nums}, problem is unsatisfiable') return s, states, output_next
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 ex1_goal(): x = z3.BitVec('x', 8) y = z3.BitVec('y', 8) h = z3.BitVec('h', 8) phi_n = (y == x * 4) phi_s = (y == x << h) return (z3.ForAll([x, y], phi_n == phi_s))
def __init__(self, known_values): self.s0 = z3.BitVec('s0', 64) self.s1 = z3.BitVec('s1', 64) self.state = [self.s0, self.s1] self.solver = z3.Solver() # The known variable will contain the values that we generated in Firefox self.known = known_values
def z3_new_state(arch): state = { "stack": z3.BitVec(unique("stack"), arch.page_size*8), "constraints": [] } for reg in arch.regs: state[reg] = z3.BitVec(unique(reg), arch.bits) return state
def gen_symbolic_value(var_type, name): if var_type == bin_format.i32: return z3.BitVec(name, 32) if var_type == bin_format.i64: return z3.BitVec(name, 64) if var_type == bin_format.f32: return z3.FP(f'f32_{i}', z3.Float32()) if var_type == bin_format.f64: return z3.FP(name, z3.Float64()) raise TypeError('Unsupported variable type')
def gen_collision(): qword1_expr = z3.BitVec("qword1", 64) qword2_expr = z3.BitVec("qword2", 64) z3_hash = hash_bytes([qword1_expr, qword2_expr]) solver = z3.Solver() solver.append(z3_hash == HASH) result = solver.check() assert str(result) == "sat", result model = solver.model() return model[qword1_expr].as_long(), model[qword2_expr].as_long()
def make_value_vars(prefix): vInput = list( z3.BitVecs(id_arr(f'{prefix}_valInput', nInput), 32, ctx)) vPR = [(list( z3.BitVecs(id_arr(f'{prefix}_valParam_{i}', comp.arity), 32, ctx)), z3.BitVec(f'{prefix}_valReturn_{i}', 32, ctx)) for i, comp in enumerate(lib)] vOutput = z3.BitVec(f'{prefix}_valOutput', 32, ctx) return vInput, vPR, vOutput
def from_ExprLoc(self, expr): if self.loc_db is None: # No loc_db, fallback to default name return z3.BitVec(str(expr), expr.size) loc_key = expr.loc_key offset = self.loc_db.get_location_offset(loc_key) if offset is not None: return z3.BitVecVal(offset, expr.size) # fallback to default name return z3.BitVec(str(loc_key), expr.size)
def abstract(self, label_suffix): old_storage = self.storage self.storage = AbstractStorage(f'abstract_storage{label_suffix}') for map_id in self.mapping_id_to_sum: if svm_utils.is_bv_concrete(map_id): map_id_string = svm_utils.get_concrete_int(map_id) else: map_id_string = str(z3.simplify(map_id)) raise Exception("pdb") label = f'abstract_sum_{map_id_string}{label_suffix}' self.mapping_id_to_sum[map_id] = z3.BitVec(label, 256) self.balance = z3.BitVec(f'gstate_balance{label_suffix}', 256)
def add_register(self, reg: Dict): start = reg["offset"] end = reg["offset"] + reg["size"] size = reg["size"] reg["start"] = start reg["end"] = end self._registers[reg["name"]] = reg key = (start, end) reg_value = self.get_register_from_bounds(reg) if reg_value != None: # this shouldnt happen idk if reg_value["size"] < size: reg_value["size"] = size reg_value["start"] = start reg_value["end"] = end if self.pure_symbolic and reg["name"] != self.aliases["PC"][ "reg"] and reg["type_str"] != "flg": reg.pop("value") reg_value["bv"] = z3.BitVec(reg["name"], size) else: reg_value["bv"] = z3.BitVecVal(reg.pop("value"), size) reg_value["bounds"] = key self.offset_dictionary[key] = reg_value reg["bounds"] = reg_value["bounds"] reg["sub"] = True else: reg_value = { "type": reg["type"], "size": size, "start": start, "end": end } if "value" in reg and (not self.pure_symbolic or reg["name"] == self.aliases["PC"]["reg"] or reg["type_str"] == "flg"): reg_value["bv"] = z3.BitVecVal(reg.pop("value"), size) else: reg.pop("value") reg_value["bv"] = z3.BitVec(reg["name"], size) reg_value["bounds"] = key self.offset_dictionary[key] = reg_value reg["bounds"] = key reg["sub"] = False
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_ExprLoc(self, expr): if self.symbol_pool is None: # No symbol_pool, fallback to default name return z3.BitVec(str(expr), expr.size) loc_key = expr.loc_key offset = self.symbol_pool.loc_key_to_offset(loc_key) name = self.symbol_pool.loc_key_to_name(loc_key) if offset is not None: return z3.BitVecVal(offset, expr.size) if name is not None: return z3.BitVec(name, expr.size) # fallback to default name return z3.BitVec(str(loc_key), expr.size)
def replace_bv_sequences_with_conjectures(z3from, prefix): """ Returns a modified z3 expression substituting conjectures in place of sequences""" concat_sequences = find_symbolic_byte_concat_sequences(z3from, prefix) also = find_symbolic_variables_in_numerical_expressions(z3from) #the idea here is that any concat sequence of length 4 will be replaced with #an integer conjecture... if the variables in that integer conjecture are also #involved in numerical expressions, we strengthen the conjecture modified_z3 = z3from for s in concat_sequences: if abs(s[1] - s[0]) + 1 == 4: if all_in_sequence_in_set(s, also, prefix): conjecture_label = "?" else: conjecture_label = "??" if s[0] < s[1]: #it is a sequence like sym_0, sym_1, sym_2, sym_3 s0 = z3.BitVec(prefix + str(s[0]), 8) s1 = z3.BitVec(prefix + str(s[0] + 1), 8) s2 = z3.BitVec(prefix + str(s[0] + 2), 8) s3 = z3.BitVec(prefix + str(s[0] + 3), 8) s32 = z3.BitVec( prefix + "[" + str(s[0]) + "-" + str(s[1]) + "]-" + conjecture_label + "_intbe:32", 32) modified_z3 = z3.substitute(modified_z3, (s0, z3.Extract(31, 24, s32))) modified_z3 = z3.substitute(modified_z3, (s1, z3.Extract(23, 16, s32))) modified_z3 = z3.substitute(modified_z3, (s2, z3.Extract(15, 8, s32))) modified_z3 = z3.substitute(modified_z3, (s3, z3.Extract(7, 0, s32))) else: # it is a sequence like sym_3, sym_2, sym_1, sym_0 s3 = z3.BitVec(prefix + str(s[0]), 8) s2 = z3.BitVec(prefix + str(s[0] - 1), 8) s1 = z3.BitVec(prefix + str(s[0] - 2), 8) s0 = z3.BitVec(prefix + str(s[0] - 3), 8) s32 = z3.BitVec( prefix + "[" + str(s[1]) + "-" + str(s[0]) + "]-" + conjecture_label + "_intle:32", 32) modified_z3 = z3.substitute(modified_z3, (s0, z3.Extract(31, 24, s32))) modified_z3 = z3.substitute(modified_z3, (s1, z3.Extract(23, 16, s32))) modified_z3 = z3.substitute(modified_z3, (s2, z3.Extract(15, 8, s32))) modified_z3 = z3.substitute(modified_z3, (s3, z3.Extract(7, 0, s32))) #more type conjectures needed for different types and sizes return modified_z3
def solve(n, keylen): mlen = len(ct) total = mlen * 8 nytes = total // n s = z3.Solver() pt = z3.BitVec("pt", total) key = z3.BitVec("key", total) cipher = z3.BitVec("ct", total) def nyte(bitvec, n, i): """Extract the i'th n-bit value from bitvec.""" start = bitvec.size() - n - (i * n) return z3.Extract(start + n - 1, start, bitvec) # Plaintext is ascii for i in xrange(mlen): s.add(nyte(pt, 8, i) >= 0x20) s.add(nyte(pt, 8, i) <= 0x7e) # Plaintext starts with "flag{" and ends with "}" for i, c in enumerate("flag{"): s.add(nyte(pt, 8, i) == ord(c)) s.add(nyte(pt, 8, mlen - 1) == ord("}")) # Key is repeating for i in xrange(keylen, mlen): s.add(nyte(key, 8, i) == nyte(key, 8, i % keylen)) # Known ciphertext for i, c in enumerate(ct): s.add(nyte(cipher, 8, i) == ord(c)) # Transformation for i in xrange(nytes): m = nyte(pt, n, i) k = nyte(key, n, i) c = nyte(cipher, n, i) s.add(c == (m + k) & ((1 << n) - 1)) cnt = 0 while z3.sat == s.check(): if cnt > 5: return cnt += 1 plaintext = s.model()[pt].as_long() flag = hex(plaintext)[2:-1].decode("hex") print "[*] {:s}".format(flag) s.add(pt != plaintext)
def getOperands(self, ops, concat=True): rops = [] for op in ops: if (op.isVar()): if (op.size > 1): rops.append( z3.Concat( map(lambda b: z3.BitVec(b, 8), op.get_bytes()))) else: rops.append(z3.BitVec(op.get_bytes()[0], 8)) else: rops.append(z3.BitVecVal(op.getValue(), 8 * op.size)) return rops
def untemper(y): y0 = z3.BitVec('y0', 32) y1 = z3.BitVec('y1', 32) y2 = z3.BitVec('y2', 32) y3 = z3.BitVec('y3', 32) equ = [ y1 == y0 ^ ((z3.LShR(y0, 11)) & 0xffffffff), y2 == y1 ^ ((y1 << 7) & 0x9d2c5680), y3 == y2 ^ ((y2 << 15) & 0xefc60000), y == y3 ^ (z3.LShR(y3, 18)) ] solver = z3.Solver() solver.add(equ) assert solver.check() == z3.z3.CheckSatResult(z3.Z3_L_TRUE) return solver.model()[y0].as_long()
def gen_input_symbol(self): name = 'input%d' % self.input_idx self.input_idx += 1 var = z3.BitVec(name, 8) if debug > 0: print(GREEN + 'created symbolic variable: %s' % var + NORMAL) return var
def test_get_expr_variables(): # Arrange x = z3.Bool("x") y = z3.BitVec("y", 256) z = z3.BitVec("z", 256) b = z3.BitVec("b", 256) expression = z3.If(x, y, z + b) # Act variables = list(map(str, _get_expr_variables(expression))) # Assert assert str(x) in variables assert str(y) in variables assert str(z) in variables assert str(b) in variables
def test_multi32(): r2p = r2pipe.open("test/tests/multi32", flags=["-2"]) r2p.cmd("s sym.check; aei; aeim; wv 162517261 @ 0x00178004") esilsolver = ESILSolver(r2p, debug=False, trace=False) #esilsolver.initVM() state = esilsolver.init_state() state.memory.write_bv(0x00178004, z3.BitVec("arg1", 32), 4) state = esilsolver.run(target=0x0000052d) eax = state.registers["eax"] state = esilsolver.run(target=0x00000558) state.solver.add(state.registers["zf"] == 1) state = esilsolver.run(target=0x00000588) print(state.registers["zf"]) state.solver.add(state.registers["zf"] == 1) print("solving") sat = state.solver.check() print(sat) m = state.solver.model() print(m.eval(eax))
def convert_to_z3(self, variables): if self.operation == Node.CONSTANT: return z3.BitVecVal(self.left, self.target_width) elif self.operation == Node.VARIABLE: if self.left in variables: return variables[self.left] else: var = z3.BitVec(self.left, self.variable_width) ext_var = z3.ZeroExt(self.target_width - self.variable_width, var) variables[self.left] = ext_var return ext_var else: # operation left = self.left.convert_to_z3(variables) right = self.right.convert_to_z3(variables) if self.operation == Node.ADDITION: return left + right elif self.operation == Node.SUBTRACTION: return left - right elif self.operation == Node.MULTIPLICATION: return left * right elif self.operation == Node.DIVISION: return left / right elif self.operation == Node.LEFT_SHIFT: return left << right elif self.operation == Node.RIGHT_SHIFT: return left >> right elif self.operation == Node.AND: return left & right elif self.operation == Node.OR: return left | right elif self.operation == Node.XOR: return left ^ right raise LookupError('Unknown operation: %s' % str(self.operation))