def trim_start(s: z3.SeqRef) -> z3.SeqRef: ctx = s.ctx trim_start = z3.RecFunction('trim_start', z3.StringSort(ctx), \ z3.StringSort(ctx)) z3.RecAddDefinition(trim_start, s, \ z3.If(is_whitespace(head(s)), \ trim_start(tail(s)), s)) return trim_start(s)
def to_case(name: str, name_char: Callable[[z3.Context], z3.FuncDeclRef], \ text: z3.SeqRef) -> z3.SeqRef: ctx = text.ctx empty = z3.StringVal("", ctx) f = z3.RecFunction(name, z3.StringSort(ctx), z3.StringSort(ctx)) z3.RecAddDefinition(f, text, \ z3.If(text == empty, \ empty, z3.Concat(name_char(ctx)(head(text)), \ f(tail(text))))) return f(text)
def case_char(name: str, map_: Dict[str, str], ctx: z3.Context) \ -> z3.FuncDeclRef: char = z3.FreshConst(z3.StringSort(ctx)) const = char for x, y in map_: const = z3.If(char == z3.StringVal(x, ctx), \ z3.StringVal(y, ctx), const, ctx) f = z3.RecFunction(f'{name}_char', z3.StringSort(ctx), z3.StringSort(ctx)) z3.RecAddDefinition(f, char, const) return f
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 type2sort(typ, ctx): if typ == int: return z3.IntSort(ctx) elif typ == str: return z3.StringSort(ctx) else: raise ValueError(f'Unsupported type: {typ}')
def SReplace(text: SStr, old: SStr, new: SStr) -> z3.SeqRef: ctx = text.ctx text, old, new = text.expr, old.expr, new.expr empty = z3.StringVal("", ctx) replace_all = z3.RecFunction('replace_all', \ z3.StringSort(ctx), z3.StringSort(ctx), z3.StringSort(ctx), # from z3.StringSort(ctx)) # to z3.RecAddDefinition(replace_all, [text, old, new], \ z3.If(z3.Or(old == empty, \ z3.Not(z3.Contains(text, old)), ctx),\ text, replace_all(z3.Replace(text, old, new), \ old, new))) return replace_all(text, old, new)
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 _z3_sort(self, json_type, typeargs=[], typeargnames={}): # print "Looking up type %s (%s, %s): %s" % (json_type['name'], typeargs, typeargnames, json_type) ## Hard-coded Z3 correspondence for some types if json_type['name'] == 'nat': return z3.IntSort() if json_type['name'] == 'string': return z3.StringSort() if json_type['name'] == 'gmap': return z3.ArraySort(self._z3_sort(json_type['args'][0]), self._z3_sort(json_type['args'][1])) if json_type['what'] == 'type:var': t = typeargnames[json_type['name']] return self._z3_sort(t) if json_type['what'] == 'type:glob': if json_type['name'] == 'buf': return z3.SeqSort(z3.BitVecSort(8)) return self.z3_sort(json_type['name'], [ self._type_var_lookup(typeargnames, x) for x in json_type['args'] ]) if str(json_type) in self.json_to_sort: return self.json_to_sort[str(json_type)] if json_type['name'] == 'list': return z3.SeqSort(self._z3_sort(typeargs[0])) datatype = z3.Datatype(str(json_type['name'])) typeargnames = {} for i in range(0, len(typeargs)): typeargname = json_type['argnames'][i] typeargnames[typeargname] = typeargs[i] for c in json_type['constructors']: cname = str(c['name']) datatype.declare( cname, *[(cname + '_%d' % idx, self._z3_sort(argtype, [], typeargnames)) for (idx, argtype) in enumerate(c['argtypes'])]) t = datatype.create() self.json_to_sort[str(json_type)] = t return t
def getZ3(tuple): if tuple[0] == CONCAT: return z3.Concat(list(map(getZ3, list(tuple[1:])))) elif tuple[0] == STAR: return z3.Star(getZ3(tuple[1])) elif tuple[0] == DOT: res = z3.Range(chr(32), chr(127)) return res elif tuple[0] == CHAR: return z3.Re(tuple[1]) elif tuple[0] == BAR: return z3.Union(list(map(getZ3, list(tuple[1:])))) elif tuple[0] == GROUP: return getZ3(tuple[2]) elif tuple[0] == EMPTY: return z3.Empty(z3.ReSort(z3.StringSort())) raise NotSupportedException('not yet supported', tuple[0])
def test_expression(): expr_string = "(= a true)" expr = Expression(expr_string) assert expr.expression == expr_string with pytest.raises(InvalidExpression, message="expected InvalidExpression"): assert Expression("((= a true)") ctx = z3.Context() var = Expression.create_z3_var(ctx, int, 'var') assert var.sort() == z3.IntSort(ctx=ctx) assert str(var) == 'var' assert var.ctx == ctx assert var.ctx != z3.main_ctx assert Expression.create_z3_var(None, bool, 'var').sort() == z3.BoolSort() assert Expression.create_z3_var(None, str, 'var').sort() == z3.StringSort() assert Expression.create_z3_var(None, float, 'var').sort() == z3.RealSort() with pytest.raises(UnsupportedVariableType, message="expected UnsupportedVariableType"): assert Expression.create_z3_var(None, list, 'var')
def __init__(self, regex: str, unknown: z3.StringSort(), word_choice_cutoff=10, dot_charset=DEFAULT_DOT_CHARSET, star_lengths: Iterable[int] = DEFAULT_STAR_LENGTHS, symbolic=False): """ Compiles Regex to Z3 String expressions :param dot_charset: Characters that the DOT metachar can match. This should be limited to valid URL characters, or can be set to a taint marker. """ self.unknown = unknown self.star_lengths = star_lengths self.string_var_count = 0 self.bool_var_count = 0 self.symbolic = symbolic _parser = parsing.RegexParser() parse_result = _parser.parse(regex) self.parsing_errors = parse_result['errors'] regex_0 = flatten_regex(parse_result['root']) regex_1 = remove_path(regex_0) regex_2 = convert_stars(regex_1, star_lengths) regex_3 = convert_bars(regex_2, cutoff=word_choice_cutoff) if symbolic: regex_4, self.symbols = convert_to_encoded_symbols(regex_3, {}) else: regex_4, self.symbols = regex_3, {} self.regex = regex_4 assert self.regex self.groups = parse_result['groups'] self.backrefs = parse_result['backrefs'] self.dot_charset = dot_charset
def setupProblem(self): self.stackvars = {} self.Qf = z3.Function("final", z3.SeqSort(z3.IntSort()), z3.BoolSort()) self.d = z3.Function("delta", z3.SeqSort(z3.IntSort()), z3.StringSort(), z3.SeqSort(z3.IntSort())) for (w, st, final, has_children) in self.t.iter(): sv = b"stack" + base64.b16encode(w) self.stackvars[w] = Sequence(sv) self.s_add_finalstate(w, final) if final and has_children: self.s_add_nonemptystate(w) if len(w): self.s_add_transition_to(w) self.s.add(self.stackvars[b''] == z3.Unit(z3.IntVal(0))) # most useful convention: # accept by drained stack, but don't read any more and fail then self.s.add(self.Qf(z3.Empty(z3.SeqSort(z3.IntSort()))) == True)
def reverse(s: z3.SeqRef) -> z3.SeqRef: ctx = s.ctx empty = z3.StringVal("", ctx) acc = z3.FreshConst(z3.StringSort(ctx), 'acc') tail_rev = z3.RecFunction('reverse', \ z3.StringSort(ctx), z3.StringSort(ctx), \ z3.StringSort(ctx)) z3.RecAddDefinition(tail_rev, [s, acc], \ z3.If(s == empty, \ acc, tail_rev(tail(s), z3.Concat(head(s), acc)))) rev = z3.RecFunction('reverse', z3.StringSort(ctx), \ z3.StringSort(ctx)) z3.RecAddDefinition(rev, s, tail_rev(s, empty)) return rev(s)
# z3.set_param("smt.string_solver", "z3str3") with open('NFS3API_2.json') as f: code = f.read() j = json.loads(code) jc = json_eval.Context() jc.load(j) m = jc.get_module('Main') stateType = m.get_type("state") sym = json_sym.SymbolicJSON(jc) sym.register_base_type("positive", lambda args: z3.IntSort()) sym.register_base_type("string", lambda args: z3.StringSort()) # XXX u0 is a u64? and u1 is a u32... sym.register_base_type("u0", lambda args: z3.BitVecSort(64)) sym.register_base_type("u1", lambda args: z3.BitVecSort(32)) sym.register_base_type( "gmap", lambda args: z3.ArraySort( sym.z3_sort(args[0]), sym.z3_sort({ 'what': 'type:glob', 'name': 'option', 'args': [args[1]], 'mod': m, }))) sym.register_base_type("buf", lambda args: z3.SeqSort(z3.BitVecSort(8))) # sym.register_base_type("list", lambda args: z3.SeqSort(sym.z3_sort(args[0])))
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 __init__(self, environment, z3_ctx): DagWalker.__init__(self, environment) self.mgr = environment.formula_manager self._get_type = environment.stc.get_type self._back_memoization = {} self.ctx = z3_ctx # Back Conversion self._back_fun = { z3.Z3_OP_AND: lambda args, expr: self.mgr.And(args), z3.Z3_OP_OR: lambda args, expr: self.mgr.Or(args), z3.Z3_OP_MUL: lambda args, expr: self.mgr.Times(args), z3.Z3_OP_ADD: lambda args, expr: self.mgr.Plus(args), z3.Z3_OP_DIV: lambda args, expr: self.mgr.Div(args[0], args[1]), z3.Z3_OP_IFF: lambda args, expr: self.mgr.Iff(args[0], args[1]), z3.Z3_OP_XOR: lambda args, expr: self.mgr.Xor(args[0], args[1]), z3.Z3_OP_FALSE: lambda args, expr: self.mgr.FALSE(), z3.Z3_OP_TRUE: lambda args, expr: self.mgr.TRUE(), z3.Z3_OP_GT: lambda args, expr: self.mgr.GT(args[0], args[1]), z3.Z3_OP_GE: lambda args, expr: self.mgr.GE(args[0], args[1]), z3.Z3_OP_LT: lambda args, expr: self.mgr.LT(args[0], args[1]), z3.Z3_OP_LE: lambda args, expr: self.mgr.LE(args[0], args[1]), z3.Z3_OP_SUB: lambda args, expr: self.mgr.Minus(args[0], args[1]), z3.Z3_OP_NOT: lambda args, expr: self.mgr.Not(args[0]), z3.Z3_OP_IMPLIES: lambda args, expr: self.mgr.Implies(args[0], args[1]), z3.Z3_OP_ITE: lambda args, expr: self.mgr.Ite(args[0], args[1], args[2]), z3.Z3_OP_TO_REAL: lambda args, expr: self.mgr.ToReal(args[0]), z3.Z3_OP_BAND : lambda args, expr: self.mgr.BVAnd(args[0], args[1]), z3.Z3_OP_BOR : lambda args, expr: self.mgr.BVOr(args[0], args[1]), z3.Z3_OP_BXOR : lambda args, expr: self.mgr.BVXor(args[0], args[1]), z3.Z3_OP_BNOT : lambda args, expr: self.mgr.BVNot(args[0]), z3.Z3_OP_BNEG : lambda args, expr: self.mgr.BVNeg(args[0]), z3.Z3_OP_CONCAT : lambda args, expr: self.mgr.BVConcat(args[0], args[1]), z3.Z3_OP_ULT : lambda args, expr: self.mgr.BVULT(args[0], args[1]), z3.Z3_OP_ULEQ : lambda args, expr: self.mgr.BVULE(args[0], args[1]), z3.Z3_OP_SLT : lambda args, expr: self.mgr.BVSLT(args[0], args[1]), z3.Z3_OP_SLEQ : lambda args, expr: self.mgr.BVSLE(args[0], args[1]), z3.Z3_OP_UGT : lambda args, expr: self.mgr.BVUGT(args[0], args[1]), z3.Z3_OP_UGEQ : lambda args, expr: self.mgr.BVUGE(args[0], args[1]), z3.Z3_OP_SGT : lambda args, expr: self.mgr.BVSGT(args[0], args[1]), z3.Z3_OP_SGEQ : lambda args, expr: self.mgr.BVSGE(args[0], args[1]), z3.Z3_OP_BADD : lambda args, expr: self.mgr.BVAdd(args[0], args[1]), z3.Z3_OP_BMUL : lambda args, expr: self.mgr.BVMul(args[0], args[1]), z3.Z3_OP_BUDIV : lambda args, expr: self.mgr.BVUDiv(args[0], args[1]), z3.Z3_OP_BSDIV : lambda args, expr: self.mgr.BVSDiv(args[0], args[1]), z3.Z3_OP_BUREM : lambda args, expr: self.mgr.BVURem(args[0], args[1]), z3.Z3_OP_BSREM : lambda args, expr: self.mgr.BVSRem(args[0], args[1]), z3.Z3_OP_BSHL : lambda args, expr: self.mgr.BVLShl(args[0], args[1]), z3.Z3_OP_BLSHR : lambda args, expr: self.mgr.BVLShr(args[0], args[1]), z3.Z3_OP_BASHR : lambda args, expr: self.mgr.BVAShr(args[0], args[1]), z3.Z3_OP_BSUB : lambda args, expr: self.mgr.BVSub(args[0], args[1]), z3.Z3_OP_EXT_ROTATE_LEFT : lambda args, expr: self.mgr.BVRol(args[0], args[1].bv_unsigned_value()), z3.Z3_OP_EXT_ROTATE_RIGHT: lambda args, expr: self.mgr.BVRor(args[0], args[1].bv_unsigned_value()), z3.Z3_OP_BV2INT: lambda args, expr: self.mgr.BVToNatural(args[0]), z3.Z3_OP_POWER : lambda args, expr: self.mgr.Pow(args[0], args[1]), z3.Z3_OP_SELECT : lambda args, expr: self.mgr.Select(args[0], args[1]), z3.Z3_OP_STORE : lambda args, expr: self.mgr.Store(args[0], args[1], args[2]), z3.Z3_OP_SEQ_LENGTH: lambda args, expr: self.mgr.StrLength(args[0]), z3.Z3_OP_SEQ_CONCAT: lambda args, expr: self.mgr.StrConcat(args), z3.Z3_OP_SEQ_AT: lambda args, expr: self.mgr.StrCharAt(args[0], args[1]), z3.Z3_OP_SEQ_CONTAINS: lambda args, expr: self.mgr.StrContains(args[0], args[1]), z3.Z3_OP_SEQ_INDEX: lambda args, expr: self.mgr.StrIndexOf(args[0], args[1], args[2]), z3.Z3_OP_SEQ_REPLACE: lambda args, expr: self.mgr.StrReplace(args[0], args[1], args[2]), z3.Z3_OP_SEQ_EXTRACT: lambda args, expr: self.mgr.StrSubstr(args[0], args[1], args[2]), z3.Z3_OP_SEQ_PREFIX: lambda args, expr: self.mgr.StrPrefixOf(args[0], args[1]), z3.Z3_OP_SEQ_SUFFIX: lambda args, expr: self.mgr.StrSuffixOf(args[0], args[1]), z3.Z3_OP_INT_TO_STR: lambda args, expr: self.mgr.IntToStr(args[0]), z3.Z3_OP_STR_TO_INT: lambda args, expr: self.mgr.StrToInt(args[0]), # Actually use both args, expr z3.Z3_OP_SIGN_EXT: lambda args, expr: self.mgr.BVSExt(args[0], z3.get_payload(expr, 0)), z3.Z3_OP_ZERO_EXT: lambda args, expr: self.mgr.BVZExt(args[0], z3.get_payload(expr, 0)), z3.Z3_OP_ROTATE_LEFT: lambda args, expr: self.mgr.BVRol(args[0], z3.get_payload(expr, 0)), z3.Z3_OP_ROTATE_RIGHT: lambda args, expr: self.mgr.BVRor(args[0], z3.get_payload(expr, 0)), z3.Z3_OP_EXTRACT: lambda args, expr: self.mgr.BVExtract(args[0], z3.get_payload(expr, 1), z3.get_payload(expr, 0)), # Complex Back Translation z3.Z3_OP_EQ : self._back_z3_eq, z3.Z3_OP_UMINUS : self._back_z3_uminus, z3.Z3_OP_CONST_ARRAY : self._back_z3_const_array, } # Unique reference to Sorts self.z3RealSort = z3.RealSort(self.ctx) self.z3BoolSort = z3.BoolSort(self.ctx) self.z3IntSort = z3.IntSort(self.ctx) self.z3StrSort = z3.StringSort(self.ctx) self._z3ArraySorts = {} self._z3BitVecSorts = {} self._z3Sorts = {} # Unique reference to Function Declaration self._z3_func_decl_cache = {} return
# Or can you? Because pure must be imported as * and names cannot be reassigned? for (patt, repl, condition) in [ # # ('F(reduce(R, L, I))', 'reduce(R`, map(F, L), I)', reduce_fn_check), ]: basic_simplifier.add(exprparse(patt), exprparse(repl), condition) # expr = exprparse('IsTruthy(isint(c) and isint(d))') # rewritten = basic_simplifier.rewrite(expr) # print('rewrite engine test', unparse(expr), unparse(rewritten)) PyFunc = z3.DeclareSort('PyFunc') Unk = z3.Datatype('Unk') Unk.declare('none') Unk.declare('bool', ('tobool', z3.BoolSort())) Unk.declare('int', ('toint', z3.IntSort())) Unk.declare('string', ('tostring', z3.StringSort())) Unk.declare('func', ('tofunc', PyFunc)) Unk.declare('app', ('tl', Unk), ('hd', Unk)) Unk.declare('_') # empty tuple Unk.declare('undef') # error value (Unk, ) = z3.CreateDatatypes(Unk) App = z3.Function('.', Unk, Unk, Unk) class ZHolder(): pass Z = ZHolder() Z.Wrapbool = Unk.bool Z.Wrapint = Unk.int
def make_string_sort(self): return z3.StringSort(self.ctx())
return SymbolicSeq(self.z3var + other.z3var) else: return SymbolicSeq(self.z3var + other) def __eq__(self, other): if isinstance(other, SymbolicSeq): return z3.Eq(self.z3var, other.z3var) else: return NotImplemented _TYPE_TO_SMT_SORT = { int: z3.IntSort(), float: z3.Float64(), bool: z3.BoolSort(), str: z3.StringSort(), } def type_to_smt_sort(t: Type): if t in _TYPE_TO_SMT_SORT: return _TYPE_TO_SMT_SORT[t] origin = getattr(t, '__origin__', None) if origin in (List, Sequence, Container): item_type = t.__args__[0] return z3.SeqSort(type_to_smt_sort(item_type)) elif origin in (Dict, Mapping): key_type, val_type = t.__args__ return z3.ArraySort(type_to_smt_sort(key_type), type_to_smt_sort(val_type)) return None
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