def construct(self, obj): ''' Takes in a ConstructableObject with preconditions and postconditions. Checks that preconditions hold in the proof context and if so, asserts the post-conditions. ''' self.solver.push() for prereq in obj.prereqs: self.solver.add(simplify(prereq, blast_distinct = True)) prereqCheck = self.solver.check() if str(prereqCheck) != 'sat': print "ProofCheck >> Construction Failed - Could not meet: " + str(prereq) self.solver.pop() return False if len(obj.prereqs) > 0: self.assumptions.extend(obj.prereqs) for conclusion in obj.conclusions: self.solver.add(simplify(conclusion, blast_distinct=True)) self.conclusions.append(conclusion) if isinstance(obj, Point): self.points[obj.label] = obj elif isinstance(obj, Line): self.lines[obj.label] = obj elif isinstance(obj, Circle): self.circles[obj.label] = obj self.solver.pop() self.solver.add(obj.prereqs) self.solver.add(obj.conclusions) return True
def get_lazy_pcs(self, pc): arg1 = z3.simplify(pc.arg(1)) arg2 = z3.simplify(pc.arg(2)) if z3.is_bv_value(arg1) and z3.is_bv_value(arg2): return [arg1.as_long(), arg2.as_long()] else: return []
def visit_WhileStmt_inv (self, node, *args, **kwargs): """" Symbolic execution of while loops with invariants """ print("node.inv=",node.inv) # evaluate invariant before the loop inv_pre = self.visit (node.inv, *args, **kwargs) print("node.inv_2.0=",inv_pre) # fork symbolic state to evaluate the invariant in the pre-condition pre_st, loop_st = kwargs['state'].fork () # pre_st.add_pc (z3.Not (inv_pre)) # if not pre_st.is_empty (): pre_st.add_pc (inv_pre) if pre_st.is_empty (): print ('Invariant not true on loop entry') print (node.inv) print (pre_st) # havoc all variables modified by the loop for v in self._defs (node.body): loop_st.env [v.name] = z3.FreshInt (v.name) # print("v",v,loop_st) # evaluate invariant after havoc and assume it inv_pre = z3.simplify (self.visit (node.inv, *args, state=loop_st)) loop_st.add_pc (inv_pre) # evaluate loop condition cond_val = self.visit (node.cond, *args, state=loop_st); # one state enters the loop, one exits enter_st, exit_st = loop_st.fork () # if enter loop, loop condition is true enter_st.add_pc (cond_val) # if exit loop, loop condition is false exit_st.add_pc (z3.Not (cond_val)) # if loop condition can be satisfied, check invariant preserved by loop body if not enter_st.is_empty (): # do loop body, might produce many new states # print("------------",kwargs["state"],enter_st) for out in self.visit (node.body, *args, state=enter_st): # print("--------------",out) # check that invariant holds at the end of each body inv_post = z3.simplify (self.visit (node.inv, *args, state=out)) # inv_post =self.visit (node.inv, *args, state=out) out.add_pc (z3.Not (inv_post)) if not out.is_empty (): print ('Invariant does not hold on loop exit') print( "2",exit_st) # print ('inv:', node.inv) # print ('inv_post', inv_post) # print ('out', out) # print ('pc', z3.And (out.path).sexpr ()) # if negation of loop condition is satisfied, continue execution after the loop if not exit_st.is_empty (): yield exit_st
def may_write_to(self, z3_index, z3_value, storage, constraint_list, consider_length): z3_index = simplify(get_bv(z3_index)) z3_value = simplify(get_bv(z3_value)) same_slot = False add_constraints = [] # z3-index directly pointing to this slot concret_index = BitVecVal(self.slot_counter, 256) # Compare expression equivalence if eq(concret_index, z3_index): same_slot = True # If not structurally equivalent, check if there is an assignment that allows them to be equivalent if not same_slot and not are_z3_satisfiable(constraint_list + [z3_index == concret_index]): return False, None add_constraints.append(simplify(z3_index == self.slot_counter)) index_str = str(z3_index) # Rule out keccak symbolic variable as the function prevents someone from arbitrarily controlling the index if len(z3_index.children()) < 2 and index_str.startswith("keccak") \ or "+" in index_str and index_str[:index_str.index("+")].strip() in keccak_map : return False, None # Todo Here I might do something more elaborate if I see that it does actually not solve critical writings # Problem because writing to an array has a keccak offset, but if the index can be arbitrarely choosen z3 finds # a solution for the controllable symbolic variable to match the index to any slot. #sym_ind_name = extract_sym_names(z3_index) #if any([name for name in sym_ind_name if name.startswith("keccak")]) and any([name for name in sym_ind_name if not name.startswith("keccak")]): # return False, None # If the slot is or may be the same and the slot we currently analyze is the same, we found a possible write if self.bitlength == 256: return True, add_constraints # If not, the slot is still written in its entirety but the observed chunk is loaded and overwritten by itself to_bit, from_bit = self.bit_counter + self.bitlength - 1, self.bit_counter # to_bit, from_bit = BitVecVal(self.bit_counter + self.bitlength - 1, 256), BitVecVal(self.bit_counter, 256) chunk_writing = Extract(to_bit, from_bit, z3_value) chunk_content = Extract(to_bit, from_bit, get_bv(get_storage_slot(BitVecVal(self.slot_counter, 256), storage))) # if the current content of the observed chunk and the respective chunk of the written value can be different # like by a different variable assignment, then we found it if are_z3_satisfiable(constraint_list + [Not(chunk_content == chunk_writing)]): # It is actually not important to use the constraint that the values are different, overwriting with the same # value is still writing. On the other hand it avoids references to storage that later have to be solved with # intertransactional analysis although the violation can be triggered in one transaction # add_constraints.append(simplify(Not(chunk_content == chunk_writing))) return True, add_constraints # For the 256-bit chunks the last step should not be necessary, but a compiler could generate some code that # overwrites a slot content with itself. This function would have a false positive in that case. return False, None
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 sig_line(foo, prev_v, nxt_v): foo_prev = x.maybe_usc_sig_usc_sub_usc_value.val(prev_v[foo[1]]) foo_nxt = x.maybe_usc_sig_usc_sub_usc_value.val(nxt_v[foo[1]]) foo_line = ("%20s %5s @ %12s -> %5s @ %12s" % (foo[0], str(simplify(x.sig_sub_value.value(foo_prev))), z3numstr(x.sig_sub_value.time(foo_prev)), str(simplify(x.sig_sub_value.value(foo_nxt))), z3numstr(x.sig_sub_value.time(foo_nxt)))) return (foo_line)
def visit_WhileStmt(self, node, *args, **kwargs): if node.inv is not None: pre_inv = z3.simplify(self.visit(node.inv, *args, **kwargs)) p_st, loop_st = kwargs['state'].fork() p_st.add_pc(z3.Not(pre_inv)) if not p_st.is_empty(): print('Invariant is false before entry the loop') print(node.inv) print(p_st) checker = wlang.undef_visitor.UndefVisitor() checker.check(node.body) for v in checker.get_defs(): loop_st.env[v.name] = z3.FreshInt(v.name) inv_pre = z3.simplify(self.visit(node.inv, *args, state=loop_st)) loop_st.add_pc(inv_pre) #if else cond = self.visit(node.cond, *args, state=loop_st) st = loop_st.fork() st[0].add_pc(cond) st[1].add_pc(z3.Not(cond)) #enter loop if not st[0].is_empty(): result = self.visit(node.body, state=st[0]) for out in result: inv_post = z3.simplify( self.visit(node.inv, *args, state=out)) out.add_pc(z3.Not(inv_post)) if not out.is_empty(): print('Invariant violation on loop exit') print('inv:', node.inv) print('out', out) print('pc', z3.And(out.path).sexpr()) if not st[1].is_empty(): return [st[1]] else: return [] todo = [kwargs['state']] done = [] for _ in range(11): if not todo: break res = [] for i in todo: cond = self.visit(node.cond, state=i) st = i.fork() st[0].add_pc(cond) st[1].add_pc(z3.Not(cond)) if not st[0].is_empty(): res.extend(self.visit(node.body, state=st[0])) if not st[1].is_empty(): done.append(st[1]) todo = res return done
def checkLengthBMC(M, bad, count): x = [] for i in range(count): x.append(M.addSuffix(str(i))) bad = z3.simplify(z3.And(bad(x[-1]))) init = z3.simplify(z3.And(M.initialize(x[0]))) trx = True for i in range(count-1): temp = M.transition(x[i]) temp = z3.And(*[xi == xpi for (xi, xpi) in itertools.izip(temp, x[i+1])]) trx = z3.And(trx, temp) S = z3.Solver() S.add(init) S.add(trx) S.add(bad) rBMC = (S.check()) if rBMC == z3.unsat: # Compute the interpolant formula1 = True formula2 = True xprime = [] for i in range(count): xprime.append(M.addSuffix(str(i)+"_prime")) formula1 = z3.And(init, trx) initprime = z3.simplify(z3.And(M.initialize(xprime[0]))) trxprime = True for i in range(count-1): temp = M.transition(xprime[i]) temp = z3.And(*[xi == xpi for (xi, xpi) in itertools.izip(temp, xprime[i+1])]) trxprime = z3.And(trxprime, temp) formula1 = z3.And(formula1, initprime, trxprime) # xval are the exact values that consecutive states of M take xval = [[0, 1]] temp = True for i in range(count-1): xval.append(M.transition(xval[i])) for i in range(1, count): temp = z3.And(temp, *[xi == xvi for (xi, xvi) in itertools.izip(x[i], xval[i])]) formula1 = z3.And(formula1, temp) Msc = SelfComposedTransitionSystem(M) formula2 = z3.simplify(z3.And(Msc.bad_sc(x[count-1]+xprime[count-1]))) return z3.unsat, x[count-1]+xprime[count-1], formula1 return rBMC, None, None
def jumpi_(self, global_state): state = global_state.mstate disassembly = global_state.environment.code states = [] op0, condition = state.stack.pop(), state.stack.pop() try: jump_addr = util.get_concrete_int(op0) # FIXME: to broad exception handler except: logging.debug("Skipping JUMPI to invalid destination.") return [global_state] index = util.get_instruction_index(disassembly.instruction_list, jump_addr) if not index: logging.debug("Invalid jump destination: " + str(jump_addr)) return [global_state] instr = disassembly.instruction_list[index] # True case condi = simplify(condition) if type( condition) == BoolRef else condition != 0 if instr['opcode'] == "JUMPDEST": if (type(condi) == bool and condi) or (type(condi) == BoolRef and not is_false(condi)): new_state = copy(global_state) new_state.mstate.pc = index new_state.mstate.depth += 1 new_state.mstate.constraints.append(condi if type(condi) == bool else simplify(condi)) states.append(new_state) else: logging.debug("True, Pruned unreachable states. at %s" % (state.pc)) # False case negated = simplify( Not(condition)) if type(condition) == BoolRef else condition == 0 if (type(negated) == bool and negated) or (type(negated) == BoolRef and not is_false(negated)): new_state = copy(global_state) new_state.mstate.depth += 1 new_state.mstate.constraints.append(negated if type(negated) == bool else simplify(negated)) states.append(new_state) else: logging.debug("False, Pruned unreachable states. at %s" % (state.pc)) return states
def exp_(self, global_state): state = global_state.mstate base, exponent = util.pop_bitvec(state), util.pop_bitvec(state) if (type(base) != BitVecNumRef) or (type(exponent) != BitVecNumRef): state.stack.append(BitVec("(" + str(simplify(base)) + ")**(" + str(simplify(exponent)) + ")", 256)) else: state.stack.append(pow(base.as_long(), exponent.as_long(), 2**256)) return [global_state]
def test_candidate(self, synth_func, candidate): # candidate = expr_string_to_z3(candidate_word, self.spec, synth_func['inputs']) goal = substitute_function_for_expression(self.spec.goal, synth_func["decl"], synth_func["z3_inputs"], candidate) while True: macro_decl = contains_funcs(goal, self._macros_decls) if macro_decl is None: break macro_name = macro_decl.name() macro = self.spec.macros[macro_name] macro_def = expr_string_to_z3(macro["definition"], self.spec, macro["inputs"]) macro_params = macro["z3_inputs"] goal = substitute_function_for_expression(goal, macro_decl, macro_params, macro_def) if self.universally_quantified: counter_example_constraints = [z3.BoolVal(True)] for counter_example in self.counter_examples: counter_example_constraints.append( z3.simplify( z3.substitute( goal, list(zip(self.spec.z3_variables, counter_example))))) counter_example_constraint = z3.simplify( z3.And(*counter_example_constraints)) if counter_example_constraint.eq(z3.BoolVal(False)): return "sat" if not counter_example_constraint.eq(z3.BoolVal(True)): goal = z3.And(goal, counter_example_constraint) else: if goal.eq(z3.BoolVal(True)): return "unsat" if goal.eq(z3.BoolVal(False)): return "sat" goal = z3.simplify(z3.Not(goal)) s = z3.Solver() s.add(goal) validity = str(s.check()) if validity == "sat": counter_example = [] model = s.model() for var in self.spec.z3_variables: counter_example.append(model.eval(var)) self.counter_examples.append(counter_example) return validity
def relationalInduction(M, Msc, bad_sc): xs = Msc.variables() xsp = Msc.variables('prime') bad = z3.simplify(z3.And(bad_sc(xs))) init = z3.And(Msc.init(xs)) check = z3.simplify(z3.And(init, bad)) S = z3.Solver() S.push() S.add(check) rInit = (S.check()) S.pop() assert (rInit == z3.unsat) S.push() good_assume = z3.simplify(z3.And(z3.Not(bad_sc(xs)))) bad_proofob = z3.simplify(z3.And(bad_sc(xsp))) trx = z3.simplify(z3.And(Msc.tr(xs, xsp))) S.add(good_assume) S.add(bad_proofob) S.add(trx) n = len(xs) // 2 while S.check() == z3.sat: m = S.model() xm1 = [m.eval(xsi) for xsi in xs[:n]] xm2 = [m.eval(xsi) for xsi in xs[n:]] bad1 = lambda xs: [ z3.And(*[xi == xmi for (xi, xmi) in itertools.izip(xm1, xs)]) ] bad2 = lambda xs: [ z3.And(*[xi == xmi for (xi, xmi) in itertools.izip(xm2, xs)]) ] print(xm1, xm2) (r1, vs1, inv1) = fixedpoint(M, bad1) if r1 == z3.unsat: sub1 = zip(vs1, xs[:n]) sub2 = zip(vs1, xs[n:]) p1 = z3.substitute(inv1, *sub1) p2 = z3.substitute(inv1, *sub2) S.add(p1) S.add(p2) print(p1, p2) continue (r2, vs2, inv2) = fixedpoint(M, bad2) if r2 == z3.unsat: sub1 = zip(vs2, xs[:n]) sub2 = zip(vs2, xs[n:]) p1 = z3.substitute(inv2, *sub1) p2 = z3.substitute(inv2, *sub2) S.add(p1) S.add(p2) print(p1, p2) S.pop()
def ast_eq(e1, e2, simplified=False): if not simplified: e1 = z3.simplify(e1) e2 = z3.simplify(e2) if e1.sort() != e2.sort(): return False if e1.decl().kind() != e2.decl().kind(): return False if z3.z3util.is_expr_val(e1) and z3.z3util.is_expr_val(e2): return e1.as_long() == e2.as_long() return all(ast_eq(c1, c2, True) for c1, c2 in zip(e1.children(), e2.children()))
def prove(self, hypotheses, conclusion=None, report=None): report = self.reportFun(report) x_hyps, x_concl = self.analyse_expt(hypotheses, conclusion, report) f_hyps, f_concl = self.fun_to_var([x_hyps, x_concl], report)[:] hyps = z3.simplify(f_hyps); concl = z3.simplify(f_concl) report('to_smt_w_expt.prove:') report(' hypotheses = ', hyps) report(' conclusion = ', concl) return super(to_smt_w_expt, self).prove(hyps, concl)
def search(self, addr, needle, length=None, reverse=False): max_len = self.max_len n = len(needle) if n == 0: return ZERO if length != None: nbv = z3.BitVecVal(n - 1, SIZE) length = z3.simplify(length - nbv) if z3.is_bv_value(length): max_len = length.as_long() else: length = z3.BitVecVal(max_len - n + 1, SIZE) ret_ind = self.error # hmm idk ind_con = z3.BoolVal(False) rargs = (0, max_len, 1) if reverse: rargs = (max_len, 0, -1) for i in range(*rargs): cs = self.read(addr + i, n) found = all([(self.solver.check(cs[k] != needle[k]) == z3.unsat) for k in range(n)]) # oof not_found = any([ (self.solver.check(cs[k] == needle[k]) == z3.unsat) for k in range(n) ]) new_ind = z3.BitVecVal(i, SIZE) over_len = self.solver.check(length > new_ind) == z3.unsat if not over_len: if found: ind_con = z3.And(length > new_ind, z3.Not(ind_con)) ret_ind = z3.If(ind_con, new_ind, ret_ind) return z3.simplify(ret_ind), i elif not not_found: new_cons = [cs[k] == needle[k] for k in range(n)] new_cons.append(length > new_ind) new_con = z3.And(*new_cons) ind_con = z3.And(new_con, z3.Not(ind_con)) ret_ind = z3.If(ind_con, new_ind, ret_ind) else: if not reverse: return z3.simplify(ret_ind), i return z3.simplify(ret_ind), max_len
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 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 calldataload_(self, global_state): state = global_state.mstate environment = global_state.environment op0 = state.stack.pop() try: offset = util.get_concrete_int(simplify(op0)) b = environment.calldata[offset] except AttributeError: logging.debug("CALLDATALOAD: Unsupported symbolic index") state.stack.append( BitVec( "calldata_" + str(environment.active_account.contract_name) + "[" + str(simplify(op0)) + "]", 256)) return [global_state] except IndexError: logging.debug("Calldata not set, using symbolic variable instead") state.stack.append( BitVec( "calldata_" + str(environment.active_account.contract_name) + "[" + str(simplify(op0)) + "]", 256)) return [global_state] if type(b) == int: val = b'' try: for i in range(offset, offset + 32): val += environment.calldata[i].to_bytes(1, byteorder='big') logging.debug("Final value: " + str(int.from_bytes(val, byteorder='big'))) state.stack.append( BitVecVal(int.from_bytes(val, byteorder='big'), 256)) # FIXME: broad exception catch except: state.stack.append( BitVec( "calldata_" + str(environment.active_account.contract_name) + "[" + str(simplify(op0)) + "]", 256)) else: # symbolic variable state.stack.append( BitVec( "calldata_" + str(environment.active_account.contract_name) + "[" + str(simplify(op0)) + "]", 256)) return [global_state]
def visit_WhileStmt(self, node, *args, **kwargs): if node.inv is not None: sim_inv = z3.simplify(self.visit(node.inv, *args, **kwargs)) init_state = kwargs['state'].fork() not_inv_state = init_state[0] inv_state = init_state[1] # inv fails initiation if not_inv_state.addcond_isSolvable(z3.Not(sim_inv)): print("inv fails initiation") # use Undefined Use Visitor to find all variables that are modified or defined for var in self._defs(node.body): inv_state.env[var.name] = z3.FreshInt(var.name) # add inv into pc of inv_state inv_state.add_pc(z3.simplify(self.visit(node.inv, *args, state=inv_state))) # fork the state based on the condition and process both conditions accordingly cond = self.visit(node.cond, *args, state=inv_state) inv_states = inv_state.fork() #cond is satisfied, enter the loop if inv_states[0].addcond_isSolvable(cond): final_state = self.visit(node.body, state=inv_states[0]) for st in final_state: if st.addcond_isSolvable(z3.simplify(self.visit(node.inv, *args, state=st))): print("inv fails invariance") if inv_states[1].addcond_isSolvable(z3.Not(cond)): return[inv_states[1]] else: return[] done = [] while_states = [kwargs['state']] executed_time = 1 while(len(while_states) != 0 and executed_time <= 10): executed_time += 1 updated_while_states = [] for state in while_states: cond = self.visit(node.cond, state=state) cond_fork = state.fork() # if after adding condition, state is still solvable, visit node.body, # and extend returned state-list if cond_fork[0].addcond_isSolvable(cond): updated_while_states.extend(self.visit(node.body, state=cond_fork[0])) # if after adding not condition, state is still solvable, append the termination state into returning states if cond_fork[1].addcond_isSolvable(z3.Not(cond)): done.append(cond_fork[1]) while_states = updated_while_states return done
def add_dependency_constrains(solver, pkg_dict, order_dict, int_dict): # add constrains from package dependencies for pkg in pkg_dict: ver_dict = pkg_dict[pkg] ands = list() for ver in ver_dict: ind = order_dict[pkg][ver] deps = sorted(ver_dict[ver]) ors = list() curr_pkg = None or_expr = None for dep in deps: # convert one pkg dependencies to z3 expr # A==1 requires B==2,B==3 -> (B==2 OR B==3) dep_pkg, dep_ver = dep.split("#") dep_ind = order_dict[dep_pkg][dep_ver] if dep_pkg != curr_pkg: if or_expr is not None: ors.append(or_expr) curr_pkg = dep_pkg or_expr = Or() expr = Or(int_dict[dep_pkg] == dep_ind) or_expr = Or(or_expr, expr) or_expr = simplify(or_expr) if or_expr is not None: ors.append(or_expr) # merge all pkg dependencies OR expr for the pkg version # A==1 requires B==2,B==3,C==1 -> A==1 AND (B==2 OR B==3) AND C==1 and_expr = And(int_dict[pkg] == ind) for expr in ors: and_expr = And(and_expr, expr) and_expr = simplify(and_expr) ands.append(and_expr) # merge all versions dependencies AND expr # A==1 requires B==2,B==3,C==1; A==3 requires B==3, C==3 # -> (A==1 AND (B==2 OR B==3) AND C==1) Or (A==3 AND B==3 AND C==3) constrain = Or() for expr in ands: constrain = Or(constrain, expr) constrain = simplify(constrain) # situation that the package is unnecessary unnecessary_ind = len(order_dict[pkg].keys()) constrain = Or(constrain, int_dict[pkg] == unnecessary_ind) constrain = simplify(constrain) # print(constrain) solver.add(constrain) return solver
def get_pred(self): if self.is_ninf(): return copy.deepcopy(self) if self.is_pzero(): return Float('-0',ne=self.ne,ns=self.ns).get_pred() bv_str = self.get_bv_str() #print(bv_str) sign = bv_str[0] if sign == '0': succ = int(bv_str[1:],2) - 1 return Float(val=z3.simplify(z3.fpBVToFP(z3.Int2BV(z3.IntVal(succ),num_bits = self.ns + self.ne),z3.FPSort(self.ne,self.ns))),ne=self.ne, ns=self.ns) else: succ = int(bv_str[1:],2) + 1 return -Float(val=z3.simplify(z3.fpBVToFP(z3.Int2BV(z3.IntVal(succ),num_bits = self.ns + self.ne),z3.FPSort(self.ne,self.ns))),ne=self.ne, ns=self.ns)
def exp_(self, global_state): state = global_state.mstate # we only implement 2 ** x base, exponent = util.pop_bitvec(state), util.pop_bitvec(state) if (type(base) != BitVecNumRef) or (type(exponent) != BitVecNumRef): state.stack.append(BitVec("(" + str(simplify(base)) + ")^(" + str(simplify(exponent)) + ")", 256)) elif base.as_long() == 2: if exponent.as_long() == 0: state.stack.append(BitVecVal(1, 256)) else: state.stack.append(base << (exponent - 1)) else: state.stack.append(base) return [global_state]
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 byte_(self, global_state): mstate = global_state.mstate op0, op1 = mstate.stack.pop(), mstate.stack.pop() try: index = util.get_concrete_int(op0) offset = (31 - index) * 8 result = Concat(BitVecVal(0, 248), Extract(offset + 7, offset, op1)) except AttributeError: logging.debug("BYTE: Unsupported symbolic byte offset") result = BitVec(str(simplify(op1)) + "_" + str(simplify(op0)), 256) mstate.stack.append(simplify(result)) return [global_state]
def get_arguments_from_stack(n_args, vm, exe, max_args=12): args = [] n_stack_val = len(vm.x86_stack) if n_stack_val > max_args: n_stack_val = max_args x = max([n_args, n_stack_val]) for i in xrange(x): if vm.x86_stack: if i < n_args: val = vm.x86_stack.pop() else: val = vm.x86_stack[n_args - i - 1] arg = z3.simplify(val) if hasattr(arg, 'as_long'): ptr_ = check_pointer(arg.as_long(), exe) if ptr_: arg = ptr_ else: arg = '0x%x' % arg.as_long() else: arg = str(arg) name = process_arg_str(arg)# if name: arg = name else: if i >= n_args:break arg = '*' args.append(arg) return args
def get_z3_value(item): if (type(item) == int): return item elif (type(item) == mythril.laser.smt.bitvec.BitVec and not item.symbolic): return item.value elif (type(item) == z3.BitVecNumRef): return item.as_long() try: return z3.simplify(item).as_long() except AttributeError: return str(z3.simplify(item)) except z3.Z3Exception: return str(item)
def symbolic_run(lines, data): print('Running symbolically') data = list(data) sym_data = list(x_vars) sym_data[ip] = data[ip] conds = [] states = [] for i in range(12): pc = data[ip] if pc >= len(lines): break print(lines[pc], sym_data) simulate(lines[pc], data) try: simulate(lines[pc], sym_data) except SymbolicExecutionImpossible: break states.append((tuple(sym_data), tuple(data))) if type(sym_data[ip]) != int: conds.append( z3.simplify(sym_data[ip] == data[ip]) ) #print('cond', conds[-1]) sym_data[ip] = data[ip] r = find_shifted(conds, states) if r: patterns[pc].add(r) break if data[ip] >= len(lines): break
def get_vars(f, rs=set()): """ shameless copy of z3util.get_vars, but returning select-operations as well. E.g. >>> x = z3.Array('x', z3.IntSort(), z3.IntSort()) >>> get_vars(x[5]) [x[5]] whereas >>> x = z3.Array('x', z3.IntSort(), z3.IntSort()) >>> z3util.get_vars(x[5]) [x] """ if not rs: f = z3.simplify(f) if f.decl().kind() == z3.Z3_OP_SELECT: arr, idx = f.children() if z3.is_const(arr): if z3.z3util.is_expr_val(idx): return rs | {f} else: return rs | {f, idx} if z3.is_const(f): if z3.z3util.is_expr_val(f): return rs else: # variable return rs | {f} else: for f_ in f.children(): rs = get_vars(f_, rs) return set(rs)
def get_z3_value_hex(item): if (type(item) == int): return hex(item) elif (type(item) == mythril.laser.smt.bitvec.BitVec and not item.symbolic): return hex(item.value) elif (type(item) == z3.BitVecNumRef): return hex(item.as_long()) try: return hex(z3.simplify(item).as_long()) except AttributeError: return str(z3.simplify(item)).replace("\n", "\n ") except z3.Z3Exception: return str(item).replace("\n", "\n ")
def visit_MLIL_SET_VAR_SSA(self, expr): dest = create_BitVec(expr.dest, expr.size) src = self.visit(expr.src) # If this value can never be larger than a byte, # then it must be one of the bytes in our swap. # Add it to a list to check later. if src is not None and not isinstance(src, (int, int)): value_range = identify_byte(expr.src, self.function) if value_range is not None: self.solver.add( Or(src == 0, And(src <= value_range.end, src >= value_range.step))) self.byte_vars.add(*expr.src.vars_read) if self.byte_values.get( (value_range.end, value_range.step)) is None: self.byte_values[( value_range.end, value_range.step)] = simplify( Extract( int(math.floor(math.log(value_range.end, 2))), int(math.floor(math.log(value_range.step, 2))), src)) self.visited.add(expr.dest) if expr.instr_index in self.to_visit: self.to_visit.remove(expr.instr_index) if src is not None: self.solver.add(dest == src)
def convertToDimacs(goal, file): #f_n = open(Options.DIMACS_FILE, 'w') d = DimacsConverter() t = Tactic("tseitin-cnf") cnf = t(goal) #print cnf clauses = [] #print(cnf) for i in cnf: for j in i: variables = [] #print (j) #print j.__class__ if len(j.children()) == 0: variables.append(str(d.getVarIndex(str(j)))) for k in j.children(): #print k if is_not(k): neg="-" newk = (simplify(Not(k))) else: neg="" newk = k variables.append(neg + str(d.getVarIndex(str(newk)))) clauses.append(variables) inv_map = {v:k for k, v in d.vars.items()} #print(inv_map) f = open(file, 'r') for line in f: [var, val] = split(line) print("\"" + str(inv_map[int(var)])+"\",")
def getDimacsMap(goal): d = DimacsConverter() t = Tactic("tseitin-cnf") cnf = t(goal) #print cnf clauses = [] #print(cnf) for i in cnf: for j in i: variables = [] #print (j) #print j.__class__ if len(j.children()) == 0: variables.append(str(d.getVarIndex(str(j)))) for k in j.children(): #print k if is_not(k): neg="-" newk = (simplify(Not(k))) else: neg="" newk = k variables.append(neg + str(d.getVarIndex(str(newk)))) clauses.append(variables) inv_map = {v:k for k, v in d.vars.items()} return inv_map
def simplify(self, expr): if expr._simplified: return expr if self._enable_simplification_cache: try: k = self._simplification_cache_key[expr._cache_key] #print "HIT WEAK KEY CACHE" return k except KeyError: pass try: k = self._simplification_cache_val[expr._cache_key] #print "HIT WEAK VALUE CACHE" return k except KeyError: pass #print "MISS CACHE" l.debug("SIMPLIFYING EXPRESSION") #print "SIMPLIFYING" expr_raw = self.convert(expr) #l.debug("... before: %s (%s)", expr_raw, expr_raw.__class__.__name__) if isinstance(expr_raw, z3.BoolRef): tactics = z3.Then(z3.Tactic("simplify"), z3.Tactic("propagate-ineqs"), z3.Tactic("propagate-values"), z3.Tactic("unit-subsume-simplify")) s = tactics(expr_raw).as_expr() n = s.decl().name() if n == 'true': s = True elif n == 'false': s = False elif isinstance(expr_raw, z3.BitVecRef): s = z3.simplify(expr_raw) else: s = expr_raw for b in _eager_backends: try: o = self.wrap(b.convert(s)) break except BackendError: continue else: o = self._abstract(s) #print "SIMPLIFIED" #l.debug("... after: %s (%s)", s, s.__class__.__name__) o._simplified = Base.FULL_SIMPLIFY if self._enable_simplification_cache: self._simplification_cache_val[expr._cache_key] = o self._simplification_cache_key[expr._cache_key] = o return o
def find_if_else_for_node(self, header: MediumLevelILBasicBlock, nodes: list): nodes_to_check = list(nodes) nodes_to_remove = [] while nodes_to_check: ni = nodes_to_check.pop() if not isinstance(ni, MediumLevelILAstCondNode): continue for nj in nodes_to_check: if not isinstance(nj, MediumLevelILAstCondNode): continue if ni.start == nj.start: continue cni = ni.condition cnj = nj.condition if is_true(simplify(cni == Not(cnj))): if cni.decl().name() == 'not': self._make_if_else(nj, ni) nodes_to_check.remove(nj) nodes_to_remove.append(ni) else: self._make_if_else(ni, nj) nodes_to_check.remove(nj) nodes_to_remove.append(nj) break return nodes_to_remove
def bitblast (e): ctx = e.ctx goal = z3.Goal (ctx=ctx) goal.add (z3.simplify (e)) tactic = z3.Tactic ('bit-blast', ctx=ctx) res = tactic.apply (goal, blast_full=True) assert (len (res) == 1) return res [0].as_expr ()
def z3_flatten_exp (z3exp) : return z3.simplify (z3exp, flat=True, # don't care about other options, # which are true by default... algebraic_number_evaluator=False, bit2bool=False, elim_sign_ext=False, hi_div0=False, mul_to_power=False, push_to_real=False)
def PEPPolicy(PEP, model): disjunctions = [] for or_id in range(NUM_ORS): conjunctions = [] for enum_id in range(NUM_ENUMS): enumVar = TEMPLATE_ENUM_VARS[PEP][or_id][enum_id] if model[enumVar] is not None: synthVal = model[enumVar].as_long() else: synthVal = -1 if synthVal >= 0 and synthVal < len(ENUM_INDEX.keys()): if not isinstance(ENUM_INDEX[synthVal], list): boolVar = ENUM_INDEX[synthVal] conjunctions.append(boolVar) else: [enumVar, val] = ENUM_INDEX[synthVal] conjunctions.append(enumVar == val) elif synthVal >= len(ENUM_INDEX.keys()) and synthVal < 2 * len(ENUM_INDEX.keys()): if not isinstance(ENUM_INDEX[synthVal - len(ENUM_INDEX.keys())], list): boolVar = ENUM_INDEX[synthVal - len(ENUM_INDEX.keys())] conjunctions.append(Not(boolVar)) else: [enumVar, val] = ENUM_INDEX[synthVal - len(ENUM_INDEX.keys())] conjunctions.append(enumVar != val) elif synthVal == 2 * len(ENUM_INDEX.keys()): conjunctions.append(True) else: conjunctions.append(False) for num_id in range(NUM_NUMERIC): minVar = TEMPLATE_NUMERIC_VARS[PEP][or_id][num_id]['min'] maxVar = TEMPLATE_NUMERIC_VARS[PEP][or_id][num_id]['max'] if model[minVar] is not None and model[maxVar] is not None: crosscheck = Solver() crosscheck.add(model[minVar] <= model[maxVar]) if crosscheck.check() == sat: conjunctions.append(NUM_VAR >= model[minVar].as_long()) conjunctions.append(NUM_VAR <= model[maxVar].as_long()) elif model[minVar] is not None: conjunctions.append(NUM_VAR >= model[minVar].as_long()) elif model[maxVar] is not None: conjunctions.append(NUM_VAR <= model[maxVar].as_long()) disjunctions.append(simplify(And(conjunctions))) return simplify(Or(disjunctions))
def simplify(self, expr): if expr._simplified: return expr if self._enable_simplification_cache: try: k = self._simplification_cache_key[expr._cache_key] #print "HIT WEAK KEY CACHE" return k except KeyError: pass try: k = self._simplification_cache_val[expr._cache_key] #print "HIT WEAK VALUE CACHE" return k except KeyError: pass #print "MISS CACHE" l.debug("SIMPLIFYING EXPRESSION") #print "SIMPLIFYING" expr_raw = self.convert(expr) #l.debug("... before: %s (%s)", expr_raw, expr_raw.__class__.__name__) #s = expr_raw if isinstance(expr_raw, z3.BoolRef): tactics = z3.Then( z3.Tactic("simplify", ctx=self._context), z3.Tactic("propagate-ineqs", ctx=self._context), z3.Tactic("propagate-values", ctx=self._context), z3.Tactic("unit-subsume-simplify", ctx=self._context), ctx=self._context ) s = tactics(expr_raw).as_expr() #n = s.decl().name() #if n == 'true': # s = True #elif n == 'false': # s = False elif isinstance(expr_raw, z3.BitVecRef): s = z3.simplify(expr_raw) else: s = expr_raw o = self._abstract(s) o._simplified = Base.FULL_SIMPLIFY if self._enable_simplification_cache: self._simplification_cache_val[expr._cache_key] = o self._simplification_cache_key[expr._cache_key] = o return o
def interpret(self, i, j): """ Convert logical indices i and j into a physical index. """ Bx = i / self.lsize0() By = j / self.lsize1() p = self.fragment(Bx, By) if not self.terminal(): x = i % self.lsize0() y = j % self.lsize1() p *= self.elem_size() p += self.rest.interpret(x, y) return z3.simplify(p)
def solve_for(inps): r1, r2, r3, r4, v11 = [BVV(x, 64) for x in map(int, inps.split(', '))] print r1, r2, r3, r4, v11 for choice1, choice2, choice3 in all_choices(): v6 = choose_op(r1, r2, choice1) v6_1 = choose_op(v6, r3, choice2) v6_2 = choose_op(v6_1, r4, choice3) if simplify(weird_op(v6_2)) == v11: return choice1, choice2, choice3
def _pattern(self, pattern, L): # we can exit early if we have a variable if self._is_var(pattern): return True constraints = [True] f, *args = breakout(pattern) # now we'll recurse appropriately for i, arg in enumerate(args): constraints.append( self._connect(f, i, arg, L) ) constraints.append( self._pattern(arg, L)) return simplify(And(constraints))
def getValue(self, op): assert(self.m <> None) 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) 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)
def prove(self, hypotheses, conclusion=None, report=None): report = self.reportFun(report) if (conclusion is None): conclusion = hypotheses hypotheses = True x_hyps, x_concl = self.analyse_expt(z3.And(hypotheses,z3.Not(conclusion)), conclusion, report) f_hyps, f_concl = self.fun_to_var([x_hyps, x_concl], report)[:] if(f_hyps is None): hyps = f_hyps else: hyps = z3.simplify(f_hyps) if(f_concl is None): concl = f_concl else: concl = z3.simplify(f_concl) report('to_smt_w_expt.prove:') report(' hypotheses = ', hyps) report(' conclusion = ', concl) return super(to_smt_w_expt, self).prove(hyps, concl)
def simplify(self, expr): #pylint:disable=arguments-differ if expr._simplified: return expr if self._enable_simplification_cache: try: k = self._simplification_cache_key[expr._cache_key] #print "HIT WEAK KEY CACHE" return k except KeyError: pass try: k = self._simplification_cache_val[expr._cache_key] #print "HIT WEAK VALUE CACHE" return k except KeyError: pass #print "MISS CACHE" l.debug("SIMPLIFYING EXPRESSION") #print "SIMPLIFYING" expr_raw = self.convert(expr) #l.debug("... before: %s (%s)", expr_raw, expr_raw.__class__.__name__) #s = expr_raw if isinstance(expr_raw, z3.BoolRef): boolref_tactics = self._boolref_tactics s = boolref_tactics(expr_raw).as_expr() #n = s.decl().name() #if n == 'true': # s = True #elif n == 'false': # s = False elif isinstance(expr_raw, z3.BitVecRef): s = z3.simplify(expr_raw) else: s = expr_raw o = self._abstract(s) o._simplified = Base.FULL_SIMPLIFY if self._enable_simplification_cache: self._simplification_cache_val[expr._cache_key] = o self._simplification_cache_key[expr._cache_key] = o return o
def constraints_for_call(self, call): situations = [] rule = self.rule_for_call(call) for priority, z3_meaning in rule.meaning_of(self.history, call): situational_exprs = [z3_meaning] for unmade_call, unmade_rule in self._call_to_rule.iteritems(): for unmade_priority, unmade_z3_meaning in unmade_rule.meaning_of(self.history, unmade_call): if self.system.priority_ordering.lt(priority, unmade_priority): if self.explain and self.expected_call == call: print "Adding negation %s (%s) to %s:" % (unmade_rule.name, unmade_call.name, rule.name) print " %s" % z3.simplify(z3.Not(unmade_z3_meaning)) situational_exprs.append(z3.Not(unmade_z3_meaning)) situations.append(z3.And(situational_exprs)) return z3.Or(situations)
def _constrain_eq_vars(self, E, L): constraints = [] for l, r in combinations(L, 2): if l.type == "return" and r.type == "return": lcomp, rcomp = self.components[l.component], self.components[r.component] if lcomp.sexpr != rcomp.sexpr: constraints.append( E[(l, r)] == False ) else: local = [True] for i in range(len(lcomp.parameters)): li, ri = get_ith_input(l.component, i, L), get_ith_input(r.component, i, L) local.append( E[(li, ri)] ) constraints.append( E[(l, r)] == And(local) ) elif l.type == "parameter" and r.type == "parameter": # type is parameter local = [(l.value == r.value)] for f, g in permutations([get_output(c, L) for c, _ in self.components.items()], 2): local.append( And([l.value == f.value, r.value == g.value, E[(f, g)]]) ) constraints.append( E[(l, r)] == Or(local) ) return simplify(And(constraints))
def test19 () : x = z3.Int ('x') y = z3.Int ('y') z = z3.Int ('z') s = z3.Solver () cons = z3.Or ([]) print 'cons', cons print 'simplify', z3.simplify (cons) s.add (cons) s.add (z3.Or (x == y, x == z)) print 'constraints to solve:', s c = s.check () print 'result:', c if c == z3.sat : m = s.model () print 'model:', m
def _is_true(self, e, extra_constraints=(), result=None, solver=None): return z3.simplify(e).eq(z3.BoolVal(True, ctx=self._context))
def add(self, cs): for c in cs: c = z3.simplify(c) #print c self.solver.add(c)
def test1(): print "=== Loading Core ===" solver = Solver() solver.push() solver.add(language.axioms) print "=== Starting tests ===" print ">> Let p q r s t u v be distinct points" p, q, r, s, t, u, v = Consts('p q r s t u v', language.PointSort) solver.add(simplify(Distinct(p,q,r,s,t,u,v), blast_distinct=True)) print ">> Let L M N O be distinct lines" K, L, M, N, O = Consts('K L M N O', language.LineSort) solver.add(simplify(Distinct(K,L,M,N,O), blast_distinct=True)) ## Diagram description assumptions = [] assumptions.append(language.OnLine(p,L)) assumptions.append(language.OnLine(q,L)) assumptions.append(language.OnLine(p,N)) assumptions.append(language.OnLine(s,N)) assumptions.append(language.OnLine(t,N)) assumptions.append(language.OnLine(p,M)) assumptions.append(language.OnLine(r,M)) assumptions.append(language.OnLine(q,O)) assumptions.append(language.OnLine(s,O)) assumptions.append(language.OnLine(r,O)) assumptions.append(language.OnLine(q,K)) assumptions.append(language.OnLine(t,K)) assumptions.append(Not(language.OnLine(r,L))) assumptions.append(language.Between(p,s,t)) assumptions.append(language.Between(q,s,r)) assumptions.append(language.Between(s,u,t)) assumptions.append(Not(p == q)) assumptions.append(language.Between(p,q,v)) print ">> Assume " + str(assumptions) solver.add(assumptions) print " << z3: " + str(solver.check()) ## Satisfied solver.push() solver.add(True) print ">> Hence True" print " << z3: " + str(solver.check()) solver.pop() ## Satisfied solver.push() solver.add(Not(language.SameSide(s,t,O))) print ">> Hence s and t are on opposite sides of O" print " << z3: " + str(solver.check()) solver.pop() ## Satisfied solver.push() solver.add(language.SameSide(u,t,M)) print ">> Hence u and t are on same side of M" print " << z3: " + str(solver.check()) solver.pop() ## unsatisfied solver.push() solver.add(language.SameSide(p,t,O)) print ">> Hence p and t are on same side of O" print " << z3: " + str(solver.check()) solver.pop() ## unsatisfied solver.push() solver.add(language.SameSide(s,t,O)) print ">> Hence s and t are on same side of O" print " << z3: " + str(solver.check()) solver.pop() ## unsatisfied solver.push() solver.add(Not(language.SameSide(s,t,M))) print ">> Hence s and t are on opposite sides of M" print " << z3: " + str(solver.check()) solver.pop() ## unsatisfied solver.push() solver.add(Not(language.SameSide(u,t,M))) print ">> Hence u and t are on opposite sides of M" print " << z3: " + str(solver.check()) solver.pop() ## unsatisfied solver.push() solver.add(language.Between(s,p,t)) print ">> Hence p is between s and t" print " << z3: " + str(solver.check()) solver.pop() ## unsatisfied solver.push() solver.add(M == N) print ">> Hence p is between s and t" print " << z3: " + str(solver.check()) solver.pop() ## unsatisfied solver.push() solver.add(language.Between(q,s,u)) print ">> Hence s is between q and u" print " << z3: " + str(solver.check()) solver.pop() ## unsatisfied solver.push() solver.add(Not( language.Segment(s,u) < language.Segment(s,t))) print ">> Hence seg su is less than seg st" print " << z3: " + str(solver.check()) solver.pop() ## unsatisfied solver.push() solver.add(L==K) print ">> Hence L = K" print " << z3: " + str(solver.check()) solver.pop()
def _is_true(self, e, extra_constraints=(), solver=None, model_callback=None): return z3.simplify(e).eq(z3.BoolVal(True, ctx=self._context))
def _simplify(self): if self._formula in [True, False]: return self._formula = z3.simplify(self._formula)
def handle(self, cur_addr): symb_pc = self.eval_expr(self.ir_arch.IRDst) possibilities = possible_values(symb_pc) if len(possibilities) == 1: assert next(iter(possibilities)).value == cur_addr else: cur_path_constraint = set() # path_constraint for the concrete path for possibility in possibilities: path_constraint = set() # Set of ExprAff for the possible path # Get constraint associated to the possible path memory_to_add = ModularIntervals(symb_pc.size) for cons in possibility.constraints: eaff = cons.to_constraint() # eaff.get_r(mem_read=True) is not enough # ExprAff consider a Memory access in dst as a write mem = eaff.dst.get_r(mem_read=True) mem.update(eaff.src.get_r(mem_read=True)) for expr in mem: if expr.is_mem(): addr_range = expr_range(expr.arg) # At upper bounds, add the size of the memory access # if addr (- [a, b], then @size[addr] reachables # values are in @8[a, b + size[ for start, stop in addr_range: stop += (expr.size / 8) - 1 full_range = ModularIntervals(symb_pc.size, [(start, stop)]) memory_to_add.update(full_range) path_constraint.add(eaff) if memory_to_add.length > self.MAX_MEMORY_INJECT: # TODO re-croncretize the constraint or z3-try raise RuntimeError("Not implemented: too long memory area") # Inject memory for start, stop in memory_to_add: for address in xrange(start, stop + 1): expr_mem = ExprMem(ExprInt(address, self.ir_arch.pc.size), 8) value = self.eval_expr(expr_mem) if not value.is_int(): raise TypeError("Rely on a symbolic memory case, " \ "address 0x%x" % address) path_constraint.add(ExprAff(expr_mem, value)) if possibility.value == cur_addr: # Add path constraint cur_path_constraint = path_constraint elif self.produce_solution: # Looking for a new solution self.cur_solver.push() for cons in path_constraint: trans = self.z3_trans.from_expr(cons) trans = z3.simplify(trans) self.cur_solver.add(trans) result = self.cur_solver.check() if result == z3.sat: model = self.cur_solver.model() self.handle_solution(model, possibility.value) self.cur_solver.pop() # Update current solver for cons in cur_path_constraint: self.cur_solver.add(self.z3_trans.from_expr(cons))
def _is_true(self, e): return z3.simplify(e).eq(z3.BoolVal(True))
def _is_false(self, e): return z3.simplify(e).eq(z3.BoolVal(False))
def sat_expr(self): expr = self._sat_expr(self.x, self.regex, 0, self.length) return z3.simplify(expr)
def smt_solution(self, timeout, neg_points=None): neg_points = neg_points or [] solver = z3.Solver() solver.set("timeout", timeout) b = self.offset z3_b = z3.Int("b") if b > 0: solver.add(z3_b >= 0) solver.add(z3_b <= b) elif b < 0: solver.add(z3_b <= 0) solver.add(z3_b >= b) else: solver.add(z3_b == 0) pos_x = True simple = sum(abs(x) for x in self.normal) < 1 non_trivial = False if not simple: some_consume = False some_produce = False diff_sol = z3_b != b h1 = b h2 = z3_b variables = [] for t_id, val in enumerate(self.normal): if not val: continue z3_val = z3.Int("a" + str(t_id)) x = z3.Int("x" + str(t_id)) variables.append(x) pos_x = z3.And(pos_x, x >= 0) if val > 0: solver.add(0 <= z3_val) solver.add(z3_val <= val) elif val < 0: solver.add(z3_val <= 0) solver.add(val <= z3_val) if not simple: some_consume = z3.Or(some_consume, z3_val < 0) some_produce = z3.Or(some_produce, z3_val > 0) non_trivial = z3.Or(non_trivial, z3_val != 0) diff_sol = z3.Or(diff_sol, z3_val != val) h1 = h1 + val * x h2 = h2 + z3_val * x if not simple: solver.add(z3.simplify(some_consume)) solver.add(z3.simplify(some_produce)) solver.add(z3.simplify(non_trivial)) solver.add(z3.simplify(diff_sol)) solver.add(z3.simplify(z3.ForAll(variables, z3.Implies(z3.And(pos_x, h1 <= 0), h2 <= 0)))) ## non negative point should be a solution for np in list(neg_points)[:min(100,len(neg_points))]: smt_np = False ineq_np = self.offset for t_id, val in enumerate(self.normal): z3_var = z3.Int("a" + str(t_id)) ineq_np = ineq_np + z3_var * np[t_id] smt_np = z3.simplify(z3.Or(smt_np, ineq_np < 0)) solver.add(smt_np) #import pdb;pdb.set_trace() sol = solver.check() if sol == z3.unsat or sol == z3.unknown: ret = False del(solver) del(sol) else: ret = solver.model() return ret
def simplify(self, expr, **kwargs): if(z3.is_expr(expr)): return z3.simplify(expr, **kwargs) else: # assume that expr has already been 'simplified' to a constant. return expr