def run_manyfloatsum_symbolic(self, arch): global type_cache if type_cache is None: with open(os.path.join(location, 'tests_src', 'manyfloatsum.c')) as fp: type_cache = parse_defns(fp.read()) p = angr.Project(os.path.join(location, 'tests', arch, 'manyfloatsum')) function = 'sum_doubles' args = [ claripy.FPS('arg_%d' % i, claripy.FSORT_DOUBLE) for i in range(len(type_cache[function].args)) ] addr = p.loader.main_object.get_symbol(function).rebased_addr my_callable = p.factory.callable(addr, prototype=type_cache[function]) result = my_callable(*args) assert result.symbolic s = claripy.Solver(timeout=15 * 60 * 1000) for arg in args: s.add(arg > claripy.FPV(1.0, claripy.FSORT_DOUBLE)) s.add(result == claripy.FPV(27.7, claripy.FSORT_DOUBLE)) args_conc = s.batch_eval(args, 1)[0] assert s.eval(result, 1)[0] == 27.7 # not almost equal!! totally equal!!! z3 is magic, if kinda slow!!!!! for arg_conc in args_conc: assert arg_conc > 1.0 assert sum(args_conc) == 27.7
def value(ty, val): if ty == 'Ity_F32': return claripy.FPV(float(val), claripy.FSORT_FLOAT) elif ty == 'Ity_F64': return claripy.FPV(float(val), claripy.FSORT_DOUBLE) else: return claripy.BVV(int(val), pyvex.get_type_size(ty))
def run_manyfloatsum_symbolic(arch): global type_cache if type_cache is None: type_cache = parse_defns( open(os.path.join(location, 'tests_src', 'manyfloatsum.c')).read()) p = angr.Project(os.path.join(location, 'tests', arch, 'manyfloatsum')) function = 'sum_doubles' cc = p.factory.cc(func_ty=type_cache[function]) args = [ claripy.FPS('arg_%d' % i, claripy.FSORT_DOUBLE) for i in range(len(type_cache[function].args)) ] addr = p.loader.main_object.get_symbol(function).rebased_addr my_callable = p.factory.callable(addr, cc=cc) result = my_callable(*args) nose.tools.assert_true(result.symbolic) s = claripy.Solver() for arg in args: s.add(arg > claripy.FPV(1.0, claripy.FSORT_DOUBLE)) s.add(result == claripy.FPV(27.7, claripy.FSORT_DOUBLE)) args_conc = s.batch_eval(args, 1)[0] nose.tools.assert_equal(s.eval(result, 1)[0], 27.7) # not almost equal!! totally equal!!! z3 is magic, if kinda slow!!!!! for arg_conc in args_conc: nose.tools.assert_greater(arg_conc, 1.0) nose.tools.assert_equal(sum(args_conc), 27.7)
def value(ty, val, size: Optional[int] = None): if ty == 'Ity_F32': return claripy.FPV(float(val), claripy.FSORT_FLOAT) elif ty == 'Ity_F64': return claripy.FPV(float(val), claripy.FSORT_DOUBLE) else: if size is not None: return claripy.BVV(int(val), size) return claripy.BVV(int(val), pyvex.get_type_size(ty))
def make_default_value(ty): if 'F' in ty: if '32' in ty: return claripy.FPV(0.0, claripy.fp.FSORT_FLOAT) elif '64' in ty: return claripy.FPV(0.0, claripy.fp.FSORT_DOUBLE) else: raise ValueError("Unknown float type %s" % ty) else: return claripy.BVV(0, extract_int(ty))
def default(ty): size = int(''.join(c for c in ty if c in '0123456789')) fp = ty.startswith('Ity_F') if not fp: return BiHead(claripy.BVV(0, size), claripy.BVV(0, size)) else: if size == 32: sort = claripy.fp.FSORT_FLOAT elif size == 64: sort = claripy.fp.FSORT_DOUBLE else: raise ValueError("Bad float size: %d" % size) return BiHead(claripy.FPV(0.0, sort), claripy.FPV(0.0, sort))
def _op_Iop_CosF64(self, args): rm, arg = args rm = self._translate_rm(rm) rounds = 20 accumulator = claripy.FPV(1.0, arg.sort) factorialpart = 2.0 for i in xrange(1, rounds + 1): term = claripy.fpDiv(rm, self.pow(rm, arg, 2 * i), claripy.FPV(float(factorialpart), arg.sort)) factorialpart *= (i * 2 + 1) * (i * 2 + 2) if i % 2 == 1: accumulator = claripy.fpSub(rm, accumulator, term) else: accumulator = claripy.fpAdd(rm, accumulator, term) return accumulator
def _cast_to(e, solution, cast_to): """ Casts a solution for the given expression to type `cast_to`. :param e: The expression `value` is a solution for :param value: The solution to be cast :param cast_to: The type `value` should be cast to. Must be one of the currently supported types (bytes|int) :raise ValueError: If cast_to is a currently unsupported cast target. :return: The value of `solution` cast to type `cast_to` """ if cast_to is None: return solution if type(solution) is bool: if cast_to is bytes: return bytes([int(solution)]) elif cast_to is int: return int(solution) elif type(solution) is float: solution = _concrete_value( claripy.FPV(solution, claripy.fp.FSort.from_size(len(e))).raw_to_bv()) if cast_to is bytes: if len(e) == 0: return b"" return binascii.unhexlify('{:x}'.format(solution).zfill( len(e) // 4)) if cast_to is not int: raise ValueError( "cast_to parameter {!r} is not a valid cast target, currently supported are only int and bytes!" .format(cast_to)) return solution
def _convert_to_ast(self, thing, size, byte_width): """ :param thing: The thing to convert to an AST :param size: The size of the thing in bytes :param byte_width: The size of a byte in bits """ if type(thing) is claripy.ast.BV: return thing if type(size) is int: bits = size * byte_width elif getattr(size, 'op', None) == 'BVV': bits = size.args[0] * byte_width else: bits = None if isinstance(thing, str): l.warning( "Encoding unicode string for memory as utf-8. Did you mean to use a bytestring?" ) thing = thing.encode('utf-8') if type(thing) in (bytes, bytearray, memoryview): return claripy.BVV(thing) elif type(thing) is int: if bits is None: l.warning( "Unknown size for memory data %#x. Default to arch.bits.", thing) bits = self.state.arch.bits return claripy.BVV(thing, bits) elif type(thing) is float: if bits == 32: return claripy.FPV(thing, claripy.FSORT_FLOAT).raw_to_bv() elif bits == 64: return claripy.FPV(thing, claripy.FSORT_DOUBLE).raw_to_bv() else: raise TypeError( "Passed float size which is not a float or a double", size) else: try: raw_to_bv = thing.raw_to_bv except AttributeError: raise TypeError("Bad value passed to memory", thing) from None else: return raw_to_bv()
def _ail_handle_Const(self, expr) -> MultiValues: if isinstance(expr.value, float): sort = None if expr.bits == 64: sort = FSORT_DOUBLE elif expr.bits == 32: sort = FSORT_FLOAT return MultiValues( offset_to_values={0: {claripy.FPV(expr.value, sort)}}) else: return MultiValues( offset_to_values={0: {claripy.BVV(expr.value, expr.bits)}})
def set_value(self, state, value, endness=None, **kwargs): self.check_value(value) if endness is None: endness = state.arch.memory_endness if isinstance(value, (int, long)): value = claripy.BVV(value, self.size*8) elif isinstance(value, float): if self.size not in (4, 8): raise ValueError("What do I do with a float %d bytes long" % self.size) value = claripy.FPV(value, claripy.FSORT_FLOAT if self.size == 4 else claripy.FSORT_DOUBLE) cur = 0 for loc in reversed(self.locations): loc.set_value(state, value[cur*8 + loc.size*8 - 1:cur*8], endness, **kwargs) cur += loc.size
def run(self, str_ref): log.debug( 'Called SimProcedure java.lang.Double.parseDouble with args: {}'. format(str_ref)) str_ = self.state.memory.load(str_ref) if str_.concrete: str_value = self.state.solver.eval(str_) # this can raise a ValueError if str_value is not convertible to float double_val = float(str_value) return claripy.FPV(double_val, claripy.FSORT_DOUBLE) else: return claripy.StrToInt(str_, self.arch.bits)
def set_value(self, state, value, endness=None, **kwargs): # pylint:disable=arguments-differ # TODO: This code needs to be reworked for variable byte with and the Third Endness self.check_value(value) if endness is None: endness = state.arch.memory_endness if isinstance(value, int): value = claripy.BVV(value, self.size*state.arch.byte_width) elif isinstance(value, float): if self.size not in (4, 8): raise ValueError("What do I do with a float %d bytes long" % self.size) value = claripy.FPV(value, claripy.FSORT_FLOAT if self.size == 4 else claripy.FSORT_DOUBLE) cur = 0 for loc in reversed(self.locations): loc.set_value(state, value[cur*state.arch.byte_width + loc.size*state.arch.byte_width - 1:cur*state.arch.byte_width], endness=endness, **kwargs) cur += loc.size
def _op_Iop_Yl2xF64(self, args): rm = self._translate_rm(args[0]) arg2_bv = args[2].to_bv() # IEEE754 double looks like this: # SEEEEEEEEEEEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF # thus, we extract the exponent bits, re-bias them, then # (signed) convert them back into an FP value for the integer # part of the log. then we make the approximation that log2(x) # = x - 1 for 1.0 <= x < 2.0 to account for the mantissa. # the bias for doubles is 1023 arg2_exp = (arg2_bv[62:52] - 1023).signed_to_fp( rm, claripy.fp.FSORT_DOUBLE) arg2_mantissa = claripy.Concat(claripy.BVV(int('001111111111', 2), 12), arg2_bv[51:0]).raw_to_fp() # this is the hacky approximation: log2_arg2_mantissa = claripy.fpSub( rm, arg2_mantissa, claripy.FPV(1.0, claripy.fp.FSORT_DOUBLE)) return claripy.fpMul(rm, args[1].raw_to_fp(), claripy.fpAdd(rm, arg2_exp, log2_arg2_mantissa))
def test_fp_ops(): a = claripy.FPV(1.5, claripy.FSORT_DOUBLE) b = claripy.fpToUBV(claripy.fp.RM_NearestTiesEven, a, 32) s = claripy.Solver() assert s.eval(b, 1)[0] == 2
def handle_expression(self, expr, tyenv, path): size = expr.result_size( tyenv) if not expr.tag.startswith('Ico_') else expr.size ty = expr.result_type( tyenv) if not expr.tag.startswith('Ico_') else expr.type addr = self.addr if expr.tag == 'Iex_Get': return self.get_reg(expr.offset, ty) elif expr.tag == 'Iex_RdTmp': return self.get_tmp(expr.tmp) elif expr.tag == 'Iex_Load': addr_expression = self.handle_expression(expr.addr, tyenv, path + ['addr']) self.access(addr_expression, ACCESS_READ) return self.get_mem(addr_expression, ty) elif expr.tag == 'Iex_Const' or expr.tag.startswith('Ico_'): if expr.tag == 'Iex_Const': expr = expr.con if 'F' in ty: if size == 32: values = BiHead( claripy.FPV(expr.value, claripy.fp.FSORT_FLOAT), claripy.FPS('%x_%d' % (addr, path[1]), claripy.fp.FSORT_FLOAT)) elif size == 64: values = BiHead( claripy.FPV(expr.value, claripy.fp.FSORT_DOUBLE), claripy.FPS('%x_%d' % (addr, path[1]), claripy.fp.FSORT_DOUBLE)) else: raise FidgetUnsupportedError( "Why is there a FP const of size %d" % size) else: values = BiHead(claripy.BVV(expr.value, size), claripy.BVS('%x_%d' % (addr, path[1]), size)) values.taints['deps'].append( PendingBinaryData(self.project, self.addr, values, path)) values.taints['concrete'] = True values.taints['concrete_root'] = True return values elif expr.tag == 'Iex_ITE': false_expr = self.handle_expression(expr.iffalse, tyenv, path + ['iffalse']) truth_expr = self.handle_expression(expr.iftrue, tyenv, path + ['iftrue']) values = truth_expr if truth_expr.taints['pointer'] else false_expr cond_expr = self.handle_expression(expr.cond, tyenv, path + ['cond']) if not cond_expr.taints['it']: values.taints['concrete'] = false_expr.taints[ 'concrete'] and truth_expr.taints['concrete'] values.taints[ 'it'] = false_expr.taints['it'] or truth_expr.taints['it'] return values elif expr.tag in ('Iex_Unop', 'Iex_Binop', 'Iex_Triop', 'Iex_Qop'): args = [] for i, sub_expr in enumerate(expr.args): arg = self.handle_expression(sub_expr, tyenv, path + ['args', i]) if expr.op.startswith('Iop_Mul') or expr.op.startswith('Iop_And') \ or (i == 0 and expr.op in ROUNDING_IROPS): if arg.taints['concrete_root']: arg = BiHead(arg.cleanval, arg.cleanval) arg.taints['concrete'] = True args.append(arg) try: values = BiHead( operations[expr.op].calculate(*(x.cleanval for x in args)), operations[expr.op].calculate(*(x.dirtyval for x in args))) except SimOperationError: l.exception( "SimOperationError while running op '%s', returning null", expr.op) return BiHead.default(ty) except KeyError: l.error("Unsupported operation '%s', returning null", expr.op) return BiHead.default(ty) else: # propogate the taints correctly values.taints['concrete'] = True for arg in args: values.taints['deps'].extend(arg.taints['deps']) values.taints['concrete'] = values.taints[ 'concrete'] and arg.taints['concrete'] values.taints[ 'it'] = values.taints['it'] or arg.taints['it'] if expr.op.startswith('Iop_Add') or expr.op.startswith('Iop_And') or \ expr.op.startswith('Iop_Or') or expr.op.startswith('Iop_Xor'): t1 = args[0].taints['pointer'] t2 = args[1].taints['pointer'] values.taints['pointer'] = (t1 if t1 else t2) if ( bool(t1) ^ bool(t2)) else False elif expr.op.startswith('Iop_Sub'): t1 = args[0].taints['pointer'] t2 = args[1].taints['pointer'] values.taints['pointer'] = t1 if t1 and not t2 else False return values elif expr.tag == 'Iex_CCall': values = BiHead.default(ty) for i, expr in enumerate(expr.args): arg = self.handle_expression(expr, tyenv, path + ['args', i]) values.taints['it'] = values.taints['it'] or arg.taints['it'] return values elif expr.tag == 'Iex_GetI': return BiHead.default(ty) else: raise FidgetUnsupportedError( 'Unknown expression tag ({:#x}): {!r}'.format(addr, expr.tag))
def _standardize_value(arg, ty, state, alloc): check = ty is not None if isinstance(arg, s_action_object.SimActionObject): return SimCC._standardize_value(arg.ast, ty, state, alloc) elif isinstance(arg, PointerWrapper): if check and not isinstance(ty, s_type.SimTypePointer): raise TypeError( "Type mismatch: expected %s, got pointer-wrapper" % ty.name) real_value = SimCC._standardize_value(arg.value, ty.pts_to if check else None, state, alloc) return alloc(real_value, state) elif isinstance(arg, str): # TODO: when we switch to py3, distinguish between str and bytes # by null-terminating str but not bytes :/ arg += '\0' ref = False if check: if isinstance(ty, s_type.SimTypePointer) and \ isinstance(ty.pts_to, s_type.SimTypeChar): ref = True elif isinstance(ty, s_type.SimTypeFixedSizeArray) and \ isinstance(ty.elem_type, s_type.SimTypeChar): ref = False if len(arg) > ty.length: raise TypeError("String %s is too long for %s" % (repr(arg), ty.name)) arg = arg.ljust(ty.length, '\0') elif isinstance(ty, s_type.SimTypeArray) and \ isinstance(ty.elem_type, s_type.SimTypeChar): ref = True if ty.length is not None: if len(arg) > ty.length: raise TypeError("String %s is too long for %s" % (repr(arg), ty.name)) arg = arg.ljust(ty.length, '\0') elif isinstance(ty, s_type.SimTypeString): ref = False if len(arg) > ty.length + 1: raise TypeError("String %s is too long for %s" % (repr(arg), ty.name)) arg = arg.ljust(ty.length + 1, '\0') else: raise TypeError("Type mismatch: Expected %s, got char*" % ty.name) val = SimCC._standardize_value( map(ord, arg), s_type.SimTypeFixedSizeArray(s_type.SimTypeChar(), len(arg)), state, alloc) if ref: val = alloc(val, state) return val elif isinstance(arg, list): ref = False subty = None if check: if isinstance(ty, s_type.SimTypePointer): ref = True subty = ty.pts_to elif isinstance(ty, s_type.SimTypeFixedSizeArray): ref = False subty = ty.elem_type if len(arg) != ty.length: raise TypeError("Array %s is the wrong length for %s" % (repr(arg), ty.name)) elif isinstance(ty, s_type.SimTypeArray): ref = True subty = ty.elem_type if ty.length is not None: if len(arg) != ty.length: raise TypeError( "Array %s is the wrong length for %s" % (repr(arg), ty.name)) else: raise TypeError("Type mismatch: Expected %s, got char*" % ty.name) else: types = map(type, arg) if types[1:] != types[:-1]: raise TypeError( "All elements of list must be of same type") val = claripy.Concat(*[ SimCC._standardize_value(sarg, subty, state, alloc) for sarg in arg ]) if ref: val = alloc(val, state) return val elif isinstance(arg, tuple): if check: if not isinstance(ty, s_type.SimStruct): raise TypeError( "Type mismatch: Expected %s, got tuple (i.e. struct)" % ty.name) if len(arg) != len(ty.fields): raise TypeError( "Wrong number of fields in struct, expected %d got %d" % (len(ty.fields), len(arg))) return claripy.Concat(*[ SimCC._standardize_value(sarg, sty, state, alloc) for sarg, sty in zip(arg, ty.fields.values()) ]) else: return claripy.Concat(*[ SimCC._standardize_value(sarg, None, state, alloc) for sarg in arg ]) elif isinstance(arg, (int, long)): if check and isinstance(ty, s_type.SimTypeFloat): return SimCC._standardize_value(float(arg), ty, state, alloc) val = state.se.BVV(arg, ty.size if check else state.arch.bits) if state.arch.memory_endness == 'Iend_LE': val = val.reversed return val elif isinstance(arg, float): sort = claripy.FSORT_FLOAT if check: if isinstance(ty, s_type.SimTypeDouble): sort = claripy.FSORT_DOUBLE elif isinstance(ty, s_type.SimTypeFloat): pass else: raise TypeError("Type mismatch: expectd %s, got float" % ty.name) else: sort = claripy.FSORT_DOUBLE if state.arch.bits == 64 else claripy.FSORT_FLOAT val = claripy.fpToIEEEBV(claripy.FPV(arg, sort)) if state.arch.memory_endness == 'Iend_LE': val = val.reversed # pylint: disable=no-member return val elif isinstance(arg, claripy.ast.Base): # yikes if state.arch.memory_endness == 'Iend_LE' and arg.length == state.arch.bits: arg = arg.reversed return arg else: raise TypeError("I don't know how to serialize %s." % repr(arg))
def store(self, state, addr, value): if type(value) in (int, float): value = claripy.FPV(float(value), self.sort) return super(SimTypeFloat, self).store(state, addr, value)
def pow(rm, arg, n): out = claripy.FPV(1.0, arg.sort) for _ in range(n): out = claripy.fpMul(rm, arg, out) return out
def _op_Iop_Yl2xp1F64(self, args): rm_raw, arg1, arg2 = args rm = self._translate_rm(rm_raw) arg2_p1 = claripy.fpAdd(rm, arg2.raw_to_fp(), claripy.FPV(1.0, claripy.fp.FSORT_DOUBLE)) return self._op_Iop_Yl2xF64((rm_raw, arg1, arg2_p1))
def test_concrete_fp(): f = claripy.FPV(1.0, claripy.FSORT_FLOAT) nose.tools.assert_equal(claripy.backends.concrete.eval(f, 2), (1.0, ))
def _get_initialized_method_args(self, state, soot_method): arg_vals = [] args_target_method = [] if 'STATIC' not in soot_method.attrs: this = SimSootValue_ThisRef.new_object(state, soot_method.class_name, init_object=False) args_target_method.append( get_new_object_arg(this, is_this_ref=True)) for param in soot_method.params: if param in ['byte', 'char']: val = random.randint(0, 255) arg_vals.append(val) arg = get_new_primitive_arg(claripy.BVV(val, 8), param) elif param in ['short', 'int', 'boolean']: val = random.randint(0, 2**32) arg_vals.append(val) arg = get_new_primitive_arg(claripy.BVV(val, 32), param) elif param == 'long': val = random.randint(0, 2**64 - 1) arg_vals.append(val) arg = get_new_primitive_arg(claripy.BVV(val, 64), param) elif param == 'float': val = random.randint(0, 2**64 - 1) arg_vals.append(val) arg = get_new_primitive_arg( claripy.FPV(val, claripy.FSORT_FLOAT), param) elif param == 'double': val = random.randint(0, 2**64 - 1) arg_vals.append(val) arg = get_new_primitive_arg( claripy.FPV(val, claripy.FSORT_DOUBLE), param) elif param == 'java.lang.String': s = "A" * 20 arg_vals.append(s) sym_str = claripy.StringV(s, 20) str_ref = SimSootValue_StringRef.new_string(state, sym_str) arg = get_new_object_arg(str_ref) elif param.endswith('[][]'): raise NotImplementedError elif param.endswith('[]') and 'byte' in param: # TODO: symbolic size? base_ref = SimSootExpr_NewArray.new_array( state, param[:-2], claripy.BVV(20, 32)) arg_vals.append([0x41] * 20) for idx in range(20): elem_ref = SimSootValue_ArrayRef(base_ref, idx) state.memory.store(elem_ref, claripy.BVV(0x41, 8)) arg = get_new_object_arg(base_ref) elif param.endswith('[]'): # TODO: symbolic size? array_ref = SimSootExpr_NewArray.new_array( state, param[:-2], claripy.BVV(2, 32)) arg = get_new_object_arg(array_ref) else: obj_ref = SimSootValue_ThisRef.new_object(state, param, init_object=False) if param in self.p.classes: clx = self.p.classes[param] for info in clx.fields.items(): # initialize strings and byte[] with some random values name = info[0] t = info[1][1] if 'String' in t: s = "A" * 20 arg_vals.append(s) sym_str = claripy.StringV(s, 20) str_ref = SimSootValue_StringRef.new_string( state, sym_str) obj_ref.set_field(state, name, t, str_ref) if 'byte[]' in t: print("Setting byte[]") import ipdb ipdb.set_trace() arg_vals.append([0x41] * 20) base_ref = SimSootExpr_NewArray.new_array( state, 'byte', claripy.BVV(20, 32)) for idx in range(20): elem_ref = SimSootValue_ArrayRef(base_ref, idx) state.memory.store(elem_ref, claripy.BVV(0x41, 8)) obj_ref.set_field(state, name, t, base_ref) arg = get_new_object_arg(obj_ref) args_target_method.append(arg) return args_target_method, arg_vals