def __init__(self, graph, model, solver): nodes = [] agent_names = solver.nodes.keys() has = solver.Graph.has(graph) links = solver.Graph.links(graph) parents = solver.Graph.parents(graph) labelmap = solver.Graph.labelmap(graph) for agent_name in agent_names: z3_node = solver.nodes[agent_name] has_some_node = model.evaluate(z3.Select(has, z3_node)) if has_some_node: labels = model.evaluate(z3.Select(labelmap, z3_node)) labels = solver._labelset_to_set_of_labels(labels, model) nodes.append(NodeResult(z3_node, agent_name, labels)) for node_1 in nodes: for node_2 in nodes: if node_1 != node_2: edge = solver.Edge.edge(node_1.z3_node, node_2.z3_node) edge_in_parents = model.evaluate(z3.Select(parents, edge)) edge_in_links = model.evaluate(z3.Select(links, edge)) if str(edge_in_parents) == 'True': node_1.add_site(node_2) if str(edge_in_links) == 'True': node_1.add_link(node_2) self.nodes = nodes
def make_array(creator: SymbolicFactory) -> object: space = creator.space code, minval, maxval = pick_code(space) nums = SymbolicArrayBasedUniformTuple(creator.varname, Tuple[int, ...]) z3_array = nums._arr() qvar = z3.Int("arrvar" + space.uniq()) space.add(z3.ForAll([qvar], minval <= z3.Select(z3_array, qvar))) space.add(z3.ForAll([qvar], z3.Select(z3_array, qvar) < maxval)) return SymbolicArray(code, nums)
def get_select(select_node, z3_vars): # returns array, index and isnumber array = select_node.children[0].children[0].value if (select_node.children[1].data == "num"): index = select_node.children[1].children[0].value return z3.Select(z3_vars[array][0], index) else: index = select_node.children[1].children[0].value return z3.Select(z3_vars[array][0], z3_vars[index][0])
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 _assert(self, submodel, interpretation): node = interpretation(self.x) action = submodel.action atomic_action = AtomicAction.rem_action(node) has_rem_action = z3.Select(action, atomic_action) graph = submodel.pregraph_has_node has_function = Graph.has(graph) pregraph_has_node = z3.Select(has_function, node) return z3.And(has_rem_action, pregraph_has_node)
def _assert(self, graph, solver): """Return a z3 predicate asserting this structure is in `graph`.""" labelmap = solver.Graph.labelmap(graph) node = solver.nodes[self.structure.central_node_label()] labelset = z3.Select(labelmap, node) # returns a labelset label = solver.string_interner.get_int_or_add(self.label) label_present = z3.Select(labelset, label) # returns a bool retval = z3.And(label_present, self.structure._assert(graph, solver)) if self.anti: return z3.Not(retval) else: return retval
def _assert(self, submodel, interpretation): if pre: labelmap = Graph.labelmap(submodel.pregraph) else: labelmap = Graph.labelmap(submodel.postgraph) node = interpretation(self.var) labelset = z3.Select(labelmap, node) label = self.label_as_int has_label = z3.Select(labelset, label) if un: return z3.Not(has_label) else: return has_label
def getTypedZ3ValFromIdentifier(identifier, types): if type(identifier) == dict: # FIXME how can we handle this here raise NotSupportedException('Complex objects as base for operations cannot be modelled in z3') if type(identifier) == list: arr = z3.Array('ignore_helper_constant_array_' + randomString(), z3.IntSort(), z3.StringSort()) for i, arg in enumerate(identifier): GLOBAL_CONSTRAINTS.append(z3.Select(arr, i) == createZ3ExpressionFromConstraint(arg, types)) ARRAY_LENGTHS[str(arr.decl())] = len(identifier) return arr cur_types = types GLOBAL_IDENTIFIER.add(identifier) cur_types = infered_types[identifier] # if cur_types == 'object': # infered_types[identifier] = '' # cur_types = '' if identifier.endswith('.length'): return z3.Length(z3.String(identifier[:-7])) if cur_types == 'string': return z3.String(identifier) elif cur_types == 'number': return z3.Int(identifier) elif cur_types == 'boolean': return z3.Bool(identifier) elif cur_types == 'array': return z3.Array(identifier, z3.IntSort(), z3.StringSort()) if 'event.data' in identifier or 'event.origin' in identifier or 'event' == identifier: return z3.String(identifier) else: MAKE_UNSOLVABLE.add(identifier) return z3.String(identifier)
def __getitem__(self, item: BitVec) -> BitVec: """Gets item from the array, item can be symbolic.""" if isinstance(item, slice): raise ValueError( "Instance of BaseArray, does not support getitem with slices") return BitVec(cast(z3.BitVecRef, z3.Select(self.raw, item.raw))) # type: ignore
def Select(self, index: BV) -> BV: if isinstance(index, int): index = BVV(index, self.index_width) else: assert index.size == self.index_width if ( isinstance(index, BVV) and self._conc_store is not None and index.value in self._conc_store ): # concrete mode return self._conc_store[index.value] # symbolic mode # no need to switch to symbolic mode! (is this right?) res = BVExpr(self.value_width, z3.Select( self.z3obj, index.z3obj ) ) if ( isinstance(index, BVV) and self._conc_store is not None ): # uninitialized read self._conc_store[index.value] = res return res
def string_indexOf(x, args): if z3.is_array(x): if str(x.decl()) not in ARRAY_LENGTHS: raise Exception('We do not know how large the underlying array should be thus we cannot include on it') helper_int = z3.Int('__ignore_arr_indexOf_helper_' + randomString()) search_string = createZ3ExpressionFromConstraint(args[0], {}) all = [] presentImplications = [] for i in range(ARRAY_LENGTHS[str(x.decl())]): conditional = z3.Select(x, i) == search_string all.append(conditional) true_imply = z3.Implies(conditional, helper_int <= i) false_imply = z3.Implies(z3.Not(conditional), helper_int > i) presentImplications.append(true_imply) presentImplications.append(false_imply) all = z3.Or(all) GLOBAL_CONSTRAINTS.append(z3.And(z3.Implies(all, z3.And(presentImplications)), z3.Implies(all, helper_int >= 0), z3.Implies(z3.mk_not(all), helper_int == -1))) return helper_int else: if len(args) > 1: return z3.IndexOf(x, createZ3ExpressionFromConstraint(args[0], {}), createZ3ExpressionFromConstraint(args[1], {})) else: return z3.IndexOf(x, createZ3ExpressionFromConstraint(args[0], {}), 0)
def select(self, conv, idx): if self.sort.id == esbmc.solve.smt_sort_kind.array: idx = conv.convert_ast(idx) ast = z3.Select(self.ast, idx.ast) result = Z3ast(ast, self.conv, self.sort.range_sort) else: assert False # XXX is only arrays anyway? self.conv.store_ast(result) return result
def get_memory_data(memory, index, length): assert type(index) == int and type( length) == int, 'Wrong types for get_memory_data' value_bytes = [] for i in range(length): value_bytes.append(z3.Select(memory, index + i)) value = z3.Concat(value_bytes) assert value.size() == (length * 8) return value
def overlay(self, chunk, base_off, chunk_off, length): slen = z3.simplify(length) if z3.is_bv_value(slen): for i in range(slen.as_long()): if isinstance(chunk, Memory): sel = chunk.select(chunk_off + i) else: sel = z3.Select(chunk, chunk_off + i) self._mem = z3.Store(self._mem, base_off + i, sel) else: if self._idx is None: self._idx = z3.BitVec('idx', 256) if isinstance(chunk, Memory): chunk_val = chunk.select(self._idx - base_off + chunk_off) else: chunk_val = z3.Select(chunk, self._idx - base_off + chunk_off) self._mem = z3.If( z3.And(self._idx >= base_off, self._idx < base_off + length), z3.Store(state.MemoryEmpty, self._idx, chunk_val), self._mem)
def _labelset_to_set_of_labels(self, labelset, model): """ Given a z3 labelset from a model, extract a set of labels. """ output = [] for i in range(1, self.string_interner.counter): if str(model.evaluate(z3.Select(labelset, i))) == 'True': # bleh thing = self.string_interner.get_str(i) if "label_" in thing: output.append(thing[6:]) return output
def RETURN(self, gstate, offset, length): if not svm_utils.is_bv_concrete(length): # raise SVMRuntimeError('Non concrete return length') length = 32 length = svm_utils.get_concrete_int(length) return_data_bytes = [z3.Select(gstate.mstate.memory, i+offset) for i in range(length)] return_data = z3.Concat(return_data_bytes) assert return_data.size() == length*8 gstate.return_data = return_data gstate.exit_code = 1 gstate.halt = True return [gstate]
def _assert(self, submodel, interpretation): if pre: graph = submodel.pregraph_has_node else: graph = submodel.postgraph edge = Edge.edge(interpretation(self.x), interpretation(self.y)) if parent: function = Graph.parents(graph) else: function = Graph.links(graph) has_edge = z3.Select(function, edge) return has_edge
def string_split(x, args): st = x split_val = z3.StringVal(args[0].encode()) x = transformNonBooleanLazyEvaluations(x) arr = z3.Array('__ignore_{}.split({})'.format(str(x), str(args[0])), z3.IntSort(), z3.StringSort()) for i in range(3): index = z3.IndexOf(st, split_val, 0) s = z3.SubString(st, 0, index) st = z3.SubString(st, index + z3.Length(split_val), z3.Length(st)) GLOBAL_CONSTRAINTS.append(z3.Select(arr, i) == s) GLOBAL_CONSTRAINTS.append(s != z3.StringVal('')) GLOBAL_ARRAY_HANDLER[arr].append(s) GLOBAL_CONSTRAINTS.append(z3.Select(arr, 3) == st) GLOBAL_CONSTRAINTS.append(st != z3.StringVal('')) GLOBAL_ARRAY_HANDLER[arr].append(st) # We just guess the length here and hope that this works for the program ARRAY_LENGTHS[str(arr.decl())] = 4 GLOBAL_CONSTRAINTS.append(z3.IndexOf(GLOBAL_ARRAY_HANDLER[arr][-1], split_val, 0) == -1) # GLOBAL_CONSTRAINTS.append(z3.PrefixOf(GLOBAL_ARRAY_HANDLER[arr][0], x)) return arr
def _assert(self, graph, solver): """Return a z3 predicate asserting this structure is in `graph`.""" links = solver.Graph.links(graph) node_1 = solver.nodes[self.structure_1.central_node_label()] node_2 = solver.nodes[self.structure_2.central_node_label()] edge = solver.Edge.edge(node_1, node_2) has_link = z3.Select(links, edge) retval = z3.And(has_link, self.structure_1._assert(graph, solver), self.structure_2._assert(graph, solver)) if self.anti: return z3.Not(retval) else: return retval
def _assert(self, graph, solver): """Return a z3 predicate asserting this structure is in `graph`.""" parents = solver.Graph.parents(graph) node_1 = solver.nodes[self.structure_1.central_node_label()] node_2 = solver.nodes[self.structure_2.central_node_label()] if self.parent_to_site: edge = solver.Edge.edge(node_1, node_2) else: edge = solver.Edge.edge(node_2, node_1) has_parent = z3.Select(parents, edge) retval = z3.And(has_parent, self.structure_1._assert(graph, solver), self.structure_2._assert(graph, solver)) if self.anti: return z3.Not(retval) else: return retval
def includes(x, args): if z3.is_string(x): return string_indexOf(x, args) > -1 elif z3.is_array(x): if str(x.decl()) not in ARRAY_LENGTHS: raise Exception('We do not know how large the underlying array should be thus we cannot include on it') cc = None searched = createZ3ExpressionFromConstraint(args[0], {}) for i in range(ARRAY_LENGTHS[str(x.decl())]): c = z3.Select(x, i) == searched if cc is None: cc = c else: cc = z3.Or(cc, c) return cc else: raise Exception('What else should we expect to be called includes on instead of strings and arrays')
def getZ3ValFromJSVal(val): if type(val) == str: return z3.StringVal(val) if type(val) == bool: return z3.BoolVal(val) if type(val) == int: return z3.IntVal(val) if type(val) == int: return z3.IntVal(val) if type(val) == list: arr = z3.Array('ignore_helper_constant_array_' + randomString(), z3.IntSort(), z3.StringSort()) for i, arg in enumerate(val): GLOBAL_CONSTRAINTS.append(z3.Select(arr, i) == createZ3ExpressionFromConstraint(arg, {})) ARRAY_LENGTHS[str(arr.decl())] = len(val) return arr if type(val) == dict: raise NotSupportedException('Complex Objects as base for operations with proxy strings are not yet supported!') raise Exception('Could not transform Js val to Z3 Val' + repr(val))
def run_test(args, name, test): print(name) global_state = load_state.get_state(test['pre']) addr = int(test['exec']['address'], 0) code, tstate = get_transaction_info(test) ts = symevm.state.TransactionState('base', addr, global_state, **tstate) root = symevm.cfg.get_cfg(code, ts, print_trace=args.trace, verbose_coverage=False) if args.cfg: symevm.cfg.to_dot(code, root) leaves = [] get_cfg_leaves(leaves, root) assert len(leaves) == 1, leaves #print(leaves[0].storage) #print(leaves[0].global_state) failed = False if 'post' in test: for addr, info in test['post'].items(): addr = int(addr, 0) if 'storage' in info: for k, v in info['storage'].items(): k = int(k, 0) v = int(v, 0) calculated = z3.simplify( z3.Select(leaves[0].storage, z3.BitVecVal(k, 256))) if v != calculated.as_long(): failed = True print( 'FAIL: expected storage[{}][{}] == {}. Actual value: {}' .format(addr, k, v, calculated)) else: # TODO think should check there was an abort maybe? pass return not failed
def Select(self, index: BV) -> BV: if isinstance(index, int): index = BVV(index, self.index_width) else: assert index.size == self.index_width if (isinstance(index, BVV) and self._mode in { BVArrayState.CONCRETE_MODE, BVArrayState.SEMI_CONCRETE_MODE } and index.value in self._conc_store): # concrete mode return self._conc_store[index.value] if (isinstance(index, BVV) and self._mode in { BVArrayState.CONCRETE_MODE, BVArrayState.SEMI_CONCRETE_MODE } and index.value not in self._conc_store): res = BVS("uninit_read_%s_%d" % (self.name, self.uninit_id), self.value_width) self.uninit_id += 1 return res # symbolic mode self._switch_to_symbolic(soft=True) return BVExpr(self.value_width, z3.Select(self._z3obj, index.z3obj))
def _switch_to_symbolic(self, soft=False): if self._mode == BVArrayState.SEMI_CONCRETE_MODE and soft: return if self._mode == BVArrayState.SEMI_CONCRETE_MODE and not soft: self._mode = BVArrayState.SYMBOLIC_MODE self._conc_store = None return if self._mode == BVArrayState.CONCRETE_MODE: assert self._z3obj is None self._z3obj = z3.Array(self.name, z3.BitVecSort(self.index_width), z3.BitVecSort(self.value_width)) # The solver needs to add those constraints! (even lazly) for index in self._conc_store: self._assertions[index] = \ BoolExpr(z3.Select( self._z3obj, index) == self._conc_store[index].z3obj) if soft: self._mode = BVArrayState.SEMI_CONCRETE_MODE else: self._mode = BVArrayState.SYMBOLIC_MODE self._conc_store = None
def VertexOperationToSmt(self): assert (self.type != VertexNode.VertexType.NONE) if self.type == VertexNode.VertexType.VAR: # Possible Vertex : input Variable, name = operand1 # input variable: there is nothing to do. # assigned Variable: name = operands[0] # It's an input variable if there is no operand : if self.operands == None: return None # otherwise, it's an assigned variable, but make sure just in case assert (self.operator == VertexNode.OpCode.ASSIGN) return self.VertexNameToSmt() == self.operands[0].VertexNameToSmt() elif self.type == VertexNode.VertexType.TEMP: # Possible Vertex : Function Call, Array Load, Binary Operation, Comparison, # Conditional Assignment, Unary Operation # function call: name = func_name(arguments) # array load: name = array[index] # binary operation: name = operand1 op operand2 # comparison: name = operand1 comp operand2 # conditional assignment: name = ite(operand1, operand2, operand3) # unary operation: name = op operand1 # It's a function call if self.operator == VertexNode.OpCode.FUNCCALL: assert (self.operands[0].type == VertexNode.VertexType.FUNC) # There are four possible functions that can last until now: if self.operands[0].name == "merge": args = [] for op in self.operands[1:]: args.append(op.VertexNameToSmt()) return self.VertexNameToSmt() == z3.Concat(args) elif self.operands[0].name == "split": toSplit = self.operands[1].VertexNameToSmt() # Extract requires actual numerical value. lowerBound = self.operands[2].value upperBound = self.operands[3].value return self.VertexNameToSmt() == z3.Extract( upperBound, lowerBound, toSplit) elif self.operands[0].name == "zeroext": toExtend = self.operands[1].VertexNameToSmt() # ZeroExt requires actual numerical value n = self.operands[2].value return self.VertexNameToSmt() == z3.ZeroExt(n, toExtend) elif self.operands[0].name == "concat": args = [] for op in self.operands[1:]: args.append(op.VertexNameToSmt()) return self.VertexNameToSmt() == z3.Concat(args) # It's an array load elif self.operator == VertexNode.OpCode.LOAD: array = self.operands[0].VertexNameToSmt() arrayIndex = self.operands[1].VertexNameToSmt() return self.VertexNameToSmt() == z3.Select(array, arrayIndex) # It's a conditional statement elif self.operator == VertexNode.OpCode.CONDITIONAL: cond = self.operands[0].VertexNameToSmt() truePath = self.operands[1].VertexNameToSmt() falsePath = self.operands[2].VertexNameToSmt() return self.VertexNameToSmt() == z3.If(cond, truePath, falsePath) # It's a comparison (x < y) elif VertexNode.OpCode.IsComparison(self.operator): lhs = self.operands[0].VertexNameToSmt() rhs = self.operands[1].VertexNameToSmt() if self.operator == VertexNode.OpCode.GT: return self.VertexNameToSmt() == z3.UGT(lhs, rhs) elif self.operator == VertexNode.OpCode.GE: return self.VertexNameToSmt() == z3.UGE(lhs, rhs) elif self.operator == VertexNode.OpCode.LT: return self.VertexNameToSmt() == z3.ULT(lhs, rhs) elif self.operator == VertexNode.OpCode.LE: return self.VertexNameToSmt() == z3.ULE(lhs, rhs) elif self.operator == VertexNode.OpCode.EQ: return self.VertexNameToSmt() == (lhs == rhs) elif self.operator == VertexNode.OpCode.NE: return self.VertexNameToSmt() == (lhs != rhs) # It's a binary operation elif VertexNode.OpCode.IsBinaryOp(self.operator): lhs = self.operands[0].VertexNameToSmt() rhs = self.operands[1].VertexNameToSmt() if self.operator == VertexNode.OpCode.PLUS: return self.VertexNameToSmt() == (lhs + rhs) elif self.operator == VertexNode.OpCode.MINUS: return self.VertexNameToSmt() == (lhs - rhs) elif self.operator == VertexNode.OpCode.AND: return self.VertexNameToSmt() == (lhs & rhs) elif self.operator == VertexNode.OpCode.OR: return self.VertexNameToSmt() == (lhs | rhs) elif self.operator == VertexNode.OpCode.XOR: return self.VertexNameToSmt() == (lhs ^ rhs) elif self.operator == VertexNode.OpCode.SHL: return self.VertexNameToSmt() == (lhs << rhs) elif self.operator == VertexNode.OpCode.SHR: return self.VertexNameToSmt() == (z3.LShR(lhs, rhs)) elif self.operator == VertexNode.OpCode.ROL: return self.VertexNameToSmt() == (z3.RotateLeft(lhs, rhs)) elif self.operator == VertexNode.OpCode.ROR: return self.VertexNameToSmt() == (z3.RotateRight(lhs, rhs)) elif self.operator == VertexNode.OpCode.MUL: return self.VertexNameToSmt() == (lhs * rhs) elif self.operator == VertexNnode.OpCode.DIV: return self.VertexNameToSmt() == (lhs / rhs) # It's a unary operation elif VertexNode.OpCode.IsUnaryOp(self.operator): rhs = self.operands[0].VertexNameToSmt() if self.operator == VertexNode.OpCode.NOT: return self.VertexNameToSmt() == ~rhs elif self.type == VertexNode.VertexType.IMM: # Possible Vertex : Immediate Value return None elif self.type == VertexNode.VertexType.ARR: # Possible Vertex : Input array, array store # input array: there is nothing to do # array store: newarray = store(array, index, value) # if operator == None, it's an "input" array if self.operator == None: return None if self.operator == VertexNode.OpCode.NONE: return None # Otherwise, it must be an array store operation vertex assert (self.operator == VertexNode.OpCode.STORE) oldArray = self.operands[0].VertexNameToSmt() index = self.operands[1].VertexNameToSmt() value = self.operands[2].VertexNameToSmt() newArray = self.VertexNameToSmt() return newArray == z3.Store(oldArray, index, value) elif self.type == VertexNode.VertexType.FUNC: # Possible Vertex : Name of the function return None
def getEq(self, mlocs): #assert(0) #for loc in mlocs: # print loc, "--", #print "" r = [] src = self.src srcs = src.getLocations() sname = Memvars.read(srcs[0]) read_array = mkArray(sname) dst = self.dst dsts = dst.getLocations() old_sname, new_sname = Memvars.write(dsts[0]) old_array = mkArray(old_sname) array = mkArray(new_sname) for (src_loc, dst_loc) in zip(srcs, dsts): read_val = z3.Select(read_array, src_loc.getIndex()) if dst_loc in mlocs: array = z3.Store(array, dst_loc.getIndex(), read_val) r.append(read_val <> 0) r.append((old_array == array)) #print r #assert(0) return r #print self.src, self.dst #if (self.src.isReg()): # src = self.src.name # self.src.size = self.size # srcs = self.getOperands([self.src]) # print srcs #else: # assert(0) #old_sname, new_sname, offset = Memvars.write(self.dst) #old_array = mkArray(old_sname) #array = mkArray(new_sname) #for i in range(self.size): # dst_op = Operand(self.dst.mem_source+"@"+str(offset+i), "BYTE") # src_var = z3.BitVec(src+":"+str(i)+"(0)",8) # if (dst_op in mvars): # array = z3.Store(array, offset+i, src_var) # r.append(src_var <> 0) #r.append((old_array == array)) return r
def contains(self, elem): assert(self.elem_sort.ref == elem.sort()) return z3.Select(self.ref, elem)
def load(self, index): return z3.Select(self.array, index)
def sstore_gas(state, addr, word): cur_val = z3.Select(state.storage, addr) return z3.If(z3.And(cur_val == 0, word != 0), Gsset, Gsreset)