def visitCompare(self, node): children = node.getChildren() if len(children) == 3: left = node.getChildren()[0] op = str(node.getChildren()[1]) if op == "==" or op == "!=": right = node.getChildren()[2] left_z3 = self.visit(left) right_z3 = self.visit(right) if z3.is_string(left_z3) and z3.is_string( right_z3) or z3.is_bool(left_z3) and z3.is_bool( right_z3): if op == "==": result = z3.simplify( z3.Not(z3.Distinct(left_z3, right_z3))) return result elif op == "!=": # sys.stderr.write("%s != %s\n" % (left_z3, right_z3)) result = z3.simplify(z3.Distinct(left_z3, right_z3)) return result # elif z3.is_string(left_z3) and z3.is_bool(right_z3): # if op == "==": # pass # elif op == "!=": # pass # elif z3.is_bool(left_z3) and z3.is_string(right_z3): # if op == "==": # pass # elif op == "!=": # pass # this expression is not supported, so make a predicate variable for it predicate = str(node) return z3.Bool("PREDICATE_%s" % (predicate))
def model_value_to_python(value: z3.ExprRef) -> object: if z3.is_string(value): return value.as_string() elif z3.is_real(value): return float(value.as_fraction()) else: return ast.literal_eval(repr(value))
def lenOfZ3(obj): if type(obj) == str or type(obj) == list: return len(obj) if z3.is_string(obj): return z3.Length(obj) raise Exception('Need to calculate length of unknown object')
def string_concat(x, args): cc = x if z3.is_string(x): for y in args: cc = z3.Concat(cc, createZ3ExpressionFromConstraint(y, {})) return cc else: raise NotSupportedException('We only support concat on stirngs as arrays are difficult in z3.')
def get_z3_value(self, value): if z3.is_string(value): return value.as_string()[1:-1].replace('\\x00', '?') elif z3.is_int(value): return value.as_long() elif value is None: return '' # TODO adhere to type else: raise ValueError('Got unknown Z3 type')
def coerceTypesIfPossible(var, other_var): if z3.is_or(other_var) and not z3.is_bool(var): other_var = transformNonBooleanLazyEvaluations(other_var) if z3.is_or(var) and not z3.is_bool(other_var): var = transformNonBooleanLazyEvaluations(var) if z3.is_and(other_var) and not z3.is_bool(var): other_var = transformNonBooleanLazyEvaluations(other_var) if z3.is_and(var) and not z3.is_bool(other_var): var = transformNonBooleanLazyEvaluations(var) if var.decl().kind() == z3.Z3_OP_UNINTERPRETED: if z3.is_bool(other_var) and not z3.is_bool(var): infered_types[str(var)] = 'boolean' return z3.Bool(str(var)), other_var if z3.is_string(other_var) and not z3.is_string(var): if other_var.as_string() == '': # we probably dont want to coerce in this specific case as this is merely a non empty check if z3.is_bool(var): return var, z3.BoolVal(False) if z3.is_int(var): return var, z3.IntVal(0) else: infered_types[str(var)] = 'string' return z3.String(str(var)), other_var if z3.is_int(other_var) and not z3.is_int(var): infered_types[str(var)] = 'number' return z3.Int(str(var)), other_var elif var.decl().kind() == z3.Z3_OP_UNINTERPRETED: if z3.is_bool(var): infered_types[str(var)] = 'boolean' if z3.is_string(var): infered_types[str(var)] = 'string' if z3.is_int(var): infered_types[str(var)] = 'number' else: # this means that it is non-interpreted and we need to coerce other var to the type of var if z3.is_string(var) and z3.is_int_value(other_var): other_var = z3.StringVal(str(other_var)) if z3.is_arith(var) and z3.is_string(other_var): other_var = z3.IntVal(int(other_var.as_string())) return var, other_var
def __k_bool__(self): if z3.is_int(self.value) or z3.is_real(self.value) or z3.is_bv( self.value): yield inference.InferenceResult(Z3Proxy.init_expr( self.value != 0, self.defaults), status=True) elif z3.is_string(self.value): yield inference.InferenceResult(Z3Proxy.init_expr( self.value != z3.StringVal(""), self.defaults), status=True) else: yield inference.InferenceResult(self, status=True)
def __k_str__(self): try: if z3.is_string(self.value): val = self.value else: val = z3.IntToStr(self.value) return inference.InferenceResult.load_result( Z3Proxy.init_expr(val, {**self.defaults})) except (z3.Z3Exception, Exception): MANAGER.logger.warning( "Can't convert expression of non integer: {} to string", self.value) return inference.InferenceResult.load_result(nodes.Uninferable())
def createZ3ForBool(var): if z3.is_int(var): return var != z3.IntVal(0) elif z3.is_string(var): return var != z3.StringVal('') elif z3.is_array(var): return z3.BoolVal(True) elif z3.is_bool(var): return var elif var is None: # this should be the case when we have a JSON value that is just inside a conditional etc return None elif z3.is_seq(var): # not string but still something ref-like we only found cases where this was string comparisons using <, >, etc. return var else: raise Exception('unhandled type in uninterpreted if')
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 AssignementsToString(val, model): if type(val) == z3.z3.ArrayRef: vals = [] # Just print out the first 5 values of array, we do not really know how # many elements need to be in the array due to z3 handling arrays as functions for i in range(3): vals.append(AssignementsToString(model.eval(val[i]), model)) return vals if z3.is_string(val): return val.as_string() if z3.is_int(val): return int(str(val)) if z3.is_bool(val): if str(val) == 'False': return False return True raise Exception('solved assignement type is neither int nor string, what to do?')
def solveConstrains(constraints, types, shouldPrint=True): if type(types) == dict: addTypesFromTaintAnalysis('event', types['event']) else: for [iden, typo] in types: if type(iden) == str: infered_types[iden] = typo logging.debug(infered_types) c = True for constraint in constraints: cc = createZ3ForIf(constraint, types) logging.debug(cc) if z3.is_int(cc): cc = cc != 0 elif z3.is_string(cc): cc = cc != z3.StringVal('') c = z3.And(c, cc) for cc in GLOBAL_CONSTRAINTS: logging.debug(cc) c = z3.And(c, cc) for type_info in infered_types: if infered_types[type_info] == '': continue cc = z3.String('type:' + type_info) == z3.StringVal(infered_types[type_info]) logging.debug(cc) c = z3.And(c, cc) for identifier in MAKE_UNSOLVABLE: cc = z3.String(identifier) == z3.StringVal('') logging.debug(cc) c = z3.And(c, cc) # solver = z3.SolverFor('QF_LIA') solver = z3.Solver() solver.add(c) r = solver.check() if r == z3.unsat: if shouldPrint: eprint("no solution") return 'unsat' elif r == z3.unknown: if shouldPrint: eprint("failed to solve") return 'unsat' try: eprint(solver.model()) except Exception: return else: model = solver.model() assignement = dict() types = dict() for decl in model.decls(): if str(decl) == 'event': continue if str(decl)[:5] == 'type:': types[str(decl)[5:]] = AssignementsToString(model.get_interp(decl), model) else: assignement[str(decl)] = AssignementsToString(model.get_interp(decl), model) for identifier in GLOBAL_IDENTIFIER: if identifier not in assignement: if identifier == 'event': continue logging.debug('Adding empty shizzle') assignement[identifier] = '' logging.debug(GLOBAL_IDENTIFIER) if shouldPrint: print(json.dumps({'assignements': assignement, 'types': types})) return {'assignements': assignement, 'types': types}