def _manage_callstack(state): # condition for call = Ijk_Call # condition for ret = stack pointer drops below call point if state.history.jumpkind == 'Ijk_Call': state._inspect('call', BP_BEFORE, function_address=state.regs._ip) new_func_addr = state._inspect_getattr('function_address', None) if new_func_addr is not None and not claripy.is_true(new_func_addr == state.regs._ip): state.regs._ip = new_func_addr try: if state.arch.call_pushes_ret: ret_addr = state.mem[state.regs._sp].long.concrete else: ret_addr = state.se.eval(state.regs._lr) except SimSolverModeError: # Use the address for UnresolvableTarget instead. ret_addr = state.project.simos.unresolvable_target try: state_addr = state.addr except (SimValueError, SimSolverModeError): state_addr = None try: stack_ptr = state.se.eval(state.regs._sp) except SimSolverModeError: stack_ptr = 0 new_frame = CallStack( call_site_addr=state.history.recent_bbl_addrs[-1], func_addr=state_addr, stack_ptr=stack_ptr, ret_addr=ret_addr, jumpkind='Ijk_Call') state.callstack.push(new_frame) state._inspect('call', BP_AFTER) else: while state.se.is_true(state.regs._sp > state.callstack.top.stack_ptr): state._inspect('return', BP_BEFORE, function_address=state.callstack.top.func_addr) state.callstack.pop() state._inspect('return', BP_AFTER) if not state.arch.call_pushes_ret and \ claripy.is_true(state.regs._ip == state.callstack.ret_addr) and \ claripy.is_true(state.regs._sp == state.callstack.stack_ptr): # very weird edge case that's not actually weird or on the edge at all: # if we use a link register for the return address, the stack pointer will be the same # before and after the call. therefore we have to check for equality with the marker # along with this other check with the instruction pointer to guess whether it's time # to pop a callframe. Still better than relying on Ijk_Ret. state._inspect('return', BP_BEFORE, function_address=state.callstack.top.func_addr) state.callstack.pop() state._inspect('return', BP_AFTER)
def test_self_modifying_code(): p = angr.Project(os.path.join(test_location, 'cgc/stuff')) pg = p.factory.simgr(p.factory.entry_state(add_options={o.STRICT_PAGE_ACCESS})) pg.step(until=lambda lpg: len(lpg.active) != 1) retval = pg.one_deadended.regs.ebx nose.tools.assert_true(claripy.is_true(retval == 65)) pgu = p.factory.simgr(p.factory.entry_state(add_options={o.STRICT_PAGE_ACCESS} | o.unicorn)) pgu.step(until=lambda lpg: len(lpg.active) != 1) retval = pgu.one_deadended.regs.ebx nose.tools.assert_true(claripy.is_true(retval == 65)) nose.tools.assert_true(pg.one_deadended.history.bbl_addrs.hardcopy == pgu.one_deadended.history.bbl_addrs.hardcopy)
def preconstrain_file(self, content, simfile, set_length=False): """ Preconstrain the contents of a file. :param content: The content to preconstrain the file to. Can be a bytestring or a list thereof. :param simfile: The actual simfile to preconstrain """ repair_entry_state_opts = False if o.TRACK_ACTION_HISTORY in self.state.options: repair_entry_state_opts = True self.state.options -= {o.TRACK_ACTION_HISTORY} if set_length: # disable read bounds simfile.has_end = False pos = 0 for write in content: if type(write) is int: write = bytes([write]) data, length, pos = simfile.read(pos, len(write), short_reads=False) if not claripy.is_true(length == len(write)): raise AngrError("Bug in either SimFile or in usage of preconstrainer: couldn't get requested data from file") self.preconstrain(write, data) # if the file is a stream, reset its position if simfile.pos is not None: simfile.pos = 0 if set_length: # enable read bounds; size is now maximum size simfile.has_end = True if repair_entry_state_opts: self.state.options |= {o.TRACK_ACTION_HISTORY}
def test_type_annotation(): my_ty = angr.sim_type.SimTypeTop() ptr = claripy.BVS('ptr', 32).annotate(angr.type_backend.TypeAnnotation(angr.sim_type.SimTypePointer(my_ty, label=[]))) ptroffset = ptr + 4 bt = angr.type_backend.TypeBackend() tv = bt.convert(ptroffset) nose.tools.assert_is(tv.ty.pts_to, my_ty) nose.tools.assert_true(claripy.is_true(tv.ty.offset == 4))
def _convert_claripy_bool_ast(self, cond): """ Convert recovered reaching conditions from claripy ASTs to ailment Expressions :return: None """ if isinstance(cond, ailment.Expr.Expression): return cond if cond.op == "BoolS" and claripy.is_true(cond): return cond if cond in self._condition_mapping: return self._condition_mapping[cond] _mapping = { 'Not': lambda cond_: ailment.Expr.UnaryOp(None, 'Not', self._convert_claripy_bool_ast(cond_.args[0])), 'And': lambda cond_: ailment.Expr.BinaryOp(None, 'LogicalAnd', ( self._convert_claripy_bool_ast(cond_.args[0]), self._convert_claripy_bool_ast(cond_.args[1]), )), 'Or': lambda cond_: ailment.Expr.BinaryOp(None, 'LogicalOr', ( self._convert_claripy_bool_ast(cond_.args[0]), self._convert_claripy_bool_ast(cond_.args[1]), )), 'ULE': lambda cond_: ailment.Expr.BinaryOp(None, 'CmpULE', tuple(map(self._convert_claripy_bool_ast, cond_.args)), ), '__le__': lambda cond_: ailment.Expr.BinaryOp(None, 'CmpLE', tuple(map(self._convert_claripy_bool_ast, cond_.args)), ), 'UGT': lambda cond_: ailment.Expr.BinaryOp(None, 'CmpUGT', tuple(map(self._convert_claripy_bool_ast, cond_.args)), ), '__gt__': lambda cond_: ailment.Expr.BinaryOp(None, 'CmpGT', tuple(map(self._convert_claripy_bool_ast, cond_.args)), ), '__eq__': lambda cond_: ailment.Expr.BinaryOp(None, 'CmpEQ', tuple(map(self._convert_claripy_bool_ast, cond_.args)), ), '__ne__': lambda cond_: ailment.Expr.BinaryOp(None, 'CmpNE', tuple(map(self._convert_claripy_bool_ast, cond_.args)), ), '__xor__': lambda cond_: ailment.Expr.BinaryOp(None, 'Xor', tuple(map(self._convert_claripy_bool_ast, cond_.args)), ), 'BVV': lambda cond_: ailment.Expr.Const(None, None, cond_.args[0], cond_.size()), 'BoolV': lambda cond_: ailment.Expr.Const(None, None, True, 1) if cond_.args[0] is True else ailment.Expr.Const(None, None, False, 1), } if cond.op in _mapping: return _mapping[cond.op](cond) raise NotImplementedError(("Condition variable %s has an unsupported operator %s. " "Consider implementing.") % (cond, cond.op))
def test_ite_reverse(): a = claripy.BVS('a', 32) cases = [(a == i, claripy.BVV(i, 32)) for i in range(30)] ast = claripy.ite_cases(cases, -1) ext_cases = list(claripy.reverse_ite_cases(ast)) assert sum(1 if case.op == 'And' else 0 for case, _ in ext_cases) for case, val in ext_cases: if case.op == 'And': assert claripy.is_true(val == -1) else: assert any(case is orig_case and val is orig_val for orig_case, orig_val in cases)
def test_true_false_cache(): claripy.backends._quick_backends.append(claripy.backends.z3) a = claripy.BVS("a_WILL_BE_VIOLATED", 32) c = a == a+1 assert claripy.is_false(c) c.args[1].args = (a, claripy.BVV(0, 32)) assert claripy.is_false(c) assert not claripy.is_true(c) assert not claripy.is_false(a == a) claripy.backends._quick_backends[-1:] = [ ]
def _make_ites(self, seq): # search for a == ^a pairs while True: for node_0 in seq.nodes: if not type(node_0) is CodeNode: continue rcond_0 = node_0.reaching_condition if rcond_0 is None: continue for node_1 in seq.nodes: if not type(node_1) is CodeNode: continue if node_0 is node_1: continue rcond_1 = node_1.reaching_condition if rcond_1 is None: continue cond_ = claripy.simplify(claripy.Not(rcond_0) == rcond_1) if claripy.is_true(cond_): # node_0 and node_1 should be structured using an if-then-else self._make_ite(seq, node_0, node_1) break else: break # make all conditionally-reachable nodes ConditionNodes for i in range(len(seq.nodes)): node = seq.nodes[i] if node.reaching_condition is not None and not claripy.is_true(node.reaching_condition): if isinstance(node.node, ConditionalBreakNode): # Put conditions together and simplify them cond = claripy.And(node.reaching_condition, self._bool_variable_from_ail_condition(node.node.condition)) new_node = CodeNode(ConditionalBreakNode(node.node.addr, cond, node.node.target), None) else: new_node = ConditionNode(node.addr, None, node.reaching_condition, node, None) seq.nodes[i] = new_node
def dbg_repr(self, indent=0): indent_str = indent * " " s = "" if self.reaching_condition is not None and not claripy.is_true(self.reaching_condition): s += (indent_str + "if (<block-missing>; %s)\n" + indent_str + "{\n" + indent_str + " %s\n" + indent_str + "}") % \ (self.reaching_condition, self.node) else: s += indent_str + str(self.node) return s
def run(self, lib_handle, name_addr): if lib_handle.symbolic: raise angr.errors.SimValueError("GetProcAddress called with symbolic library handle %s" % lib_handle) lib_handle = self.state.solver.eval(lib_handle) if lib_handle == 0: obj = self.project.loader.main_object else: for obj in self.project.loader.all_pe_objects: if obj.mapped_base == lib_handle: break else: l.warning("GetProcAddress: invalid library handle %s", lib_handle) return 0 if claripy.is_true(name_addr < 0x10000): # this matches the bogus name specified in the loader... ordinal = self.state.solver.eval(name_addr) name = 'ordinal.%d.%s' % (ordinal, obj.provides) else: name = self.state.mem[name_addr].string.concrete.decode('utf-8') full_name = '%s.%s' % (obj.provides, name) self.procs.add(full_name) sym = obj.get_symbol(name) if sym is None and name.endswith('@'): # There seems to be some mangling parsing being done in the linker? # I don't know what I'm doing for suffix in ['Z', 'XZ']: sym = obj.get_symbol(name + suffix) if sym is not None: name = name + suffix break if sym is None: l.info("GetProcAddress: object %s does not contain %s", obj.provides, name) return 0 sym = sym.resolve_forwarder() if sym is None: l.warning("GetProcAddress: forwarding failed for %s from %s", name, obj.provides) return 0 name = sym.name # fix ordinal names full_name = '%s.%s' % (obj.provides, name) self.procs.add(full_name) l.debug("GetProcAddress: Imported %s (%#x) from %s", name, sym.rebased_addr, obj.provides) return sym.rebased_addr
def _load_bytes(self, addr, max_size, state=None, clemory=None): if not clemory: if state is None: raise SimEngineError('state and clemory cannot both be None in _load_bytes().') if o.ABSTRACT_MEMORY in state.options: # abstract memory clemory = state.memory.regions['global'].memory.mem._memory_backer else: # symbolic memory clemory = state.memory.mem._memory_backer buff, size = "", 0 # Load from the clemory if we can smc = self._support_selfmodifying_code if state: try: p = state.memory.permissions(addr) if p.symbolic: smc = True else: smc = claripy.is_true(p & 2 != 0) except: # pylint: disable=bare-except smc = True # I don't know why this would ever happen, we checked this right? if not smc or not state: try: buff, size = clemory.read_bytes_c(addr) except KeyError: pass # If that didn't work, try to load from the state if size == 0 and state: if addr in state.memory and addr + max_size - 1 in state.memory: buff = state.se.eval(state.memory.load(addr, max_size, inspect=False), cast_to=str) size = max_size else: good_addrs = [] for i in xrange(max_size): if addr + i in state.memory: good_addrs.append(addr + i) else: break buff = ''.join(chr(state.se.eval(state.memory.load(i, 1, inspect=False))) for i in good_addrs) size = len(buff) size = min(max_size, size) return buff, size
def extract(self, state, addr, concrete=False): if self.length is None: out = None last_byte = state.memory.load(addr, 1) addr += 1 while not claripy.is_true(last_byte == 0): out = last_byte if out is None else out.concat(last_byte) last_byte = state.memory.load(addr, 1) addr += 1 else: out = state.memory.load(addr, self.length) if not concrete: return out if out is not None else claripy.BVV(0, 0) else: return state.solver.eval(out, cast_to=bytes) if out is not None else ''
def test_extract_concat_simplify(): a = claripy.BVS("a", 32) assert a[31:0] is a assert a[31:8].concat(a[7:0]) is a # pylint:disable=no-member assert a[31:16].concat(a[15:8], a[7:0]) is a # pylint:disable=no-member assert a[31:24].concat(a[23:16], a[15:8], a[7:0]) is a # pylint:disable=no-member a = claripy.BVS("a", 32) b = a + 100 b_concat = b[31:8].concat(b[7:0]) a100 = a + 100 assert claripy.is_false(b_concat == a100) is False assert list(claripy.Solver().eval(b_concat == a100, 2)) == [ True ] assert b_concat is a100 assert claripy.is_true(b_concat == a100)
def extract(self, state, addr, concrete=False): if self.length is None: out = None last_byte = state.memory.load(addr, 2) addr += 2 while not claripy.is_true(last_byte == 0): out = last_byte if out is None else out.concat(last_byte) last_byte = state.memory.load(addr, 2) addr += 2 else: out = state.memory.load(addr, self.length*2) if out is None: out = claripy.BVV(0, 0) if not concrete: return out else: return u''.join(chr(state.solver.eval(x.reversed if state.arch.memory_endness == 'Iend_LE' else x)) for x in out.chop(16))
def extract(self, state, addr, concrete=False): if self.length is None: out = None last_byte = state.memory.load(addr, 1) # if we try to extract a symbolic string, it's likely that we are going to be trapped in a very large loop. if state.solver.symbolic(last_byte): raise ValueError("Trying to extract a symbolic string at %#x" % state.solver.eval(addr)) addr += 1 while not claripy.is_true(last_byte == 0): out = last_byte if out is None else out.concat(last_byte) last_byte = state.memory.load(addr, 1) addr += 1 else: out = state.memory.load(addr, self.length) if not concrete: return out if out is not None else claripy.BVV(0, 0) else: return state.solver.eval(out, cast_to=bytes) if out is not None else ''
def run(self, lib_handle, name_addr): if lib_handle.symbolic: raise angr.errors.SimValueError( "GetProcAddress called with symbolic library handle %s" % lib_handle) lib_handle = self.state.se.any_int(lib_handle) for obj in self.project.loader.all_pe_objects: if obj.mapped_base == lib_handle: break else: l.warning("GetProcAddress: invalid library handle %s", lib_handle) return 0 if claripy.is_true(name_addr < 0x10000): # this matches the bogus name specified in the loader... ordinal = self.state.se.any_int(name_addr) name = 'ordinal.%d' % ordinal else: name = self.state.mem[name_addr].string.concrete full_name = '%s.%s' % (obj.provides, name) self.procs.add(full_name) sym = obj.get_symbol(name) if sym is None and name.endswith('@'): # There seems to be some mangling parsing being done in the linker? # I don't know what I'm doing for suffix in ['Z', 'XZ']: sym = obj.get_symbol(name + suffix) if sym is not None: name = name + suffix break if sym is None: l.warning("GetProcAddress: object %s does not contain %s", obj.provides, name) return 0 else: name = sym.name # fix ordinal names full_name = '%s.%s' % (obj.provides, name) self.procs.add(full_name) return sym.rebased_addr
def _make_condition_nodes(self, seq): # make all conditionally-reachable nodes ConditionNodes for i in range(len(seq.nodes)): node = seq.nodes[i] if isinstance(node, CodeNode): if isinstance(node.node, SequenceNode): self._make_condition_nodes(node.node) if node.reaching_condition is not None and not claripy.is_true(node.reaching_condition): if isinstance(node.node, ConditionalBreakNode): # Put conditions together and simplify them cond = claripy.And(node.reaching_condition, node.node.condition) new_node = CodeNode(ConditionalBreakNode(node.node.addr, cond, node.node.target), None) else: new_node = ConditionNode(node.addr, None, node.reaching_condition, node, None) seq.nodes[i] = new_node
def extract(self, state, addr, concrete=False): if self.length is None: out = None last_byte = state.memory.load(addr, 2) addr += 2 while not claripy.is_true(last_byte == 0): out = last_byte if out is None else out.concat(last_byte) last_byte = state.memory.load(addr, 2) addr += 2 else: out = state.memory.load(addr, self.length * 2) if out is None: out = claripy.BVV(0, 0) if not concrete: return out else: return u''.join( unichr( state.se.eval(x.reversed if state.arch.memory_endness == 'Iend_LE' else x)) for x in out.chop(16))
def extract(self, state, addr, concrete=False): if self.length is None: out = None last_byte = state.memory.load(addr, 2) # if we try to extract a symbolic string, it's likely that we are going to be trapped in a very large loop. if state.solver.symbolic(last_byte): raise ValueError("Trying to extract a symbolic string at %#x" % state.solver.eval(addr)) addr += 2 while not claripy.is_true(last_byte == 0): out = last_byte if out is None else out.concat(last_byte) last_byte = state.memory.load(addr, 2) addr += 2 else: out = state.memory.load(addr, self.length*2) if out is None: out = claripy.BVV(0, 0) if not concrete: return out else: return u''.join(chr(state.solver.eval(x.reversed if state.arch.memory_endness == 'Iend_LE' else x)) for x in out.chop(16))
def preconstrain_file(self, content, simfile, set_length=False): """ Preconstrain the contents of a file. :param content: The content to preconstrain the file to. Can be a bytestring or a list thereof. :param simfile: The actual simfile to preconstrain """ repair_entry_state_opts = False if o.TRACK_ACTION_HISTORY in self.state.options: repair_entry_state_opts = True self.state.options -= {o.TRACK_ACTION_HISTORY} if set_length: # disable read bounds simfile.has_end = False pos = 0 for write in content: if type(write) is int: write = bytes([write]) data, length, pos = simfile.read(pos, len(write), disable_actions=True, inspect=False, short_reads=False) if not claripy.is_true(length == len(write)): raise AngrError( "Bug in either SimFile or in usage of preconstrainer: couldn't get requested data from file" ) self.preconstrain(write, data) # if the file is a stream, reset its position if simfile.pos is not None: simfile.pos = 0 if set_length: # enable read bounds; size is now maximum size simfile.has_end = True if repair_entry_state_opts: self.state.options |= {o.TRACK_ACTION_HISTORY}
def _convert_claripy_bool_ast(self, cond): """ Convert recovered reaching conditions from claripy ASTs to ailment Expressions :return: None """ if claripy.is_true(cond): return cond if cond in self._condition_mapping: return self._condition_mapping[cond] _mapping = { 'Not': lambda cond_: ailment.Expr.UnaryOp( None, 'Not', self._convert_claripy_bool_ast(cond_.args[0])), } if cond.op in _mapping: return _mapping[cond.op](cond) raise NotImplementedError( ("Condition variable %s has an unsupported operator %s. " "Consider implementing.") % cond.op)
def _handle_LoadG(self, stmt): guard = self._expr(stmt.guard) guard_v = guard.one_value() if claripy.is_true(guard_v): # FIXME: full conversion support if stmt.cvt.find('Ident') < 0: l.warning('Unsupported conversion %s in LoadG.', stmt.cvt) load_expr = pyvex.expr.Load(stmt.end, stmt.cvt_types[1], stmt.addr) wr_tmp_stmt = pyvex.stmt.WrTmp(stmt.dst, load_expr) self._handle_WrTmp(wr_tmp_stmt) elif claripy.is_false(guard_v): wr_tmp_stmt = pyvex.stmt.WrTmp(stmt.dst, stmt.alt) self._handle_WrTmp(wr_tmp_stmt) else: if stmt.cvt.find('Ident') < 0: l.warning('Unsupported conversion %s in LoadG.', stmt.cvt) load_expr = pyvex.expr.Load(stmt.end, stmt.cvt_types[1], stmt.addr) load_expr_v = self._expr(load_expr) alt_v = self._expr(stmt.alt) data = load_expr_v.merge(alt_v) self._handle_WrTmpData(stmt.dst, data)
def _handle_StoreG(self, stmt: pyvex.IRStmt.StoreG): guard = self._expr(stmt.guard) guard_v = guard.one_value() if claripy.is_true(guard_v): addr = self._expr(stmt.addr) if len(addr.values) == 1: addrs = next(iter(addr.values.values())) size = stmt.data.result_size(self.tyenv) // 8 data = self._expr(stmt.data) self._store_core(addrs, size, data) elif claripy.is_false(guard_v): pass else: # guard.data == {True, False} # get current data addr = self._expr(stmt.addr) if len(addr.values) == 1: addrs = next(iter(addr.values.values())) size = stmt.data.result_size(self.tyenv) // 8 data_old = self._load_core(addrs, size, stmt.endness) data = self._expr(stmt.data) self._store_core(addrs, size, data, data_old=data_old)
def _load_bytes(self, addr, max_size, state=None, clemory=None): if not clemory: if state is None: raise SimEngineError('state and clemory cannot both be None in _load_bytes().') if o.ABSTRACT_MEMORY in state.options: # abstract memory clemory = state.memory.regions['global'].memory.mem._memory_backer else: # symbolic memory clemory = state.memory.mem._memory_backer buff, size = b"", 0 # Load from the clemory if we can smc = self._support_selfmodifying_code if state and not smc: try: p = state.memory.permissions(addr) if p.symbolic: smc = True else: smc = claripy.is_true(p & 2 != 0) except: # pylint: disable=bare-except smc = True # I don't know why this would ever happen, we checked this right? if not smc or not state: try: start, backer = next(clemory.backers(addr)) except StopIteration: pass else: if start <= addr: offset = addr - start buff = pyvex.ffi.from_buffer(backer) + offset size = len(backer) - offset # If that didn't work, try to load from the state if size == 0 and state: fallback = True if addr in state.memory and addr + max_size - 1 in state.memory: try: buff = state.solver.eval(state.memory.load(addr, max_size, inspect=False), cast_to=bytes) size = max_size fallback = False except SimError: l.warning("Cannot load bytes at %#x. Fallback to the slow path.", addr) if fallback: buff_lst = [ ] symbolic_warned = False for i in range(max_size): if addr + i in state.memory: try: byte = state.memory.load(addr + i, 1, inspect=False) if byte.symbolic and not symbolic_warned: symbolic_warned = True l.warning("Executing symbolic code at %#x", addr + i) buff_lst.append(state.solver.eval(byte)) except SimError: break else: break buff = bytes(buff_lst) size = len(buff) size = min(max_size, size) return buff, size
def test_rcr(): p = angr.Project(os.path.join(os.path.dirname(__file__), '../../binaries/tests/i386/rcr_test')) result = p.factory.successors(p.factory.entry_state()).successors[0] nose.tools.assert_true(claripy.is_true(result.regs.cl == 8))
def setup_callsite(self, state, ret_addr, args, stack_base=None, alloc_base=None, grow_like_stack=True): """ This function performs the actions of the caller getting ready to jump into a function. :param state: The SimState to operate on :param ret_addr: The address to return to when the called function finishes :param args: The list of arguments that that the called function will see :param stack_base: An optional pointer to use as the top of the stack, circa the function entry point :param alloc_base: An optional pointer to use as the place to put excess argument data :param grow_like_stack: When allocating data at alloc_base, whether to allocate at decreasing addresses The idea here is that you can provide almost any kind of python type in `args` and it'll be translated to a binary format to be placed into simulated memory. Lists (representing arrays) must be entirely elements of the same type and size, while tuples (representing structs) can be elements of any type and size. If you'd like there to be a pointer to a given value, wrap the value in a `PointerWrapper`. Any value that can't fit in a register will be automatically put in a PointerWrapper. If stack_base is not provided, the current stack pointer will be used, and it will be updated. If alloc_base is not provided, the current stack pointer will be used, and it will be updated. You might not like the results if you provide stack_base but not alloc_base. grow_like_stack controls the behavior of allocating data at alloc_base. When data from args needs to be wrapped in a pointer, the pointer needs to point somewhere, so that data is dumped into memory at alloc_base. If you set alloc_base to point to somewhere other than the stack, set grow_like_stack to False so that sequencial allocations happen at increasing addresses. """ allocator = AllocHelper(alloc_base if alloc_base is not None else state.regs.sp, grow_like_stack, self.arch.memory_endness == 'Iend_LE') if self.func_ty is not None: vals = [self._standardize_value(arg, ty, state, allocator.dump) for arg, ty in zip(args, self.func_ty.args)] else: vals = [self._standardize_value(arg, None, state, allocator.dump) for arg in args] arg_session = self.arg_session arg_locs = [None]*len(args) for i, (arg, val) in enumerate(zip(args, vals)): if self.is_fp_value(arg) or \ (self.func_ty is not None and isinstance(self.func_ty.args[i], SimTypeFloat)): arg_locs[i] = arg_session.next_arg(is_fp=True, size=val.length/8) continue if val.length > state.arch.bits or (self.func_ty is None and isinstance(arg, (str, unicode, list, tuple))): vals[i] = allocator.dump(val, state) elif val.length < state.arch.bits: if self.arch.memory_endness == 'Iend_LE': vals[i] = val.concat(claripy.BVV(0, state.arch.bits - val.length)) else: vals[i] = claripy.BVV(0, state.arch.bits - val.length).concat(val) arg_locs[i] = arg_session.next_arg(is_fp=False, size=vals[i].length/8) if alloc_base is None: state.regs.sp = allocator.ptr if stack_base is None: state.regs.sp -= self.stack_space(arg_locs) # handle alignment while claripy.is_true((state.regs.sp + self.STACKARG_SP_DIFF) % self.STACK_ALIGNMENT != 0): state.regs.sp -= 1 for loc, val in zip(arg_locs, vals): loc.set_value(state, val, endness='Iend_BE', stack_base=stack_base) self.return_addr.set_value(state, ret_addr, stack_base=stack_base)
def test_rcr(): p = angr.Project( os.path.join(os.path.dirname(__file__), '..', '..', 'binaries', 'tests', 'i386', 'rcr_test')) result = p.factory.successors(p.factory.entry_state()).successors[0] nose.tools.assert_true(claripy.is_true(result.regs.cl == 8))
def convert_claripy_bool_ast_core(self, cond, memo): if isinstance(cond, ailment.Expr.Expression): return cond if cond.op in {"BoolS", "BoolV"} and claripy.is_true(cond): return ailment.Expr.Const(None, None, True, 1) if cond in self._condition_mapping: return self._condition_mapping[cond] if cond.op in {"BVS", "BoolS" } and cond.args[0] in self._condition_mapping: return self._condition_mapping[cond.args[0]] def _binary_op_reduce(op, args, signed=False): r = None for arg in args: if r is None: r = self.convert_claripy_bool_ast(arg, memo=memo) else: # TODO: Keep track of tags r = ailment.Expr.BinaryOp( None, op, (r, self.convert_claripy_bool_ast(arg, memo=memo)), signed) return r def _unary_op_reduce(op, arg): r = self.convert_claripy_bool_ast(arg, memo=memo) # TODO: Keep track of tags return ailment.Expr.UnaryOp(None, op, r) _mapping = { 'Not': lambda cond_: _unary_op_reduce('Not', cond_.args[0]), 'And': lambda cond_: _binary_op_reduce('LogicalAnd', cond_.args), 'Or': lambda cond_: _binary_op_reduce('LogicalOr', cond_.args), '__le__': lambda cond_: _binary_op_reduce('CmpLE', cond_.args, signed=True), 'SLE': lambda cond_: _binary_op_reduce('CmpLE', cond_.args, signed=True), '__lt__': lambda cond_: _binary_op_reduce('CmpLT', cond_.args, signed=True), 'SLT': lambda cond_: _binary_op_reduce('CmpLT', cond_.args, signed=True), 'UGT': lambda cond_: _binary_op_reduce('CmpGT', cond_.args), 'UGE': lambda cond_: _binary_op_reduce('CmpGE', cond_.args), '__gt__': lambda cond_: _binary_op_reduce('CmpGT', cond_.args, signed=True), '__ge__': lambda cond_: _binary_op_reduce('CmpGE', cond_.args, signed=True), 'SGT': lambda cond_: _binary_op_reduce('CmpGT', cond_.args, signed=True), 'SGE': lambda cond_: _binary_op_reduce('CmpGE', cond_.args, signed=True), 'ULT': lambda cond_: _binary_op_reduce('CmpLT', cond_.args), 'ULE': lambda cond_: _binary_op_reduce('CmpLE', cond_.args), '__eq__': lambda cond_: _binary_op_reduce('CmpEQ', cond_.args), '__ne__': lambda cond_: _binary_op_reduce('CmpNE', cond_.args), '__add__': lambda cond_: _binary_op_reduce('Add', cond_.args, signed=False), '__sub__': lambda cond_: _binary_op_reduce('Sub', cond_.args), '__mul__': lambda cond_: _binary_op_reduce('Mul', cond_.args), '__xor__': lambda cond_: _binary_op_reduce('Xor', cond_.args), '__or__': lambda cond_: _binary_op_reduce('Or', cond_.args, signed=False), '__and__': lambda cond_: _binary_op_reduce('And', cond_.args), '__lshift__': lambda cond_: _binary_op_reduce('Shl', cond_.args), '__rshift__': lambda cond_: _binary_op_reduce('Sar', cond_.args), '__floordiv__': lambda cond_: _binary_op_reduce('Div', cond_.args), 'LShR': lambda cond_: _binary_op_reduce('Shr', cond_.args), 'BVV': lambda cond_: ailment.Expr.Const(None, None, cond_.args[0], cond_.size()), 'BoolV': lambda cond_: ailment.Expr.Const(None, None, True, 1) if cond_.args[0] is True else ailment.Expr.Const( None, None, False, 1), 'Extract': lambda cond_: self._convert_extract(*cond_.args, memo=memo), } if cond.op in _mapping: return _mapping[cond.op](cond) raise NotImplementedError( ("Condition variable %s has an unsupported operator %s. " "Consider implementing.") % (cond, cond.op))
def __eq__(self, other): return self.name == other.name and self.source == other.source and claripy.is_true( self.offset == other.offset)
def _load_bytes(self, addr, max_size, state=None, clemory=None): if not clemory: if state is None: raise SimEngineError( 'state and clemory cannot both be None in _load_bytes().') if o.ABSTRACT_MEMORY in state.options: # abstract memory clemory = state.memory.regions[ 'global'].memory.mem._memory_backer else: # symbolic memory clemory = state.memory.mem._memory_backer buff, size = "", 0 # Load from the clemory if we can smc = self._support_selfmodifying_code if state: try: p = state.memory.permissions(addr) if p.symbolic: smc = True else: smc = claripy.is_true(p & 2 != 0) except: # pylint: disable=bare-except smc = True # I don't know why this would ever happen, we checked this right? if not smc or not state: try: buff, size = clemory.read_bytes_c(addr) except KeyError: pass # If that didn't work, try to load from the state if size == 0 and state: fallback = True if addr in state.memory and addr + max_size - 1 in state.memory: try: buff = state.se.eval(state.memory.load(addr, max_size, inspect=False), cast_to=str) size = max_size fallback = False except SimError: l.warning( "Cannot load bytes at %#x. Fallback to the slow path.", addr) if fallback: buff_lst = [] for i in xrange(max_size): if addr + i in state.memory: try: buff_lst.append( chr( state.se.eval( state.memory.load(addr + i, 1, inspect=False)))) except SimError: break else: break buff = ''.join(buff_lst) size = len(buff) size = min(max_size, size) return buff, size
def convert_claripy_bool_ast(self, cond): """ Convert recovered reaching conditions from claripy ASTs to ailment Expressions :return: None """ if isinstance(cond, ailment.Expr.Expression): return cond if cond.op == "BoolS" and claripy.is_true(cond): return cond if cond in self._condition_mapping: return self._condition_mapping[cond] def _binary_op_reduce(op, args, signed=False): r = None for arg in args: if r is None: r = self.convert_claripy_bool_ast(arg) else: r = ailment.Expr.BinaryOp( None, op, (r, self.convert_claripy_bool_ast(arg)), signed) return r _mapping = { 'Not': lambda cond_: ailment.Expr.UnaryOp( None, 'Not', self.convert_claripy_bool_ast(cond_.args[0])), 'And': lambda cond_: _binary_op_reduce('LogicalAnd', cond_.args), 'Or': lambda cond_: _binary_op_reduce('LogicalOr', cond_.args), '__le__': lambda cond_: ailment.Expr.BinaryOp( None, 'CmpLE', tuple(map(self.convert_claripy_bool_ast, cond_.args)), True), 'SLE': lambda cond_: ailment.Expr.BinaryOp( None, 'CmpLE', tuple(map(self.convert_claripy_bool_ast, cond_.args)), True), '__lt__': lambda cond_: ailment.Expr.BinaryOp( None, 'CmpLT', tuple(map(self.convert_claripy_bool_ast, cond_.args)), True), 'SLT': lambda cond_: ailment.Expr.BinaryOp( None, 'CmpLT', tuple(map(self.convert_claripy_bool_ast, cond_.args)), True), 'UGT': lambda cond_: ailment.Expr.BinaryOp( None, 'CmpGT', tuple(map(self.convert_claripy_bool_ast, cond_.args)), False), 'UGE': lambda cond_: ailment.Expr.BinaryOp( None, 'CmpGE', tuple(map(self.convert_claripy_bool_ast, cond_.args)), False), '__gt__': lambda cond_: ailment.Expr.BinaryOp( None, 'CmpGT', tuple(map(self.convert_claripy_bool_ast, cond_.args)), True), '__ge__': lambda cond_: ailment.Expr.BinaryOp( None, 'CmpGE', tuple(map(self.convert_claripy_bool_ast, cond_.args)), True), 'SGT': lambda cond_: ailment.Expr.BinaryOp( None, 'CmpGT', tuple(map(self.convert_claripy_bool_ast, cond_.args)), True), 'SGE': lambda cond_: ailment.Expr.BinaryOp( None, 'CmpGE', tuple(map(self.convert_claripy_bool_ast, cond_.args)), True), 'ULT': lambda cond_: ailment.Expr.BinaryOp( None, 'CmpLT', tuple(map(self.convert_claripy_bool_ast, cond_.args)), False), 'ULE': lambda cond_: ailment.Expr.BinaryOp( None, 'CmpLE', tuple(map(self.convert_claripy_bool_ast, cond_.args)), False), '__eq__': lambda cond_: ailment.Expr.BinaryOp( None, 'CmpEQ', tuple(map(self.convert_claripy_bool_ast, cond_.args)), False), '__ne__': lambda cond_: ailment.Expr.BinaryOp( None, 'CmpNE', tuple(map(self.convert_claripy_bool_ast, cond_.args)), False), '__add__': lambda cond_: _binary_op_reduce('Add', cond_.args, signed=False), '__sub__': lambda cond_: ailment.Expr.BinaryOp( None, 'Sub', tuple(map(self.convert_claripy_bool_ast, cond_.args)), False), '__mul__': lambda cond_: ailment.Expr.BinaryOp( None, 'Mul', tuple(map(self.convert_claripy_bool_ast, cond_.args)), False), '__xor__': lambda cond_: ailment.Expr.BinaryOp( None, 'Xor', tuple(map(self.convert_claripy_bool_ast, cond_.args)), False), '__or__': lambda cond_: _binary_op_reduce('Or', cond_.args, signed=False), '__and__': lambda cond_: ailment.Expr.BinaryOp( None, 'And', tuple(map(self.convert_claripy_bool_ast, cond_.args)), False), '__lshift__': lambda cond_: ailment.Expr.BinaryOp( None, 'Shl', tuple(map(self.convert_claripy_bool_ast, cond_.args)), False), '__rshift__': lambda cond_: ailment.Expr.BinaryOp( None, 'Sar', tuple(map(self.convert_claripy_bool_ast, cond_.args)), False), 'LShR': lambda cond_: ailment.Expr.BinaryOp( None, 'Shr', tuple(map(self.convert_claripy_bool_ast, cond_.args)), False), 'BVV': lambda cond_: ailment.Expr.Const(None, None, cond_.args[0], cond_.size()), 'BoolV': lambda cond_: ailment.Expr.Const(None, None, True, 1) if cond_.args[0] is True else ailment.Expr.Const( None, None, False, 1), } if cond.op in _mapping: return _mapping[cond.op](cond) raise NotImplementedError( ("Condition variable %s has an unsupported operator %s. " "Consider implementing.") % (cond, cond.op))
def _convert_claripy_bool_ast(self, cond): """ Convert recovered reaching conditions from claripy ASTs to ailment Expressions :return: None """ if isinstance(cond, ailment.Expr.Expression): return cond if cond.op == "BoolS" and claripy.is_true(cond): return cond if cond in self._condition_mapping: return self._condition_mapping[cond] _mapping = { 'Not': lambda cond_: ailment.Expr.UnaryOp(None, 'Not', self._convert_claripy_bool_ast(cond_.args[0])), 'And': lambda cond_: ailment.Expr.BinaryOp(None, 'LogicalAnd', ( self._convert_claripy_bool_ast(cond_.args[0]), self._convert_claripy_bool_ast(cond_.args[1]), )), 'Or': lambda cond_: ailment.Expr.BinaryOp(None, 'LogicalOr', ( self._convert_claripy_bool_ast(cond_.args[0]), self._convert_claripy_bool_ast(cond_.args[1]), )), 'ULE': lambda cond_: ailment.Expr.BinaryOp(None, 'CmpULE', tuple(map(self._convert_claripy_bool_ast, cond_.args)), ), '__le__': lambda cond_: ailment.Expr.BinaryOp(None, 'CmpLE', tuple(map(self._convert_claripy_bool_ast, cond_.args)), ), '__lt__': lambda cond_: ailment.Expr.BinaryOp(None, 'CmpLT', tuple(map(self._convert_claripy_bool_ast, cond_.args)), ), 'UGT': lambda cond_: ailment.Expr.BinaryOp(None, 'CmpUGT', tuple(map(self._convert_claripy_bool_ast, cond_.args)), ), '__gt__': lambda cond_: ailment.Expr.BinaryOp(None, 'CmpGT', tuple(map(self._convert_claripy_bool_ast, cond_.args)), ), '__eq__': lambda cond_: ailment.Expr.BinaryOp(None, 'CmpEQ', tuple(map(self._convert_claripy_bool_ast, cond_.args)), ), '__ne__': lambda cond_: ailment.Expr.BinaryOp(None, 'CmpNE', tuple(map(self._convert_claripy_bool_ast, cond_.args)), ), '__add__': lambda cond_: ailment.Expr.BinaryOp(None, 'Add', tuple(map(self._convert_claripy_bool_ast, cond_.args)), ), '__xor__': lambda cond_: ailment.Expr.BinaryOp(None, 'Xor', tuple(map(self._convert_claripy_bool_ast, cond_.args)), ), '__and__': lambda cond_: ailment.Expr.BinaryOp(None, 'And', tuple(map(self._convert_claripy_bool_ast, cond_.args)), ), 'LShR': lambda cond_: ailment.Expr.BinaryOp(None, 'Shr', tuple(map(self._convert_claripy_bool_ast, cond_.args)), ), 'BVV': lambda cond_: ailment.Expr.Const(None, None, cond_.args[0], cond_.size()), 'BoolV': lambda cond_: ailment.Expr.Const(None, None, True, 1) if cond_.args[0] is True else ailment.Expr.Const(None, None, False, 1), } if cond.op in _mapping: return _mapping[cond.op](cond) raise NotImplementedError(("Condition variable %s has an unsupported operator %s. " "Consider implementing.") % (cond, cond.op))
def _load_bytes(self, addr, max_size, state=None, clemory=None): if not clemory: if state is None: raise SimEngineError('state and clemory cannot both be None in _load_bytes().') if o.ABSTRACT_MEMORY in state.options: # abstract memory clemory = state.memory.regions['global'].memory.mem._memory_backer else: # symbolic memory clemory = state.memory.mem._memory_backer buff, size = b"", 0 # Load from the clemory if we can smc = self._support_selfmodifying_code if state: try: p = state.memory.permissions(addr) if p.symbolic: smc = True else: smc = claripy.is_true(p & 2 != 0) except: # pylint: disable=bare-except smc = True # I don't know why this would ever happen, we checked this right? if not smc or not state: try: start, backer = next(clemory.backers(addr)) except StopIteration: pass else: if start <= addr: offset = addr - start buff = pyvex.ffi.from_buffer(backer) + offset size = len(backer) - offset # If that didn't work, try to load from the state if size == 0 and state: fallback = True if addr in state.memory and addr + max_size - 1 in state.memory: try: buff = state.solver.eval(state.memory.load(addr, max_size, inspect=False), cast_to=bytes) size = max_size fallback = False except SimError: l.warning("Cannot load bytes at %#x. Fallback to the slow path.", addr) if fallback: buff_lst = [ ] for i in range(max_size): if addr + i in state.memory: try: buff_lst.append(state.solver.eval(state.memory.load(addr + i, 1, inspect=False))) except SimError: break else: break buff = bytes(buff_lst) size = len(buff) size = min(max_size, size) return buff, size
def test_wrapped_intervals(): #SI = claripy.StridedInterval # Disable the use of DiscreteStridedIntervalSet claripy.vsa.strided_interval.allow_dsis = False # # Signedness/unsignedness conversion # si1 = claripy.SI(bits=32, stride=1, lower_bound=0, upper_bound=0xffffffff) nose.tools.assert_equal(si1.model._signed_bounds(), [ (0x0, 0x7fffffff), (-0x80000000, -0x1) ]) nose.tools.assert_equal(si1.model._unsigned_bounds(), [ (0x0, 0xffffffff) ]) # # Addition # # Plain addition si1 = claripy.SI(bits=32, stride=1, lower_bound=-1, upper_bound=1) si2 = claripy.SI(bits=32, stride=1, lower_bound=-1, upper_bound=1) si3 = claripy.SI(bits=32, stride=1, lower_bound=-2, upper_bound=2) nose.tools.assert_true((si1 + si2).identical(si3)) si4 = claripy.SI(bits=32, stride=1, lower_bound=0xfffffffe, upper_bound=2) nose.tools.assert_true((si1 + si2).identical(si4)) si5 = claripy.SI(bits=32, stride=1, lower_bound=2, upper_bound=-2) nose.tools.assert_false((si1 + si2).identical(si5)) # Addition with overflowing cardinality si1 = claripy.SI(bits=8, stride=1, lower_bound=0, upper_bound=0xfe) si2 = claripy.SI(bits=8, stride=1, lower_bound=0xfe, upper_bound=0xff) nose.tools.assert_true((si1 + si2).model.is_top) # Addition that shouldn't get a TOP si1 = claripy.SI(bits=8, stride=1, lower_bound=0, upper_bound=0xfe) si2 = claripy.SI(bits=8, stride=1, lower_bound=0, upper_bound=0) nose.tools.assert_false((si1 + si2).model.is_top) # # Subtraction # si1 = claripy.SI(bits=8, stride=1, lower_bound=10, upper_bound=15) si2 = claripy.SI(bits=8, stride=1, lower_bound=11, upper_bound=12) si3 = claripy.SI(bits=8, stride=1, lower_bound=-2, upper_bound=4) nose.tools.assert_true((si1 - si2).identical(si3)) # # Multiplication # # integer multiplication si1 = claripy.SI(bits=32, to_conv=0xffff) si2 = claripy.SI(bits=32, to_conv=0x10000) si3 = claripy.SI(bits=32, to_conv=0xffff0000) nose.tools.assert_true((si1 * si2).identical(si3)) # intervals multiplication si1 = claripy.SI(bits=32, stride=1, lower_bound=10, upper_bound=15) si2 = claripy.SI(bits=32, stride=1, lower_bound=20, upper_bound=30) si3 = claripy.SI(bits=32, stride=1, lower_bound=200, upper_bound=450) nose.tools.assert_true((si1 * si2).identical(si3)) # # Division # # integer division si1 = claripy.SI(bits=32, to_conv=10) si2 = claripy.SI(bits=32, to_conv=5) si3 = claripy.SI(bits=32, to_conv=2) nose.tools.assert_true((si1 / si2).identical(si3)) si3 = claripy.SI(bits=32, to_conv=0) nose.tools.assert_true((si2 / si1).identical(si3)) # intervals division si1 = claripy.SI(bits=32, stride=1, lower_bound=10, upper_bound=100) si2 = claripy.SI(bits=32, stride=1, lower_bound=10, upper_bound=20) si3 = claripy.SI(bits=32, stride=1, lower_bound=0, upper_bound=10) nose.tools.assert_true((si1 / si2).identical(si3)) # # Comparisons # # -1 == 0xff si1 = claripy.SI(bits=8, stride=1, lower_bound=-1, upper_bound=-1) si2 = claripy.SI(bits=8, stride=1, lower_bound=0xff, upper_bound=0xff) nose.tools.assert_true(claripy.is_true(si1 == si2)) # -2 != 0xff si1 = claripy.SI(bits=8, stride=1, lower_bound=-2, upper_bound=-2) si2 = claripy.SI(bits=8, stride=1, lower_bound=0xff, upper_bound=0xff) nose.tools.assert_true(claripy.is_true(si1 != si2)) # [-2, -1] < [1, 2] (signed arithmetic) si1 = claripy.SI(bits=8, stride=1, lower_bound=1, upper_bound=2) si2 = claripy.SI(bits=8, stride=1, lower_bound=-2, upper_bound=-1) nose.tools.assert_true(claripy.is_true(si2.SLT(si1))) # [-2, -1] <= [1, 2] (signed arithmetic) nose.tools.assert_true(claripy.is_true(si2.SLE(si1))) # [0xfe, 0xff] > [1, 2] (unsigned arithmetic) nose.tools.assert_true(claripy.is_true(si2.UGT(si1))) # [0xfe, 0xff] >= [1, 2] (unsigned arithmetic) nose.tools.assert_true(claripy.is_true(si2.UGE(si1)))
def get_patches(self): cfg = self.patcher.cfg patches = [] pnum = 0 used_spec_chars = [] for func, (func_name, func_obj) in self.ident.matches.items(): if func_name not in PRINTF_VARIANTS: continue if func_obj.format_spec_char is None: l.warning("func_obj.format_spec_char is None") continue fmt_arg_pos = PRINTF_VARIANTS[func_name] callers = set.union( set(), *(cfg.get_predecessors(node) for node in cfg.get_all_nodes(func.addr))) handled_addrs = set() func_to_cfg = {} for caller in callers: if caller.addr in handled_addrs: continue try: args, _ = self.ident.get_call_args(func, caller.addr) except KeyError: continue fmt_str = args[fmt_arg_pos] if not claripy.is_true(claripy.Or(*(claripy.And(seg.min_addr <= fmt_str, fmt_str <= seg.max_addr)\ for seg in self.ro_segments))): # we bad break handled_addrs.add(caller.addr) else: # patch not necessary for this function continue pnum += 1 # we need this to ensure always different labels used_spec_chars.append(func_obj.format_spec_char) check = """ ; is the address not in RO memory? cmp dword [esp+{stack_offset}], {{max_ro_addr}} jbe _end_printfcheck_%d ; int 3 ; is the address in the flag page? cmp dword [esp+{stack_offset}], {flag_page} jb _check_for_percent_%d cmp dword [esp+{stack_offset}], {flag_page_almost_end} ja _check_for_percent_%d ; they're trying to read from the flag page! f**k them. jmp 0x41414141 _check_for_percent_%d: push esi ; = pointer to string mov esi, [esp+{stack_offset_2}] push eax xor eax, eax; hash _loop_printfcheck_%d: cmp byte [esi], 0 je _final_check_printfcheck_%d xor al, byte[esi] cmp byte[esi], {format_spec_char} jne _continue_printfcheck_%d mov ah, 0x1 _continue_printfcheck_%d: inc esi jmp _loop_printfcheck_%d _final_check_printfcheck_%d: test ah, ah je _restore_printfcheck_%d test al, al ; avoid al==0 as we do in the hash algorithm jne _do_not_inc_%d inc al _do_not_inc_%d: ; the dynamic hash will always be bigger than 0, the hash list is null terminated mov esi, {{hash_list_{format_spec_char}}} _hash_check_loop_%d: cmp byte[esi], 0 ; the end of the list has been reached je 0x41414141 cmp byte[esi], al ; esi points to the hash list je _restore_printfcheck_%d inc esi jmp _hash_check_loop_%d _restore_printfcheck_%d: pop eax pop esi _end_printfcheck_%d: """.format( stack_offset=(fmt_arg_pos + 1) * 4, stack_offset_2=(fmt_arg_pos + 2) * 4, flag_page=FLAG_PAGE, flag_page_almost_end=FLAG_PAGE + 0xffc, format_spec_char=ord(func_obj.format_spec_char), ) % tuple([pnum] * 18) patches.append( InsertCodePatch(func.addr, check, priority=250, name="noflagprintf_%d" % pnum)) l.info("function at %#08x protected" % func.addr) if patches: max_ro_addr = max(seg.max_addr for seg in self.ro_segments) patches.append(AddLabelPatch(max_ro_addr, name="max_ro_addr")) # print repr(self.hash_dict) for fspec in set(used_spec_chars): hash_list = b"".join(self.hash_dict[fspec]) + b"\x00" patches.append( AddRODataPatch(hash_list, name="hash_list_{format_spec_char}".format( format_spec_char=ord(fspec)))) # print "\n".join(map(str,patches)) return patches
ss.add(z == itz) ss.add(itz != 0) nose.tools.assert_equal(ss.eval(y/x, 100), ( 2, )) nose.tools.assert_equal(sorted(ss.eval(x, 100)), [ 1, 10, 100 ]) nose.tools.assert_equal(sorted(ss.eval(y, 100)), [ 2, 20, 200 ]) def test_ite_reverse(): a = claripy.BVS('a', 32) cases = [(a == i, claripy.BVV(i, 32)) for i in range(30)] ast = claripy.ite_cases(cases, -1) ext_cases = list(claripy.reverse_ite_cases(ast)) assert sum(1 if case.op == 'And' else 0 for case, _ in ext_cases) for case, val in ext_cases: if case.op == 'And': assert claripy.is_true(val == -1) else: assert any(case is orig_case and val is orig_val for orig_case, orig_val in cases) def test_bool(): bc = claripy.backends.concrete a = claripy.And(*[False, False, True]) nose.tools.assert_equal(bc.convert(a), False) a = claripy.And(*[True, True, True]) nose.tools.assert_equal(bc.convert(a), True) o = claripy.Or(*[False, False, True]) nose.tools.assert_equal(bc.convert(o), True) o = claripy.Or(*[False, False, False]) nose.tools.assert_equal(bc.convert(o), False)
def _search_value(self): if self._arm: armins = self._string_to_insn(self._insbytes) if not self._arm64: if not self._armthumb: # ARM instructions if armins & 0x0C000000 == 0x04000000: # LDR thoughtval = armins & 0xFFF if thoughtval != self.value: raise ValueNotFoundError imm12 = self._imm(12) self.patch_value_expression = imm12.zero_extend(self.bits-12) self.patch_bytes_expression = claripy.Concat( BVV(armins >> 12, 20), imm12 ) self._test_values = (1, 0xfff) elif armins & 0x0E000000 == 0x02000000: # Data processing w/ immediate shiftval = (armins & 0xF00) >> 7 thoughtval = armins & 0xFF thoughtval = ror(thoughtval, shiftval, 32) if thoughtval != self.value: raise ValueNotFoundError shift = self._imm(4, 'shift') imm8 = self._imm(8) self.patch_value_expression = claripy.RotateRight( imm8.zero_extend(32-8), shift.zero_extend(32-4)*2 ) self.patch_bytes_expression = claripy.Concat( BVV(armins >> 12, 20), shift, imm8 ) self._test_values = (1, 0xff, 0xff000000) elif armins & 0x0E400090 == 0x00400090: # LDRH thoughtval = (armins & 0xF) | ((armins & 0xF00) >> 4) if thoughtval != self.value: raise ValueNotFoundError hinib = self._imm(4, 'hinib') lonib = self._imm(4, 'lonib') self.patch_value_expression = claripy.Concat(hinib, lonib).zero_extend(self.bits-8) self.patch_bytes_expression = claripy.Concat( BVV(armins >> 12, 20), hinib, BVV((armins >> 4) & 0xF, 4), lonib ) self._test_values = (1, 0xff) elif armins & 0x0E000000 == 0x0C000000: # Coprocessor data transfer # i.e. FLD/FST thoughtval = armins & 0xFF thoughtval *= 4 if thoughtval != self.value: raise ValueNotFoundError imm8 = self._imm(8) self.patch_value_expression = imm8.zero_extend(self.bits-8) << 2 self.patch_bytes_expression = claripy.Concat( BVV(armins >> 8, 24), imm8 ) self._test_values = (4, 0x3fc) else: raise ValueNotFoundError else: # THUMB instructions # https://ece.uwaterloo.ca/~ece222/ARM/ARM7-TDMI-manual-pt3.pdf if self._inslen == 2: # 16 bit instructions if armins & 0xF000 in (0x9000, 0xA000): # SP-relative LDR/STR, also SP-addiition # page 26, 28 # unsigned offsets only, 10 bit imm stored w/o last two bits thoughtval = armins & 0xFF thoughtval *= 4 if thoughtval != self.value: raise ValueNotFoundError imm8 = self._imm(8) self.patch_value_expression = imm8.zero_extend(self.bits-8) << 2 self.patch_bytes_expression = claripy.Concat( BVV(armins >> 8, 8), imm8 ) self._test_values = (4, 0x3fc) elif armins & 0xFF00 == 0xB000: # Add/sub offset to SP # page 30 # uses sign bit, 9 bit imm stored w/o last two bits thoughtval = armins & 0x7F thoughtval *= 4 if thoughtval != self.value: raise ValueNotFoundError imm7 = self._imm(7) self.patch_value_expression = imm7.zero_extend(self.bits-7) << 2 self.patch_bytes_expression = claripy.Concat( BVV(armins >> 7, 9), imm7 ) self._test_values = (4, 0x1fc) elif armins & 0xFC00 == 0x1C00: # ADD/SUB (immediate format) # page 7 # uses sign bit, 3 bit immediate thoughtval = (armins & 0x01C0) >> 6 if thoughtval != self.value: raise ValueNotFoundError imm3 = self._imm(3) self.patch_value_expression = imm3.zero_extend(self.bits-3) self.patch_bytes_expression = claripy.Concat( BVV(armins >> 9, 7), imm3, BVV(armins & 0x3F, 6) ) self._test_values = (1, 7) elif armins & 0xE000 == 0x2000: # Move/Compare/Add/Subtract immediate # page 9 # Unsigned 8 bit immediate thoughtval = armins & 0xFF if thoughtval != self.value: raise ValueNotFoundError imm8 = self._imm(8) self.patch_value_expression = imm8.zero_extend(self.bits-8) self.patch_bytes_expression = claripy.Concat( BVV(armins >> 8, 8), imm8 ) self._test_values = (1, 0xff) elif armins & 0xF000 == 0x6000: # Register-relative LDR/STR # page 22 # unsigned 7 bit imm stored w/o last two bits thoughtval = ((armins >> 6) & 0x1F) << 2 if thoughtval != self.value: raise ValueNotFoundError imm5 = self._imm(5) self.patch_value_expression = imm5.zero_extend(self.bits-5) << 2 self.patch_bytes_expression = claripy.Concat( BVV(armins >> 11, 5), imm5, BVV(armins & 0x3F, 6) ) self._test_values = (4, 0x7c) elif armins & 0xF000 == 0x7000: # Register-relative LDRB/STRB # page 22 # unsigned 5 bit imm thoughtval = (armins >> 6) & 0x1F if thoughtval != self.value: raise ValueNotFoundError imm5 = self._imm(5) self.patch_value_expression = imm5.zero_extend(self.bits-5) self.patch_bytes_expression = claripy.Concat( BVV(armins >> 11, 5), imm5, BVV(armins & 0x3F, 6) ) self._test_values = (1, 0x1f) else: raise ValueNotFoundError elif self._inslen == 4: # 32 bit instructions # http://read.pudn.com/downloads159/doc/709030/Thumb-2SupplementReferenceManual.pdf if armins & 0xFE1F0000 == 0xF81F0000 or \ armins & 0xFE800000 == 0xF8800000: # Load/Store # page 66, formats 1-2 # imm12 with designated sign bit thoughtval = armins & 0xFFF if thoughtval != self.value: raise ValueNotFoundError imm12 = self._imm(12) self.patch_value_expression = imm12.zero_extend(self.bits-12) self.patch_bytes_expression = claripy.Concat( BVV(armins >> 12, 20), imm12 ) self._test_values = (1, 0xfff) elif armins & 0xFE800900 == 0xF8000800: # Load/Store # page 66, formats 3-4 # imm8 with designated sign bit thoughtval = armins & 0xFF if thoughtval != self.value: raise ValueNotFoundError imm8 = self._imm(8) self.patch_value_expression = imm8.zero_extend(self.bits-8) self.patch_bytes_expression = claripy.Concat( BVV(armins >> 8, 24), imm8 ) self._test_values = (1, 0xff) elif armins & 0xFE800900 == 0xF8000900: # Load/Store # page 66, formats 5-6 # imm8, sign extended thoughtval = armins & 0x7F if armins & 0x80 == 0x80: thoughtval = (thoughtval ^ 0x7F) + 1 if thoughtval != self.value: raise ValueNotFoundError imm8 = self._imm(8) self.patch_value_expression = imm8.sign_extend(self.bits-8) self.patch_bytes_expression = claripy.Concat( BVV(armins >> 8, 24), imm8 ) self._test_values = (-0x80, 0x7f) elif armins & 0xFB408000 == 0xF2000000: # Add/Sub # page 53, format 2 # 12 bit immediate split into 3 bitfields thoughtval = armins & 0xFF thoughtval |= (armins & 0x7000) >> 4 thoughtval |= (armins & 0x04000000) >> 15 if thoughtval != self.value: raise ValueNotFoundError imm8 = self._imm(8) imm3 = self._imm(3) imm1 = self._imm(1) self.patch_value_expression = claripy.Concat( imm1, imm3, imm8 ).zero_extend(self.bits-12) self.patch_bytes_expression = claripy.Concat( BVV(armins >> 27, 5), imm1, BVV((armins & 0x03FF8000) >> 15, 11), imm3, BVV((armins & 0xF00) >> 8, 4), imm8 ) self._test_values = (1, 0xfff) elif armins & 0xFB408000 == 0xF2400000: # Move # page 53, format 3 # 16 bit immediate split into 4 bitfields thoughtval = armins & 0xFF thoughtval |= (armins & 0x7000) >> 4 thoughtval |= (armins & 0x04000000) >> 15 thoughtval |= (armins & 0xF0000) >> 4 if thoughtval != self.value: raise ValueNotFoundError imm8 = self._imm(8) imm3 = self._imm(3) imm1 = self._imm(1) imm4 = self._imm(1) self.patch_value_expression = claripy.Concat( imm4, imm1, imm3, imm8 ).zero_extend(self.bits-12) self.patch_bytes_expression = claripy.Concat( BVV(armins >> 27, 5), imm1, BVV((armins & 0x03F00000) >> 20, 6), imm4, BVV((armins & 0x00008000) >> 15, 1), imm3, BVV((armins & 0xF00) >> 8, 4), imm8 ) self._test_values = (1, 0xffff) elif armins & 0xFA008000 == 0xF0000000: # Data processing, modified 12 bit imm, aka EVIL # page 53 # wow. just. wow. imm12 = armins & 0xFF imm12 |= (armins & 0x7000) >> 4 imm12 |= (armins & 0x04000000) >> 15 # decoding algorithm from page 93 if imm12 & 0xC00 == 0: if imm12 & 0x300 == 0: thoughtval = imm12 elif imm12 & 0x300 == 0x100: thoughtval = imm12 & 0xFF thoughtval |= thoughtval << 16 elif imm12 & 0x300 == 0x200: thoughtval = (imm12 & 0xFF) << 8 thoughtval |= thoughtval << 16 elif imm12 & 0x300 == 0x300: thoughtval = imm12 & 0xFF thoughtval |= thoughtval << 8 thoughtval |= thoughtval << 16 else: assert False else: thoughtval = ror(0x80 | (imm12 & 0x7F), imm12 >> 7, 32) if thoughtval != self.value: raise ValueNotFoundError imm12 = self._imm(12) ITE = claripy.If CAT = claripy.Concat ROR = claripy.RotateRight imm8 = imm12[7:0] imm7 = imm12[6:0] imm3 = imm12[10:8] imm1 = imm12[11] zero = BVV(0, 8) bit = BVV(1, 1) monster = ITE(imm12[11:10] == 0, ITE(imm12[9] == 0, ITE(imm12[8] == 0, imm12[7:0].zero_extend(32-8), CAT(zero, imm8, zero, imm8) ), ITE(imm12[8] == 0, CAT(imm8, zero, imm8, zero), CAT(imm8, imm8, imm8, imm8) ) ), ROR(CAT(bit, imm7).zero_extend(32-8), imm12[11:7].zero_extend(32-5) ) ) self.patch_value_expression = monster self.patch_bytes_expression = claripy.Concat( BVV(armins >> 27, 5), imm1, BVV((armins & 0x03FF8000) >> 15, 11), imm3, BVV((armins & 0xF00) >> 8, 4), imm8 ) self._test_values = (0xff00ff00, 0x00ff00ff, 0xffffffff, 0xff, 0xff000000) else: raise ValueNotFoundError else: raise FidgetUnsupportedError("You found a THUMB instruction longer than 32 bits??") else: self.bit_length = 64 # aarch64 instructions # can't find a reference doc?????? I'm pulling these from VEX, guest_arm64_toIR.c if armins & 0x7f800000 in (0x28800000, 0x29800000, 0x29000000): # LDP/SDP # line 4791 # 7 bit immediate signed offset, scaled by load size (from MSB) shift = 3 if armins & 0x80000000 else 2 simm7 = (armins & 0x3f8000) >> 15 simm7 = resign_int(simm7, 7) simm7 <<= shift if simm7 != self.value: raise ValueNotFoundError imm7 = self._imm(7) self.patch_value_expression = imm7.sign_extend(self.bits-7) << shift self.patch_bytes_expression = claripy.Concat( BVV((armins & 0xffc00000) >> 22, 10), imm7, BVV(armins & 0x7fff, 15) ) self._test_values = (-0x40 << shift, 0x3f << shift) elif (armins & 0x3f800000 == 0x39000000) or \ (armins & 0x3f800000 == 0x39800000 and \ ((armins >> 30) | ((armins >> 22) & 1)) in (4, 2, 3, 0, 1)): # LDR/STR, LDRS # line 4639, 5008 # 12 bit immediate unsigned offset, scaled by load size (from 2 MSB) shift = (armins & 0xc0000000) >> 30 offs = (armins & 0x3ffc00) >> 10 offs <<= shift if offs != self.value: raise ValueNotFoundError imm12 = self._imm(12) self.patch_value_expression = imm12.zero_extend(self.bits-12) << shift self.patch_bytes_expression = claripy.Concat( BVV((armins & 0xffc00000) >> 22, 10), imm12, BVV(armins & 0x3ff, 10) ) self._test_values = (1 << shift, 0xfff << shift) elif armins & 0x1f000000 == 0x11000000: # ADD/SUB imm # line 2403 # 12 bit shifted unsigned immediate if not armins & 0x80000000: self.bit_length = 32 shift = (armins >> 22) & 3 imm12 = (armins >> 10) & 0xfff imm12 <<= 12*shift if imm12 != self.value: raise ValueNotFoundError shift = self._imm(1, 'shift') imm12 = self._imm(12) shift_full = shift.zero_extend(self.bits-1)*12 self.patch_value_expression = imm12.zero_extend(self.bits-12) << shift_full self.patch_bytes_expression = claripy.Concat( BVV(armins >> 24, 8), BVV(0, 1), shift, imm12, BVV(armins & 0x3ff, 10) ) self._test_values = (1, 0xfff, 0xfff000) elif armins & 0x3fa00000 == 0x38000000: # LDUR/STUR # Line 4680 # 9 bit signed immediate offset imm9 = (armins >> 12) & 0x1ff imm9 = resign_int(imm9, 9) if imm9 != self.value: raise ValueNotFoundError imm9 = self._imm(9) self.patch_value_expression = imm9.sign_extend(self.bits-9) self.patch_bytes_expression = claripy.Concat( BVV(armins >> 21, 11), imm9, BVV(armins & 0xfff, 12) ) self._test_values = (-0x100, 0xff) else: raise ValueNotFoundError if not self.sanity_check(): raise ValueNotFoundError else: insn = self._string_to_insn(self._insbytes) insn = BVV(insn, self._inslen*8) for word_size in (64, 32, 16, 8): if word_size > self.bits: continue for bit_offset in range(0, insn.length-word_size+1, 8): result = insn[bit_offset+word_size-1:bit_offset] result = result.sign_extend(self.bits-word_size) if claripy.is_true(result == self.value): imm = self._imm(word_size) self.patch_value_expression = imm.sign_extend(self.bits-word_size) if bit_offset + word_size >= insn.length: acc = imm else: acc = claripy.Concat(insn[insn.length-1:bit_offset+word_size], imm) if bit_offset != 0: acc = claripy.Concat(acc, insn[bit_offset-1:0]) if self._project.arch.memory_endness == 'Iend_LE': self.patch_bytes_offset = bit_offset//8 else: self.patch_bytes_offset = self._inslen - (bit_offset + word_size)//8 self.patch_bytes_size = word_size//8 self.patch_bytes_expression = acc self._test_values = (-(1 << word_size) >> 1, ((1 << word_size) >> 1) - 1) if self.sanity_check(): break # found if self._project.arch.name == 'PPC64': # On PPC64, the lowest two bits of immediate values can be used for other things # Mask those out result = (result & ~3).sign_extend(self.bits-word_size) if not claripy.is_true(result == self.value): continue imm = self._imm(word_size-2) self.patch_value_expression = claripy.Concat( imm, BVV(0, 2) ).sign_extend(self.bits-word_size) if bit_offset + word_size >= insn.length: acc = imm else: acc = claripy.Concat(insn[insn.length-1:bit_offset+word_size], imm) acc = claripy.Concat(acc, insn[bit_offset+1:0]) if self._project.arch.memory_endness == 'Iend_LE': self.patch_bytes_offset = bit_offset//8 else: self.patch_bytes_offset = self._inslen - (bit_offset + word_size)//8 self.patch_bytes_size = word_size//8 self.patch_bytes_expression = acc self._test_values = (-(1 << word_size) >> 1, ((1 << word_size) >> 1) - 4) if self.sanity_check(): break # found else: # inner loop did not break: not found continue # inner loop broke: found break else: # outer loop did not break: inner loop did not break: not found raise ValueNotFoundError # outer loop broke: inner loop broke: found return
def test_vsa_constraint_to_si(): # Set backend b = claripy.backend_vsa s = claripy.LightFrontend(claripy.backend_vsa) #pylint:disable=unused-variable SI = claripy.SI BVV = claripy.BVV claripy.vsa.strided_interval.allow_dsis = False # # If(SI == 0, 1, 0) == 1 # s1 = claripy.SI(bits=32, stride=1, lower_bound=0, upper_bound=2) ast_true = (claripy.If(s1 == BVV(0, 32), BVV(1, 1), BVV(0, 1)) == BVV(1, 1)) ast_false = (claripy.If(s1 == BVV(0, 32), BVV(1, 1), BVV(0, 1)) != BVV(1, 1)) trueside_sat, trueside_replacement = b.constraint_to_si(ast_true) nose.tools.assert_equal(trueside_sat, True) nose.tools.assert_equal(len(trueside_replacement), 1) nose.tools.assert_true(trueside_replacement[0][0] is s1) # True side: claripy.SI<32>0[0, 0] nose.tools.assert_true( claripy.is_true(trueside_replacement[0][1] == claripy.SI(bits=32, stride=0, lower_bound=0, upper_bound=0))) falseside_sat, falseside_replacement = b.constraint_to_si(ast_false) nose.tools.assert_equal(falseside_sat, True) nose.tools.assert_equal(len(falseside_replacement), 1) nose.tools.assert_true(falseside_replacement[0][0] is s1) # False side; claripy.SI<32>1[1, 2] nose.tools.assert_true( claripy.is_true(falseside_replacement[0][1].identical(SI(bits=32, stride=1, lower_bound=1, upper_bound=2)))) # # Extract(0, 0, Concat(BVV(0, 63), If(SI == 0, 1, 0))) == 1 # s2 = claripy.SI(bits=32, stride=1, lower_bound=0, upper_bound=2) ast_true = (claripy.Extract(0, 0, claripy.Concat(BVV(0, 63), claripy.If(s2 == 0, BVV(1, 1), BVV(0, 1)))) == 1) ast_false = (claripy.Extract(0, 0, claripy.Concat(BVV(0, 63), claripy.If(s2 == 0, BVV(1, 1), BVV(0, 1)))) != 1) trueside_sat, trueside_replacement = b.constraint_to_si(ast_true) nose.tools.assert_equal(trueside_sat, True) nose.tools.assert_equal(len(trueside_replacement), 1) nose.tools.assert_true(trueside_replacement[0][0] is s2) # True side: claripy.SI<32>0[0, 0] nose.tools.assert_true( claripy.is_true(trueside_replacement[0][1].identical(SI(bits=32, stride=0, lower_bound=0, upper_bound=0)))) falseside_sat, falseside_replacement = b.constraint_to_si(ast_false) nose.tools.assert_equal(falseside_sat, True) nose.tools.assert_equal(len(falseside_replacement), 1) nose.tools.assert_true(falseside_replacement[0][0] is s2) # False side; claripy.SI<32>1[1, 2] nose.tools.assert_true( claripy.is_true(falseside_replacement[0][1].identical(SI(bits=32, stride=1, lower_bound=1, upper_bound=2)))) # # Extract(0, 0, ZeroExt(32, If(SI == 0, BVV(1, 32), BVV(0, 32)))) == 1 # s3 = claripy.SI(bits=32, stride=1, lower_bound=0, upper_bound=2) ast_true = (claripy.Extract(0, 0, claripy.ZeroExt(32, claripy.If(s3 == 0, BVV(1, 32), BVV(0, 32)))) == 1) ast_false = (claripy.Extract(0, 0, claripy.ZeroExt(32, claripy.If(s3 == 0, BVV(1, 32), BVV(0, 32)))) != 1) trueside_sat, trueside_replacement = b.constraint_to_si(ast_true) nose.tools.assert_equal(trueside_sat, True) nose.tools.assert_equal(len(trueside_replacement), 1) nose.tools.assert_true(trueside_replacement[0][0] is s3) # True side: claripy.SI<32>0[0, 0] nose.tools.assert_true( claripy.is_true(trueside_replacement[0][1].identical(SI(bits=32, stride=0, lower_bound=0, upper_bound=0)))) falseside_sat, falseside_replacement = b.constraint_to_si(ast_false) nose.tools.assert_equal(falseside_sat, True) nose.tools.assert_equal(len(falseside_replacement), 1) nose.tools.assert_true(falseside_replacement[0][0] is s3) # False side; claripy.SI<32>1[1, 2] nose.tools.assert_true( claripy.is_true(falseside_replacement[0][1].identical(SI(bits=32, stride=1, lower_bound=1, upper_bound=2)))) # # Extract(0, 0, ZeroExt(32, If(Extract(32, 0, (SI & claripy.SI)) < 0, BVV(1, 1), BVV(0, 1)))) # s4 = claripy.SI(bits=64, stride=1, lower_bound=0, upper_bound=0xffffffffffffffff) ast_true = ( claripy.Extract(0, 0, claripy.ZeroExt(32, claripy.If(claripy.Extract(31, 0, (s4 & s4)).SLT(0), BVV(1, 32), BVV(0, 32)))) == 1) ast_false = ( claripy.Extract(0, 0, claripy.ZeroExt(32, claripy.If(claripy.Extract(31, 0, (s4 & s4)).SLT(0), BVV(1, 32), BVV(0, 32)))) != 1) trueside_sat, trueside_replacement = b.constraint_to_si(ast_true) nose.tools.assert_equal(trueside_sat, True) nose.tools.assert_equal(len(trueside_replacement), 1) nose.tools.assert_true(trueside_replacement[0][0] is s4) # True side: claripy.SI<32>0[0, 0] nose.tools.assert_true( claripy.is_true(trueside_replacement[0][1].identical(SI(bits=64, stride=1, lower_bound=-0x8000000000000000, upper_bound=-1)))) falseside_sat, falseside_replacement = b.constraint_to_si(ast_false) nose.tools.assert_equal(falseside_sat, True) nose.tools.assert_equal(len(falseside_replacement), 1) nose.tools.assert_true(falseside_replacement[0][0] is s4) # False side; claripy.SI<32>1[1, 2] nose.tools.assert_true( claripy.is_true(falseside_replacement[0][1].identical(SI(bits=64, stride=1, lower_bound=0, upper_bound=0x7fffffffffffffff))))
def _manage_callstack(state): # condition for call = Ijk_Call # condition for ret = stack pointer drops below call point if state.history.jumpkind == 'Ijk_Call': state._inspect('call', BP_BEFORE, function_address=state.regs._ip) new_func_addr = state._inspect_getattr('function_address', None) if new_func_addr is not None and not claripy.is_true( new_func_addr == state.regs._ip): state.regs._ip = new_func_addr try: if state.arch.call_pushes_ret: ret_addr = state.mem[state.regs._sp].long.concrete else: ret_addr = state.solver.eval(state.regs._lr) except SimSolverModeError: # Use the address for UnresolvableCallTarget instead. ret_addr = state.project.simos.unresolvable_call_target try: state_addr = state.addr except (SimValueError, SimSolverModeError): state_addr = None try: stack_ptr = state.solver.eval(state.regs._sp) except SimSolverModeError: stack_ptr = 0 new_frame = CallStack( call_site_addr=state.history.recent_bbl_addrs[-1], func_addr=state_addr, stack_ptr=stack_ptr, ret_addr=ret_addr, jumpkind='Ijk_Call') state.callstack.push(new_frame) state._inspect('call', BP_AFTER) else: while True: cur_sp = state.solver.max(state.regs._sp) if state.has_plugin( 'symbolizer') else state.regs._sp if not state.solver.is_true( cur_sp > state.callstack.top.stack_ptr): break state._inspect('return', BP_BEFORE, function_address=state.callstack.top.func_addr) state.callstack.pop() state._inspect('return', BP_AFTER) if not state.arch.call_pushes_ret and \ claripy.is_true(state.regs._ip == state.callstack.ret_addr) and \ claripy.is_true(state.regs._sp == state.callstack.stack_ptr): # very weird edge case that's not actually weird or on the edge at all: # if we use a link register for the return address, the stack pointer will be the same # before and after the call. therefore we have to check for equality with the marker # along with this other check with the instruction pointer to guess whether it's time # to pop a callframe. Still better than relying on Ijk_Ret. state._inspect('return', BP_BEFORE, function_address=state.callstack.top.func_addr) state.callstack.pop() state._inspect('return', BP_AFTER)
def __init__(self, *args): super(JQ, self).__init__(*args) if claripy.is_true(self.rm) == 0 and claripy.is_true(self.mem == 0): self.NAME = 'HF'
def _runtime_unify(self, state, one, two, stack_frame=False, overwrite=True): """ decide if one and two need to be unified, if so add a 'UNIFY' tag :param state: The analysis state that holds intermediate results :param one: The first value to unify :param two: The second value to unify :param stack_frame: If we're only allowed to look at offsets in front of the pointer :param overwrite: Whether to use the semantics that one is "overwriting" two """ one_ty = self.ty_backend.convert(one).ty two_ty = self.ty_backend.convert(two).ty # if both of them are pointers!!! this gets very tricky if type(one_ty) is type(two_ty) is sim_type.SimTypePointer: one_subty = one_ty.pts_to two_subty = two_ty.pts_to one_offset = one_ty.offset two_offset = two_ty.offset if one_offset.symbolic or two_offset.symbolic: import ipdb ipdb.set_trace() print('yikes! (jesus christ)') if one_subty is two_subty: if one_offset is not two_subty: import ipdb ipdb.set_trace() print('yikes? (arrays maybe. recursion probably)') else: import ipdb ipdb.set_trace() print('yikes. (no object identity but yes equality)') # these are two different structures that we might have to unify. # possible cases: # - two structures are actually the same structure. # - two stack frames. flag tells us this. only deal with the argument parts # - a structure is present in another structure # TODO: do some type checking on the two structs to make sure we're not making # a huge mistake!!! else: if claripy.is_true( one_offset == two_offset) and claripy.is_true( one_offset == 0): self.pass_results.append(('UNIFY', (one, two))) elif stack_frame: for ckey, _ in two_subty.offsets.iteritems(): offset = ckey.ast if not claripy.is_true(claripy.SGT(offset, 0)): continue two_value = state.memory.load( two + offset, size=state.arch.bytes, inspect=False, endness=state.arch.memory_endness) one_value = state.memory.load( one + offset, size=state.arch.bytes, inspect=False, endness=state.arch.memory_endness) # one last edge case consideration: if one_value doesn't have a source # (since we disabled inspect, this might happen) # we should manually give it a source since this is something we know one_value_ty = self.ty_backend.convert(one_value).ty if type(one_value_ty) is not sim_type.SimTypePointer and \ len(one_value_ty.label) == 0: one_value = one_value.annotate( TypeAnnotation( sim_type.SimTypeTop( label=[ValueSource(two_subty, offset) ]))) self._runtime_unify(state, one_value, two_value) else: import ipdb ipdb.set_trace() # look through the structs and check offset by offset # do we want to check in the initial state or elsewhere? # think we should check in the current state. everything from the initial state wil be there still? print('okay??') # when only one of them is a pointer! # if a source is available we should toss it to SOURCE, she'll just drop the other in! # if a source is not available, wait. eventually one will be available :) elif type(two_ty) is sim_type.SimTypePointer: if len(one_ty.label) > 0: if len(one_ty.label) > 1: import ipdb ipdb.set_trace() print('????????????') self.pass_results.append(('SOURCE', one_ty.label[0])) # this is where overwrite semantics comes into play. # if one overwrites two, then we can't mark two as a pointer just because 1 is a pointer. # otherwise, this is the same as the previous case I guess? # I'm not sure what good this does elif type(one_ty) is sim_type.SimTypePointer: import ipdb ipdb.set_trace() if not overwrite: if len(two_ty.label) > 0: if len(two_ty.label) > 1: import ipdb ipdb.set_trace() print('????????????') self.pass_results.append(('SOURCE', two_ty.label[0])) # If neither of them are pointers bail out. this is not a general type inference :) else: pass
def test_rcr(): p = angr.Project(os.path.join(os.path.dirname(__file__), '../../binaries/tests/i386/rcr_test')) path = p.factory.path() path.step() nose.tools.assert_true(claripy.is_true(path.successors[0].state.regs.cl == 8))
def test_vsa(): # Set backend b = claripy.backend_vsa SI = claripy.StridedInterval VS = claripy.ValueSet BVV = claripy.BVV # Disable the use of DiscreteStridedIntervalSet claripy.vsa.strided_interval.allow_dsis = False def is_equal(ast_0, ast_1): return ast_0.identical(ast_1) si1 = claripy.TSI(32, name="foo") nose.tools.assert_equal(si1.model.name, "foo") # Normalization si1 = SI(bits=32, stride=1, lower_bound=10, upper_bound=10) nose.tools.assert_equal(si1.model.stride, 0) # Integers si1 = claripy.SI(bits=32, stride=0, lower_bound=10, upper_bound=10) si2 = claripy.SI(bits=32, stride=0, lower_bound=10, upper_bound=10) si3 = claripy.SI(bits=32, stride=0, lower_bound=28, upper_bound=28) # Strided intervals si_a = claripy.SI(bits=32, stride=2, lower_bound=10, upper_bound=20) si_b = claripy.SI(bits=32, stride=2, lower_bound=-100, upper_bound=200) si_c = claripy.SI(bits=32, stride=3, lower_bound=-100, upper_bound=200) si_d = claripy.SI(bits=32, stride=2, lower_bound=50, upper_bound=60) si_e = claripy.SI(bits=16, stride=1, lower_bound=0x2000, upper_bound=0x3000) si_f = claripy.SI(bits=16, stride=1, lower_bound=0, upper_bound=255) si_g = claripy.SI(bits=16, stride=1, lower_bound=0, upper_bound=0xff) si_h = claripy.SI(bits=32, stride=0, lower_bound=0x80000000, upper_bound=0x80000000) nose.tools.assert_true(is_equal(si1, claripy.SI(bits=32, to_conv=10))) nose.tools.assert_true(is_equal(si2, claripy.SI(bits=32, to_conv=10))) nose.tools.assert_true(is_equal(si1, si2)) # __add__ si_add_1 = si1 + si2 nose.tools.assert_true(is_equal(si_add_1, claripy.SI(bits=32, stride=0, lower_bound=20, upper_bound=20))) si_add_2 = si1 + si_a nose.tools.assert_true(is_equal(si_add_2, claripy.SI(bits=32, stride=2, lower_bound=20, upper_bound=30))) si_add_3 = si_a + si_b nose.tools.assert_true(is_equal(si_add_3, claripy.SI(bits=32, stride=2, lower_bound=-90, upper_bound=220))) si_add_4 = si_b + si_c nose.tools.assert_true(is_equal(si_add_4, claripy.SI(bits=32, stride=1, lower_bound=-200, upper_bound=400))) # __add__ with overflow si_add_5 = si_h + 0xffffffff nose.tools.assert_true(is_equal(si_add_5, claripy.SI(bits=32, stride=0, lower_bound=0x7fffffff, upper_bound=0x7fffffff))) # __sub__ si_minus_1 = si1 - si2 nose.tools.assert_true(is_equal(si_minus_1, claripy.SI(bits=32, stride=0, lower_bound=0, upper_bound=0))) si_minus_2 = si_a - si_b nose.tools.assert_true(is_equal(si_minus_2, claripy.SI(bits=32, stride=2, lower_bound=-190, upper_bound=120))) si_minus_3 = si_b - si_c nose.tools.assert_true(is_equal(si_minus_3, claripy.SI(bits=32, stride=1, lower_bound=-300, upper_bound=300))) # __neg__ / __invert__ / bitwise not si_neg_1 = ~si1 nose.tools.assert_true(is_equal(si_neg_1, claripy.SI(bits=32, to_conv=-11))) si_neg_2 = ~si_b nose.tools.assert_true(is_equal(si_neg_2, claripy.SI(bits=32, stride=2, lower_bound=-201, upper_bound=99))) # __or__ si_or_1 = si1 | si3 nose.tools.assert_true(is_equal(si_or_1, claripy.SI(bits=32, to_conv=30))) si_or_2 = si1 | si2 nose.tools.assert_true(is_equal(si_or_2, claripy.SI(bits=32, to_conv=10))) si_or_3 = si1 | si_a # An integer | a strided interval nose.tools.assert_true(is_equal(si_or_3 , claripy.SI(bits=32, stride=2, lower_bound=10, upper_bound=30))) si_or_3 = si_a | si1 # Exchange the operands nose.tools.assert_true(is_equal(si_or_3, claripy.SI(bits=32, stride=2, lower_bound=10, upper_bound=30))) si_or_4 = si_a | si_d # A strided interval | another strided interval nose.tools.assert_true(is_equal(si_or_4, claripy.SI(bits=32, stride=2, lower_bound=50, upper_bound=62))) si_or_4 = si_d | si_a # Exchange the operands nose.tools.assert_true(is_equal(si_or_4, claripy.SI(bits=32, stride=2, lower_bound=50, upper_bound=62))) si_or_5 = si_e | si_f # nose.tools.assert_true(is_equal(si_or_5, claripy.SI(bits=16, stride=1, lower_bound=0x2000, upper_bound=0x30ff))) si_or_6 = si_e | si_g # nose.tools.assert_true(is_equal(si_or_6, claripy.SI(bits=16, stride=1, lower_bound=0x2000, upper_bound=0x30ff))) # Shifting si_shl_1 = si1 << 3 nose.tools.assert_equal(si_shl_1.size(), 32) nose.tools.assert_true(is_equal(si_shl_1, claripy.SI(bits=32, stride=0, lower_bound=80, upper_bound=80))) # Multiplication si_mul_1 = si1 * 3 nose.tools.assert_equal(si_mul_1.size(), 32) nose.tools.assert_true(is_equal(si_mul_1, claripy.SI(bits=32, stride=0, lower_bound=30, upper_bound=30))) si_mul_2 = si_a * 3 nose.tools.assert_equal(si_mul_2.size(), 32) nose.tools.assert_true(is_equal(si_mul_2, claripy.SI(bits=32, stride=6, lower_bound=30, upper_bound=60))) si_mul_3 = si_a * si_b nose.tools.assert_equal(si_mul_3.size(), 32) nose.tools.assert_true(is_equal(si_mul_3, claripy.SI(bits=32, stride=2, lower_bound=-2000, upper_bound=4000))) # Division si_div_1 = si1 / 3 nose.tools.assert_equal(si_div_1.size(), 32) nose.tools.assert_true(is_equal(si_div_1, claripy.SI(bits=32, stride=0, lower_bound=3, upper_bound=3))) si_div_2 = si_a / 3 nose.tools.assert_equal(si_div_2.size(), 32) nose.tools.assert_true(is_equal(si_div_2, claripy.SI(bits=32, stride=1, lower_bound=3, upper_bound=6))) # Modulo si_mo_1 = si1 % 3 nose.tools.assert_equal(si_mo_1.size(), 32) nose.tools.assert_true(is_equal(si_mo_1, claripy.SI(bits=32, stride=0, lower_bound=1, upper_bound=1))) si_mo_2 = si_a % 3 nose.tools.assert_equal(si_mo_2.size(), 32) nose.tools.assert_true(is_equal(si_mo_2, claripy.SI(bits=32, stride=1, lower_bound=0, upper_bound=2))) # # Extracting the sign bit # # a negative integer si = claripy.SI(bits=64, stride=0, lower_bound=-1, upper_bound=-1) sb = si[63: 63] nose.tools.assert_true(is_equal(sb, claripy.SI(bits=1, to_conv=1))) # non-positive integers si = claripy.SI(bits=64, stride=1, lower_bound=-1, upper_bound=0) sb = si[63: 63] nose.tools.assert_true(is_equal(sb, claripy.SI(bits=1, stride=1, lower_bound=0, upper_bound=1))) # Extracting an integer si = claripy.SI(bits=64, stride=0, lower_bound=0x7fffffffffff0000, upper_bound=0x7fffffffffff0000) part1 = si[63 : 32] part2 = si[31 : 0] nose.tools.assert_true(is_equal(part1, claripy.SI(bits=32, stride=0, lower_bound=0x7fffffff, upper_bound=0x7fffffff))) nose.tools.assert_true(is_equal(part2, claripy.SI(bits=32, stride=0, lower_bound=0xffff0000, upper_bound=0xffff0000))) # Concatenating two integers si_concat = part1.concat(part2) nose.tools.assert_true(is_equal(si_concat, si)) # Extracting a claripy.SI si = claripy.SI(bits=64, stride=0x9, lower_bound=0x1, upper_bound=0xa) part1 = si[63 : 32] part2 = si[31 : 0] nose.tools.assert_true(is_equal(part1, claripy.SI(bits=32, stride=0, lower_bound=0x0, upper_bound=0x0))) nose.tools.assert_true(is_equal(part2, claripy.SI(bits=32, stride=9, lower_bound=1, upper_bound=10))) # Concatenating two claripy.SIs si_concat = part1.concat(part2) nose.tools.assert_true(is_equal(si_concat, si)) # Zero-Extend the low part si_zeroextended = part2.zero_extend(32) nose.tools.assert_true(is_equal(si_zeroextended, claripy.SI(bits=64, stride=9, lower_bound=1, upper_bound=10))) # Sign-extension si_signextended = part2.sign_extend(32) nose.tools.assert_true(is_equal(si_signextended, claripy.SI(bits=64, stride=9, lower_bound=1, upper_bound=10))) # Extract from the result above si_extracted = si_zeroextended[31:0] nose.tools.assert_true(is_equal(si_extracted, claripy.SI(bits=32, stride=9, lower_bound=1, upper_bound=10))) # Union si_union_1 = si1.union(si2) nose.tools.assert_true(is_equal(si_union_1, claripy.SI(bits=32, stride=0, lower_bound=10, upper_bound=10))) si_union_2 = si1.union(si3) nose.tools.assert_true(is_equal(si_union_2, claripy.SI(bits=32, stride=18, lower_bound=10, upper_bound=28))) si_union_3 = si1.union(si_a) nose.tools.assert_true(is_equal(si_union_3, claripy.SI(bits=32, stride=2, lower_bound=10, upper_bound=20))) si_union_4 = si_a.union(si_b) nose.tools.assert_true(is_equal(si_union_4, claripy.SI(bits=32, stride=2, lower_bound=-100, upper_bound=200))) si_union_5 = si_b.union(si_c) nose.tools.assert_true(is_equal(si_union_5, claripy.SI(bits=32, stride=1, lower_bound=-100, upper_bound=200))) # Intersection si_intersection_1 = si1.intersection(si1) nose.tools.assert_true(is_equal(si_intersection_1, si2)) si_intersection_2 = si1.intersection(si2) nose.tools.assert_true(is_equal(si_intersection_2, claripy.SI(bits=32, stride=0, lower_bound=10, upper_bound=10))) si_intersection_3 = si1.intersection(si_a) nose.tools.assert_true(is_equal(si_intersection_3, claripy.SI(bits=32, stride=0, lower_bound=10, upper_bound=10))) si_intersection_4 = si_a.intersection(si_b) nose.tools.assert_true(is_equal(si_intersection_4, claripy.SI(bits=32, stride=2, lower_bound=10, upper_bound=20))) si_intersection_5 = si_b.intersection(si_c) nose.tools.assert_true(is_equal(si_intersection_5, claripy.SI(bits=32, stride=6, lower_bound=-100, upper_bound=200))) # Sign-extension si = claripy.SI(bits=1, stride=0, lower_bound=1, upper_bound=1) si_signextended = si.sign_extend(31) nose.tools.assert_true(is_equal(si_signextended, claripy.SI(bits=32, stride=0, lower_bound=0xffffffff, upper_bound=0xffffffff))) # Comparison between claripy.SI and BVV si = claripy.SI(bits=32, stride=1, lower_bound=-0x7f, upper_bound=0x7f) si.uninitialized = True bvv = BVV(0x30, 32) comp = (si < bvv) nose.tools.assert_equal(comp.model, MaybeResult()) # Better extraction # si = <32>0x1000000[0xcffffff, 0xdffffff]R si = claripy.SI(bits=32, stride=0x1000000, lower_bound=0xcffffff, upper_bound=0xdffffff) si_byte0 = si[7: 0] si_byte1 = si[15: 8] si_byte2 = si[23: 16] si_byte3 = si[31: 24] nose.tools.assert_true(is_equal(si_byte0, claripy.SI(bits=8, stride=0, lower_bound=0xff, upper_bound=0xff))) nose.tools.assert_true(is_equal(si_byte1, claripy.SI(bits=8, stride=0, lower_bound=0xff, upper_bound=0xff))) nose.tools.assert_true(is_equal(si_byte2, claripy.SI(bits=8, stride=0, lower_bound=0xff, upper_bound=0xff))) nose.tools.assert_true(is_equal(si_byte3, claripy.SI(bits=8, stride=1, lower_bound=0xc, upper_bound=0xd))) # Optimization on bitwise-and si_1 = claripy.SI(bits=32, stride=1, lower_bound=0x0, upper_bound=0xffffffff) si_2 = claripy.SI(bits=32, stride=0, lower_bound=0x80000000, upper_bound=0x80000000) si = si_1 & si_2 nose.tools.assert_true(is_equal(si, claripy.SI(bits=32, stride=0x80000000, lower_bound=0, upper_bound=0x80000000))) si_1 = claripy.SI(bits=32, stride=1, lower_bound=0x0, upper_bound=0x7fffffff) si_2 = claripy.SI(bits=32, stride=0, lower_bound=0x80000000, upper_bound=0x80000000) si = si_1 & si_2 nose.tools.assert_true(is_equal(si, claripy.SI(bits=32, stride=0, lower_bound=0, upper_bound=0))) # # ValueSet # vs_1 = claripy.ValueSet(bits=32) nose.tools.assert_true(vs_1.model.is_empty, True) # Test merging two addresses vs_1.model.merge_si('global', si1) vs_1.model.merge_si('global', si3) nose.tools.assert_true(vs_1.model.get_si('global').identical(SI(bits=32, stride=18, lower_bound=10, upper_bound=28).model)) # Length of this ValueSet nose.tools.assert_equal(len(vs_1.model), 32) vs_1 = claripy.ValueSet(name='boo', bits=32) vs_2 = claripy.ValueSet(name='boo', bits=32) nose.tools.assert_true(vs_1.identical(vs_1)) nose.tools.assert_true(vs_1.identical(vs_2)) vs_1.model.merge_si('global', si1) nose.tools.assert_false(vs_1.identical(vs_2)) vs_2.model.merge_si('global', si1) nose.tools.assert_true(vs_1.identical(vs_2)) vs_1.model.merge_si('global', si3) nose.tools.assert_false(vs_1.identical(vs_2)) # # IfProxy # # max and min on IfProxy si = claripy.SI(bits=32, stride=1, lower_bound=0, upper_bound=0xffffffff) if_0 = claripy.If(si == 0, si, si - 1) max_val = b.max(if_0) min_val = b.min(if_0) nose.tools.assert_true(max_val, 0xffffffff) nose.tools.assert_true(min_val, -0x80000000) # if_1 = And(VS_2, IfProxy(si == 0, 0, 1)) vs_2 = VS(region='global', bits=32, val=0xFA7B00B) si = claripy.SI(bits=32, stride=1, lower_bound=0, upper_bound=1) if_1 = (vs_2 & claripy.If(si == 0, claripy.SI(bits=32, stride=0, lower_bound=0, upper_bound=0), claripy.SI(bits=32, stride=0, lower_bound=0xffffffff, upper_bound=0xffffffff))) nose.tools.assert_true(claripy.is_true(if_1.model.trueexpr == VS(region='global', bits=32, val=0).model)) nose.tools.assert_true(claripy.is_true(if_1.model.falseexpr == vs_2.model)) # if_2 = And(VS_3, IfProxy(si != 0, 0, 1) vs_3 = claripy.ValueSet(region='global', bits=32, val=0xDEADCA7) si = claripy.SI(bits=32, stride=1, lower_bound=0, upper_bound=1) if_2 = (vs_3 & claripy.If(si != 0, claripy.SI(bits=32, stride=0, lower_bound=0, upper_bound=0), claripy.SI(bits=32, stride=0, lower_bound=0xffffffff, upper_bound=0xffffffff))) nose.tools.assert_true(claripy.is_true(if_2.model.trueexpr == VS(region='global', bits=32, val=0).model)) nose.tools.assert_true(claripy.is_true(if_2.model.falseexpr == vs_3.model)) # Something crazy is gonna happen... if_3 = if_1 + if_2 nose.tools.assert_true(claripy.is_true(if_3.model.trueexpr == vs_3.model)) nose.tools.assert_true(claripy.is_true(if_3.model.falseexpr == vs_2.model))
def _is_true(self, v): return claripy.is_true(v)
def test_vsa(): # Set backend b = claripy.backend_vsa SI = claripy.StridedInterval VS = claripy.ValueSet BVV = claripy.BVV # Disable the use of DiscreteStridedIntervalSet claripy.vsa.strided_interval.allow_dsis = False def is_equal(ast_0, ast_1): return ast_0.identical(ast_1) si1 = claripy.TSI(32, name="foo") nose.tools.assert_equal(si1.model.name, "foo") # Normalization si1 = SI(bits=32, stride=1, lower_bound=10, upper_bound=10) nose.tools.assert_equal(si1.model.stride, 0) # Integers si1 = claripy.SI(bits=32, stride=0, lower_bound=10, upper_bound=10) si2 = claripy.SI(bits=32, stride=0, lower_bound=10, upper_bound=10) si3 = claripy.SI(bits=32, stride=0, lower_bound=28, upper_bound=28) # Strided intervals si_a = claripy.SI(bits=32, stride=2, lower_bound=10, upper_bound=20) si_b = claripy.SI(bits=32, stride=2, lower_bound=-100, upper_bound=200) si_c = claripy.SI(bits=32, stride=3, lower_bound=-100, upper_bound=200) si_d = claripy.SI(bits=32, stride=2, lower_bound=50, upper_bound=60) si_e = claripy.SI(bits=16, stride=1, lower_bound=0x2000, upper_bound=0x3000) si_f = claripy.SI(bits=16, stride=1, lower_bound=0, upper_bound=255) si_g = claripy.SI(bits=16, stride=1, lower_bound=0, upper_bound=0xff) si_h = claripy.SI(bits=32, stride=0, lower_bound=0x80000000, upper_bound=0x80000000) nose.tools.assert_true(is_equal(si1, claripy.SI(bits=32, to_conv=10))) nose.tools.assert_true(is_equal(si2, claripy.SI(bits=32, to_conv=10))) nose.tools.assert_true(is_equal(si1, si2)) # __add__ si_add_1 = si1 + si2 nose.tools.assert_true( is_equal(si_add_1, claripy.SI(bits=32, stride=0, lower_bound=20, upper_bound=20))) si_add_2 = si1 + si_a nose.tools.assert_true( is_equal(si_add_2, claripy.SI(bits=32, stride=2, lower_bound=20, upper_bound=30))) si_add_3 = si_a + si_b nose.tools.assert_true( is_equal( si_add_3, claripy.SI(bits=32, stride=2, lower_bound=-90, upper_bound=220))) si_add_4 = si_b + si_c nose.tools.assert_true( is_equal( si_add_4, claripy.SI(bits=32, stride=1, lower_bound=-200, upper_bound=400))) # __add__ with overflow si_add_5 = si_h + 0xffffffff nose.tools.assert_true( is_equal( si_add_5, claripy.SI(bits=32, stride=0, lower_bound=0x7fffffff, upper_bound=0x7fffffff))) # __sub__ si_minus_1 = si1 - si2 nose.tools.assert_true( is_equal(si_minus_1, claripy.SI(bits=32, stride=0, lower_bound=0, upper_bound=0))) si_minus_2 = si_a - si_b nose.tools.assert_true( is_equal( si_minus_2, claripy.SI(bits=32, stride=2, lower_bound=-190, upper_bound=120))) si_minus_3 = si_b - si_c nose.tools.assert_true( is_equal( si_minus_3, claripy.SI(bits=32, stride=1, lower_bound=-300, upper_bound=300))) # __neg__ / __invert__ / bitwise not si_neg_1 = ~si1 nose.tools.assert_true(is_equal(si_neg_1, claripy.SI(bits=32, to_conv=-11))) si_neg_2 = ~si_b nose.tools.assert_true( is_equal( si_neg_2, claripy.SI(bits=32, stride=2, lower_bound=-201, upper_bound=99))) # __or__ si_or_1 = si1 | si3 nose.tools.assert_true(is_equal(si_or_1, claripy.SI(bits=32, to_conv=30))) si_or_2 = si1 | si2 nose.tools.assert_true(is_equal(si_or_2, claripy.SI(bits=32, to_conv=10))) si_or_3 = si1 | si_a # An integer | a strided interval nose.tools.assert_true( is_equal(si_or_3, claripy.SI(bits=32, stride=2, lower_bound=10, upper_bound=30))) si_or_3 = si_a | si1 # Exchange the operands nose.tools.assert_true( is_equal(si_or_3, claripy.SI(bits=32, stride=2, lower_bound=10, upper_bound=30))) si_or_4 = si_a | si_d # A strided interval | another strided interval nose.tools.assert_true( is_equal(si_or_4, claripy.SI(bits=32, stride=2, lower_bound=50, upper_bound=62))) si_or_4 = si_d | si_a # Exchange the operands nose.tools.assert_true( is_equal(si_or_4, claripy.SI(bits=32, stride=2, lower_bound=50, upper_bound=62))) si_or_5 = si_e | si_f # nose.tools.assert_true( is_equal( si_or_5, claripy.SI(bits=16, stride=1, lower_bound=0x2000, upper_bound=0x30ff))) si_or_6 = si_e | si_g # nose.tools.assert_true( is_equal( si_or_6, claripy.SI(bits=16, stride=1, lower_bound=0x2000, upper_bound=0x30ff))) # Shifting si_shl_1 = si1 << 3 nose.tools.assert_equal(si_shl_1.size(), 32) nose.tools.assert_true( is_equal(si_shl_1, claripy.SI(bits=32, stride=0, lower_bound=80, upper_bound=80))) # Multiplication si_mul_1 = si1 * 3 nose.tools.assert_equal(si_mul_1.size(), 32) nose.tools.assert_true( is_equal(si_mul_1, claripy.SI(bits=32, stride=0, lower_bound=30, upper_bound=30))) si_mul_2 = si_a * 3 nose.tools.assert_equal(si_mul_2.size(), 32) nose.tools.assert_true( is_equal(si_mul_2, claripy.SI(bits=32, stride=6, lower_bound=30, upper_bound=60))) si_mul_3 = si_a * si_b nose.tools.assert_equal(si_mul_3.size(), 32) nose.tools.assert_true( is_equal( si_mul_3, claripy.SI(bits=32, stride=2, lower_bound=-2000, upper_bound=4000))) # Division si_div_1 = si1 / 3 nose.tools.assert_equal(si_div_1.size(), 32) nose.tools.assert_true( is_equal(si_div_1, claripy.SI(bits=32, stride=0, lower_bound=3, upper_bound=3))) si_div_2 = si_a / 3 nose.tools.assert_equal(si_div_2.size(), 32) nose.tools.assert_true( is_equal(si_div_2, claripy.SI(bits=32, stride=1, lower_bound=3, upper_bound=6))) # Modulo si_mo_1 = si1 % 3 nose.tools.assert_equal(si_mo_1.size(), 32) nose.tools.assert_true( is_equal(si_mo_1, claripy.SI(bits=32, stride=0, lower_bound=1, upper_bound=1))) si_mo_2 = si_a % 3 nose.tools.assert_equal(si_mo_2.size(), 32) nose.tools.assert_true( is_equal(si_mo_2, claripy.SI(bits=32, stride=1, lower_bound=0, upper_bound=2))) # # Extracting the sign bit # # a negative integer si = claripy.SI(bits=64, stride=0, lower_bound=-1, upper_bound=-1) sb = si[63:63] nose.tools.assert_true(is_equal(sb, claripy.SI(bits=1, to_conv=1))) # non-positive integers si = claripy.SI(bits=64, stride=1, lower_bound=-1, upper_bound=0) sb = si[63:63] nose.tools.assert_true( is_equal(sb, claripy.SI(bits=1, stride=1, lower_bound=0, upper_bound=1))) # Extracting an integer si = claripy.SI(bits=64, stride=0, lower_bound=0x7fffffffffff0000, upper_bound=0x7fffffffffff0000) part1 = si[63:32] part2 = si[31:0] nose.tools.assert_true( is_equal( part1, claripy.SI(bits=32, stride=0, lower_bound=0x7fffffff, upper_bound=0x7fffffff))) nose.tools.assert_true( is_equal( part2, claripy.SI(bits=32, stride=0, lower_bound=0xffff0000, upper_bound=0xffff0000))) # Concatenating two integers si_concat = part1.concat(part2) nose.tools.assert_true(is_equal(si_concat, si)) # Extracting a claripy.SI si = claripy.SI(bits=64, stride=0x9, lower_bound=0x1, upper_bound=0xa) part1 = si[63:32] part2 = si[31:0] nose.tools.assert_true( is_equal( part1, claripy.SI(bits=32, stride=0, lower_bound=0x0, upper_bound=0x0))) nose.tools.assert_true( is_equal(part2, claripy.SI(bits=32, stride=9, lower_bound=1, upper_bound=10))) # Concatenating two claripy.SIs si_concat = part1.concat(part2) nose.tools.assert_true(is_equal(si_concat, si)) # Zero-Extend the low part si_zeroextended = part2.zero_extend(32) nose.tools.assert_true( is_equal(si_zeroextended, claripy.SI(bits=64, stride=9, lower_bound=1, upper_bound=10))) # Sign-extension si_signextended = part2.sign_extend(32) nose.tools.assert_true( is_equal(si_signextended, claripy.SI(bits=64, stride=9, lower_bound=1, upper_bound=10))) # Extract from the result above si_extracted = si_zeroextended[31:0] nose.tools.assert_true( is_equal(si_extracted, claripy.SI(bits=32, stride=9, lower_bound=1, upper_bound=10))) # Union si_union_1 = si1.union(si2) nose.tools.assert_true( is_equal(si_union_1, claripy.SI(bits=32, stride=0, lower_bound=10, upper_bound=10))) si_union_2 = si1.union(si3) nose.tools.assert_true( is_equal( si_union_2, claripy.SI(bits=32, stride=18, lower_bound=10, upper_bound=28))) si_union_3 = si1.union(si_a) nose.tools.assert_true( is_equal(si_union_3, claripy.SI(bits=32, stride=2, lower_bound=10, upper_bound=20))) si_union_4 = si_a.union(si_b) nose.tools.assert_true( is_equal( si_union_4, claripy.SI(bits=32, stride=2, lower_bound=-100, upper_bound=200))) si_union_5 = si_b.union(si_c) nose.tools.assert_true( is_equal( si_union_5, claripy.SI(bits=32, stride=1, lower_bound=-100, upper_bound=200))) # Intersection si_intersection_1 = si1.intersection(si1) nose.tools.assert_true(is_equal(si_intersection_1, si2)) si_intersection_2 = si1.intersection(si2) nose.tools.assert_true( is_equal(si_intersection_2, claripy.SI(bits=32, stride=0, lower_bound=10, upper_bound=10))) si_intersection_3 = si1.intersection(si_a) nose.tools.assert_true( is_equal(si_intersection_3, claripy.SI(bits=32, stride=0, lower_bound=10, upper_bound=10))) si_intersection_4 = si_a.intersection(si_b) nose.tools.assert_true( is_equal(si_intersection_4, claripy.SI(bits=32, stride=2, lower_bound=10, upper_bound=20))) si_intersection_5 = si_b.intersection(si_c) nose.tools.assert_true( is_equal( si_intersection_5, claripy.SI(bits=32, stride=6, lower_bound=-100, upper_bound=200))) # Sign-extension si = claripy.SI(bits=1, stride=0, lower_bound=1, upper_bound=1) si_signextended = si.sign_extend(31) nose.tools.assert_true( is_equal( si_signextended, claripy.SI(bits=32, stride=0, lower_bound=0xffffffff, upper_bound=0xffffffff))) # Comparison between claripy.SI and BVV si = claripy.SI(bits=32, stride=1, lower_bound=-0x7f, upper_bound=0x7f) si.uninitialized = True bvv = BVV(0x30, 32) comp = (si < bvv) nose.tools.assert_equal(comp.model, MaybeResult()) # Better extraction # si = <32>0x1000000[0xcffffff, 0xdffffff]R si = claripy.SI(bits=32, stride=0x1000000, lower_bound=0xcffffff, upper_bound=0xdffffff) si_byte0 = si[7:0] si_byte1 = si[15:8] si_byte2 = si[23:16] si_byte3 = si[31:24] nose.tools.assert_true( is_equal( si_byte0, claripy.SI(bits=8, stride=0, lower_bound=0xff, upper_bound=0xff))) nose.tools.assert_true( is_equal( si_byte1, claripy.SI(bits=8, stride=0, lower_bound=0xff, upper_bound=0xff))) nose.tools.assert_true( is_equal( si_byte2, claripy.SI(bits=8, stride=0, lower_bound=0xff, upper_bound=0xff))) nose.tools.assert_true( is_equal( si_byte3, claripy.SI(bits=8, stride=1, lower_bound=0xc, upper_bound=0xd))) # Optimization on bitwise-and si_1 = claripy.SI(bits=32, stride=1, lower_bound=0x0, upper_bound=0xffffffff) si_2 = claripy.SI(bits=32, stride=0, lower_bound=0x80000000, upper_bound=0x80000000) si = si_1 & si_2 nose.tools.assert_true( is_equal( si, claripy.SI(bits=32, stride=0x80000000, lower_bound=0, upper_bound=0x80000000))) si_1 = claripy.SI(bits=32, stride=1, lower_bound=0x0, upper_bound=0x7fffffff) si_2 = claripy.SI(bits=32, stride=0, lower_bound=0x80000000, upper_bound=0x80000000) si = si_1 & si_2 nose.tools.assert_true( is_equal(si, claripy.SI(bits=32, stride=0, lower_bound=0, upper_bound=0))) # # ValueSet # vs_1 = claripy.ValueSet(bits=32) nose.tools.assert_true(vs_1.model.is_empty, True) # Test merging two addresses vs_1.model.merge_si('global', si1) vs_1.model.merge_si('global', si3) nose.tools.assert_true( vs_1.model.get_si('global').identical( SI(bits=32, stride=18, lower_bound=10, upper_bound=28).model)) # Length of this ValueSet nose.tools.assert_equal(len(vs_1.model), 32) vs_1 = claripy.ValueSet(name='boo', bits=32) vs_2 = claripy.ValueSet(name='boo', bits=32) nose.tools.assert_true(vs_1.identical(vs_1)) nose.tools.assert_true(vs_1.identical(vs_2)) vs_1.model.merge_si('global', si1) nose.tools.assert_false(vs_1.identical(vs_2)) vs_2.model.merge_si('global', si1) nose.tools.assert_true(vs_1.identical(vs_2)) vs_1.model.merge_si('global', si3) nose.tools.assert_false(vs_1.identical(vs_2)) # # IfProxy # # max and min on IfProxy si = claripy.SI(bits=32, stride=1, lower_bound=0, upper_bound=0xffffffff) if_0 = claripy.If(si == 0, si, si - 1) max_val = b.max(if_0) min_val = b.min(if_0) nose.tools.assert_true(max_val, 0xffffffff) nose.tools.assert_true(min_val, -0x80000000) # if_1 = And(VS_2, IfProxy(si == 0, 0, 1)) vs_2 = VS(region='global', bits=32, val=0xFA7B00B) si = claripy.SI(bits=32, stride=1, lower_bound=0, upper_bound=1) if_1 = (vs_2 & claripy.If( si == 0, claripy.SI(bits=32, stride=0, lower_bound=0, upper_bound=0), claripy.SI( bits=32, stride=0, lower_bound=0xffffffff, upper_bound=0xffffffff))) nose.tools.assert_true( claripy.is_true( if_1.model.trueexpr == VS(region='global', bits=32, val=0).model)) nose.tools.assert_true(claripy.is_true(if_1.model.falseexpr == vs_2.model)) # if_2 = And(VS_3, IfProxy(si != 0, 0, 1) vs_3 = claripy.ValueSet(region='global', bits=32, val=0xDEADCA7) si = claripy.SI(bits=32, stride=1, lower_bound=0, upper_bound=1) if_2 = (vs_3 & claripy.If( si != 0, claripy.SI(bits=32, stride=0, lower_bound=0, upper_bound=0), claripy.SI( bits=32, stride=0, lower_bound=0xffffffff, upper_bound=0xffffffff))) nose.tools.assert_true( claripy.is_true( if_2.model.trueexpr == VS(region='global', bits=32, val=0).model)) nose.tools.assert_true(claripy.is_true(if_2.model.falseexpr == vs_3.model)) # Something crazy is gonna happen... if_3 = if_1 + if_2 nose.tools.assert_true(claripy.is_true(if_3.model.trueexpr == vs_3.model)) nose.tools.assert_true(claripy.is_true(if_3.model.falseexpr == vs_2.model))
def test_wrapped_intervals(): #SI = claripy.StridedInterval # Disable the use of DiscreteStridedIntervalSet claripy.vsa.strided_interval.allow_dsis = False # # Signedness/unsignedness conversion # si1 = claripy.SI(bits=32, stride=1, lower_bound=0, upper_bound=0xffffffff) nose.tools.assert_equal(si1.model._signed_bounds(), [(0x0, 0x7fffffff), (-0x80000000, -0x1)]) nose.tools.assert_equal(si1.model._unsigned_bounds(), [(0x0, 0xffffffff)]) # # Addition # # Plain addition si1 = claripy.SI(bits=32, stride=1, lower_bound=-1, upper_bound=1) si2 = claripy.SI(bits=32, stride=1, lower_bound=-1, upper_bound=1) si3 = claripy.SI(bits=32, stride=1, lower_bound=-2, upper_bound=2) nose.tools.assert_true((si1 + si2).identical(si3)) si4 = claripy.SI(bits=32, stride=1, lower_bound=0xfffffffe, upper_bound=2) nose.tools.assert_true((si1 + si2).identical(si4)) si5 = claripy.SI(bits=32, stride=1, lower_bound=2, upper_bound=-2) nose.tools.assert_false((si1 + si2).identical(si5)) # Addition with overflowing cardinality si1 = claripy.SI(bits=8, stride=1, lower_bound=0, upper_bound=0xfe) si2 = claripy.SI(bits=8, stride=1, lower_bound=0xfe, upper_bound=0xff) nose.tools.assert_true((si1 + si2).model.is_top) # Addition that shouldn't get a TOP si1 = claripy.SI(bits=8, stride=1, lower_bound=0, upper_bound=0xfe) si2 = claripy.SI(bits=8, stride=1, lower_bound=0, upper_bound=0) nose.tools.assert_false((si1 + si2).model.is_top) # # Subtraction # si1 = claripy.SI(bits=8, stride=1, lower_bound=10, upper_bound=15) si2 = claripy.SI(bits=8, stride=1, lower_bound=11, upper_bound=12) si3 = claripy.SI(bits=8, stride=1, lower_bound=-2, upper_bound=4) nose.tools.assert_true((si1 - si2).identical(si3)) # # Multiplication # # integer multiplication si1 = claripy.SI(bits=32, to_conv=0xffff) si2 = claripy.SI(bits=32, to_conv=0x10000) si3 = claripy.SI(bits=32, to_conv=0xffff0000) nose.tools.assert_true((si1 * si2).identical(si3)) # intervals multiplication si1 = claripy.SI(bits=32, stride=1, lower_bound=10, upper_bound=15) si2 = claripy.SI(bits=32, stride=1, lower_bound=20, upper_bound=30) si3 = claripy.SI(bits=32, stride=1, lower_bound=200, upper_bound=450) nose.tools.assert_true((si1 * si2).identical(si3)) # # Division # # integer division si1 = claripy.SI(bits=32, to_conv=10) si2 = claripy.SI(bits=32, to_conv=5) si3 = claripy.SI(bits=32, to_conv=2) nose.tools.assert_true((si1 / si2).identical(si3)) si3 = claripy.SI(bits=32, to_conv=0) nose.tools.assert_true((si2 / si1).identical(si3)) # intervals division si1 = claripy.SI(bits=32, stride=1, lower_bound=10, upper_bound=100) si2 = claripy.SI(bits=32, stride=1, lower_bound=10, upper_bound=20) si3 = claripy.SI(bits=32, stride=1, lower_bound=0, upper_bound=10) nose.tools.assert_true((si1 / si2).identical(si3)) # # Comparisons # # -1 == 0xff si1 = claripy.SI(bits=8, stride=1, lower_bound=-1, upper_bound=-1) si2 = claripy.SI(bits=8, stride=1, lower_bound=0xff, upper_bound=0xff) nose.tools.assert_true(claripy.is_true(si1 == si2)) # -2 != 0xff si1 = claripy.SI(bits=8, stride=1, lower_bound=-2, upper_bound=-2) si2 = claripy.SI(bits=8, stride=1, lower_bound=0xff, upper_bound=0xff) nose.tools.assert_true(claripy.is_true(si1 != si2)) # [-2, -1] < [1, 2] (signed arithmetic) si1 = claripy.SI(bits=8, stride=1, lower_bound=1, upper_bound=2) si2 = claripy.SI(bits=8, stride=1, lower_bound=-2, upper_bound=-1) nose.tools.assert_true(claripy.is_true(si2.SLT(si1))) # [-2, -1] <= [1, 2] (signed arithmetic) nose.tools.assert_true(claripy.is_true(si2.SLE(si1))) # [0xfe, 0xff] > [1, 2] (unsigned arithmetic) nose.tools.assert_true(claripy.is_true(si2.UGT(si1))) # [0xfe, 0xff] >= [1, 2] (unsigned arithmetic) nose.tools.assert_true(claripy.is_true(si2.UGE(si1)))
def test_vsa_constraint_to_si(): # Set backend b = claripy.backend_vsa s = claripy.LightFrontend(claripy.backend_vsa) #pylint:disable=unused-variable SI = claripy.SI BVV = claripy.BVV claripy.vsa.strided_interval.allow_dsis = False # # If(SI == 0, 1, 0) == 1 # s1 = claripy.SI(bits=32, stride=1, lower_bound=0, upper_bound=2) ast_true = (claripy.If(s1 == BVV(0, 32), BVV(1, 1), BVV(0, 1)) == BVV(1, 1)) ast_false = (claripy.If(s1 == BVV(0, 32), BVV(1, 1), BVV(0, 1)) != BVV( 1, 1)) trueside_sat, trueside_replacement = b.constraint_to_si(ast_true) nose.tools.assert_equal(trueside_sat, True) nose.tools.assert_equal(len(trueside_replacement), 1) nose.tools.assert_true(trueside_replacement[0][0] is s1) # True side: claripy.SI<32>0[0, 0] nose.tools.assert_true( claripy.is_true(trueside_replacement[0][1] == claripy.SI( bits=32, stride=0, lower_bound=0, upper_bound=0))) falseside_sat, falseside_replacement = b.constraint_to_si(ast_false) nose.tools.assert_equal(falseside_sat, True) nose.tools.assert_equal(len(falseside_replacement), 1) nose.tools.assert_true(falseside_replacement[0][0] is s1) # False side; claripy.SI<32>1[1, 2] nose.tools.assert_true( claripy.is_true(falseside_replacement[0][1].identical( SI(bits=32, stride=1, lower_bound=1, upper_bound=2)))) # # Extract(0, 0, Concat(BVV(0, 63), If(SI == 0, 1, 0))) == 1 # s2 = claripy.SI(bits=32, stride=1, lower_bound=0, upper_bound=2) ast_true = (claripy.Extract( 0, 0, claripy.Concat(BVV(0, 63), claripy.If(s2 == 0, BVV(1, 1), BVV(0, 1)))) == 1) ast_false = (claripy.Extract( 0, 0, claripy.Concat(BVV(0, 63), claripy.If(s2 == 0, BVV(1, 1), BVV(0, 1)))) != 1) trueside_sat, trueside_replacement = b.constraint_to_si(ast_true) nose.tools.assert_equal(trueside_sat, True) nose.tools.assert_equal(len(trueside_replacement), 1) nose.tools.assert_true(trueside_replacement[0][0] is s2) # True side: claripy.SI<32>0[0, 0] nose.tools.assert_true( claripy.is_true(trueside_replacement[0][1].identical( SI(bits=32, stride=0, lower_bound=0, upper_bound=0)))) falseside_sat, falseside_replacement = b.constraint_to_si(ast_false) nose.tools.assert_equal(falseside_sat, True) nose.tools.assert_equal(len(falseside_replacement), 1) nose.tools.assert_true(falseside_replacement[0][0] is s2) # False side; claripy.SI<32>1[1, 2] nose.tools.assert_true( claripy.is_true(falseside_replacement[0][1].identical( SI(bits=32, stride=1, lower_bound=1, upper_bound=2)))) # # Extract(0, 0, ZeroExt(32, If(SI == 0, BVV(1, 32), BVV(0, 32)))) == 1 # s3 = claripy.SI(bits=32, stride=1, lower_bound=0, upper_bound=2) ast_true = (claripy.Extract( 0, 0, claripy.ZeroExt(32, claripy.If(s3 == 0, BVV(1, 32), BVV(0, 32)))) == 1) ast_false = (claripy.Extract( 0, 0, claripy.ZeroExt(32, claripy.If(s3 == 0, BVV(1, 32), BVV(0, 32)))) != 1) trueside_sat, trueside_replacement = b.constraint_to_si(ast_true) nose.tools.assert_equal(trueside_sat, True) nose.tools.assert_equal(len(trueside_replacement), 1) nose.tools.assert_true(trueside_replacement[0][0] is s3) # True side: claripy.SI<32>0[0, 0] nose.tools.assert_true( claripy.is_true(trueside_replacement[0][1].identical( SI(bits=32, stride=0, lower_bound=0, upper_bound=0)))) falseside_sat, falseside_replacement = b.constraint_to_si(ast_false) nose.tools.assert_equal(falseside_sat, True) nose.tools.assert_equal(len(falseside_replacement), 1) nose.tools.assert_true(falseside_replacement[0][0] is s3) # False side; claripy.SI<32>1[1, 2] nose.tools.assert_true( claripy.is_true(falseside_replacement[0][1].identical( SI(bits=32, stride=1, lower_bound=1, upper_bound=2)))) # # Extract(0, 0, ZeroExt(32, If(Extract(32, 0, (SI & claripy.SI)) < 0, BVV(1, 1), BVV(0, 1)))) # s4 = claripy.SI(bits=64, stride=1, lower_bound=0, upper_bound=0xffffffffffffffff) ast_true = (claripy.Extract( 0, 0, claripy.ZeroExt( 32, claripy.If( claripy.Extract(31, 0, (s4 & s4)).SLT(0), BVV(1, 32), BVV(0, 32)))) == 1) ast_false = (claripy.Extract( 0, 0, claripy.ZeroExt( 32, claripy.If( claripy.Extract(31, 0, (s4 & s4)).SLT(0), BVV(1, 32), BVV( 0, 32)))) != 1) trueside_sat, trueside_replacement = b.constraint_to_si(ast_true) nose.tools.assert_equal(trueside_sat, True) nose.tools.assert_equal(len(trueside_replacement), 1) nose.tools.assert_true(trueside_replacement[0][0] is s4) # True side: claripy.SI<32>0[0, 0] nose.tools.assert_true( claripy.is_true(trueside_replacement[0][1].identical( SI(bits=64, stride=1, lower_bound=-0x8000000000000000, upper_bound=-1)))) falseside_sat, falseside_replacement = b.constraint_to_si(ast_false) nose.tools.assert_equal(falseside_sat, True) nose.tools.assert_equal(len(falseside_replacement), 1) nose.tools.assert_true(falseside_replacement[0][0] is s4) # False side; claripy.SI<32>1[1, 2] nose.tools.assert_true( claripy.is_true(falseside_replacement[0][1].identical( SI(bits=64, stride=1, lower_bound=0, upper_bound=0x7fffffffffffffff))))
def _search_value(self): if self._arm: armins = self._string_to_insn(self._insbytes) if not self._arm64: if not self._armthumb: # ARM instructions if armins & 0x0C000000 == 0x04000000: # LDR thoughtval = armins & 0xFFF if thoughtval != self.value: raise ValueNotFoundError imm12 = self._imm(12) self.patch_value_expression = imm12.zero_extend( self.bits - 12) self.patch_bytes_expression = claripy.Concat( BVV(armins >> 12, 20), imm12) self._test_values = (1, 0xfff) elif armins & 0x0E000000 == 0x02000000: # Data processing w/ immediate shiftval = (armins & 0xF00) >> 7 thoughtval = armins & 0xFF thoughtval = ror(thoughtval, shiftval, 32) if thoughtval != self.value: raise ValueNotFoundError shift = self._imm(4, 'shift') imm8 = self._imm(8) self.patch_value_expression = claripy.RotateRight( imm8.zero_extend(32 - 8), shift.zero_extend(32 - 4) * 2) self.patch_bytes_expression = claripy.Concat( BVV(armins >> 12, 20), shift, imm8) self._test_values = (1, 0xff, 0xff000000) elif armins & 0x0E400090 == 0x00400090: # LDRH thoughtval = (armins & 0xF) | ((armins & 0xF00) >> 4) if thoughtval != self.value: raise ValueNotFoundError hinib = self._imm(4, 'hinib') lonib = self._imm(4, 'lonib') self.patch_value_expression = claripy.Concat( hinib, lonib).zero_extend(self.bits - 8) self.patch_bytes_expression = claripy.Concat( BVV(armins >> 12, 20), hinib, BVV((armins >> 4) & 0xF, 4), lonib) self._test_values = (1, 0xff) elif armins & 0x0E000000 == 0x0C000000: # Coprocessor data transfer # i.e. FLD/FST thoughtval = armins & 0xFF thoughtval *= 4 if thoughtval != self.value: raise ValueNotFoundError imm8 = self._imm(8) self.patch_value_expression = imm8.zero_extend( self.bits - 8) << 2 self.patch_bytes_expression = claripy.Concat( BVV(armins >> 8, 24), imm8) self._test_values = (4, 0x3fc) else: raise ValueNotFoundError else: # THUMB instructions # https://ece.uwaterloo.ca/~ece222/ARM/ARM7-TDMI-manual-pt3.pdf if self._inslen == 2: # 16 bit instructions if armins & 0xF000 in (0x9000, 0xA000): # SP-relative LDR/STR, also SP-addiition # page 26, 28 # unsigned offsets only, 10 bit imm stored w/o last two bits thoughtval = armins & 0xFF thoughtval *= 4 if thoughtval != self.value: raise ValueNotFoundError imm8 = self._imm(8) self.patch_value_expression = imm8.zero_extend( self.bits - 8) << 2 self.patch_bytes_expression = claripy.Concat( BVV(armins >> 8, 8), imm8) self._test_values = (4, 0x3fc) elif armins & 0xFF00 == 0xB000: # Add/sub offset to SP # page 30 # uses sign bit, 9 bit imm stored w/o last two bits thoughtval = armins & 0x7F thoughtval *= 4 if thoughtval != self.value: raise ValueNotFoundError imm7 = self._imm(7) self.patch_value_expression = imm7.zero_extend( self.bits - 7) << 2 self.patch_bytes_expression = claripy.Concat( BVV(armins >> 7, 9), imm7) self._test_values = (4, 0x1fc) elif armins & 0xFC00 == 0x1C00: # ADD/SUB (immediate format) # page 7 # uses sign bit, 3 bit immediate thoughtval = (armins & 0x01C0) >> 6 if thoughtval != self.value: raise ValueNotFoundError imm3 = self._imm(3) self.patch_value_expression = imm3.zero_extend( self.bits - 3) self.patch_bytes_expression = claripy.Concat( BVV(armins >> 9, 7), imm3, BVV(armins & 0x3F, 6)) self._test_values = (1, 7) elif armins & 0xE000 == 0x2000: # Move/Compare/Add/Subtract immediate # page 9 # Unsigned 8 bit immediate thoughtval = armins & 0xFF if thoughtval != self.value: raise ValueNotFoundError imm8 = self._imm(8) self.patch_value_expression = imm8.zero_extend( self.bits - 8) self.patch_bytes_expression = claripy.Concat( BVV(armins >> 8, 8), imm8) self._test_values = (1, 0xff) elif armins & 0xF000 == 0x6000: # Register-relative LDR/STR # page 22 # unsigned 7 bit imm stored w/o last two bits thoughtval = ((armins >> 6) & 0x1F) << 2 if thoughtval != self.value: raise ValueNotFoundError imm5 = self._imm(5) self.patch_value_expression = imm5.zero_extend( self.bits - 5) << 2 self.patch_bytes_expression = claripy.Concat( BVV(armins >> 11, 5), imm5, BVV(armins & 0x3F, 6)) self._test_values = (4, 0x7c) elif armins & 0xF000 == 0x7000: # Register-relative LDRB/STRB # page 22 # unsigned 5 bit imm thoughtval = (armins >> 6) & 0x1F if thoughtval != self.value: raise ValueNotFoundError imm5 = self._imm(5) self.patch_value_expression = imm5.zero_extend( self.bits - 5) self.patch_bytes_expression = claripy.Concat( BVV(armins >> 11, 5), imm5, BVV(armins & 0x3F, 6)) self._test_values = (1, 0x1f) else: raise ValueNotFoundError elif self._inslen == 4: # 32 bit instructions # http://read.pudn.com/downloads159/doc/709030/Thumb-2SupplementReferenceManual.pdf if armins & 0xFE1F0000 == 0xF81F0000 or \ armins & 0xFE800000 == 0xF8800000: # Load/Store # page 66, formats 1-2 # imm12 with designated sign bit thoughtval = armins & 0xFFF if thoughtval != self.value: raise ValueNotFoundError imm12 = self._imm(12) self.patch_value_expression = imm12.zero_extend( self.bits - 12) self.patch_bytes_expression = claripy.Concat( BVV(armins >> 12, 20), imm12) self._test_values = (1, 0xfff) elif armins & 0xFE800900 == 0xF8000800: # Load/Store # page 66, formats 3-4 # imm8 with designated sign bit thoughtval = armins & 0xFF if thoughtval != self.value: raise ValueNotFoundError imm8 = self._imm(8) self.patch_value_expression = imm8.zero_extend( self.bits - 8) self.patch_bytes_expression = claripy.Concat( BVV(armins >> 8, 24), imm8) self._test_values = (1, 0xff) elif armins & 0xFE800900 == 0xF8000900: # Load/Store # page 66, formats 5-6 # imm8, sign extended thoughtval = armins & 0x7F if armins & 0x80 == 0x80: thoughtval = (thoughtval ^ 0x7F) + 1 if thoughtval != self.value: raise ValueNotFoundError imm8 = self._imm(8) self.patch_value_expression = imm8.sign_extend( self.bits - 8) self.patch_bytes_expression = claripy.Concat( BVV(armins >> 8, 24), imm8) self._test_values = (-0x80, 0x7f) elif armins & 0xFB408000 == 0xF2000000: # Add/Sub # page 53, format 2 # 12 bit immediate split into 3 bitfields thoughtval = armins & 0xFF thoughtval |= (armins & 0x7000) >> 4 thoughtval |= (armins & 0x04000000) >> 15 if thoughtval != self.value: raise ValueNotFoundError imm8 = self._imm(8) imm3 = self._imm(3) imm1 = self._imm(1) self.patch_value_expression = claripy.Concat( imm1, imm3, imm8).zero_extend(self.bits - 12) self.patch_bytes_expression = claripy.Concat( BVV(armins >> 27, 5), imm1, BVV((armins & 0x03FF8000) >> 15, 11), imm3, BVV((armins & 0xF00) >> 8, 4), imm8) self._test_values = (1, 0xfff) elif armins & 0xFB408000 == 0xF2400000: # Move # page 53, format 3 # 16 bit immediate split into 4 bitfields thoughtval = armins & 0xFF thoughtval |= (armins & 0x7000) >> 4 thoughtval |= (armins & 0x04000000) >> 15 thoughtval |= (armins & 0xF0000) >> 4 if thoughtval != self.value: raise ValueNotFoundError imm8 = self._imm(8) imm3 = self._imm(3) imm1 = self._imm(1) imm4 = self._imm(1) self.patch_value_expression = claripy.Concat( imm4, imm1, imm3, imm8).zero_extend(self.bits - 12) self.patch_bytes_expression = claripy.Concat( BVV(armins >> 27, 5), imm1, BVV((armins & 0x03F00000) >> 20, 6), imm4, BVV((armins & 0x00008000) >> 15, 1), imm3, BVV((armins & 0xF00) >> 8, 4), imm8) self._test_values = (1, 0xffff) elif armins & 0xFA008000 == 0xF0000000: # Data processing, modified 12 bit imm, aka EVIL # page 53 # wow. just. wow. imm12 = armins & 0xFF imm12 |= (armins & 0x7000) >> 4 imm12 |= (armins & 0x04000000) >> 15 # decoding algorithm from page 93 if imm12 & 0xC00 == 0: if imm12 & 0x300 == 0: thoughtval = imm12 elif imm12 & 0x300 == 0x100: thoughtval = imm12 & 0xFF thoughtval |= thoughtval << 16 elif imm12 & 0x300 == 0x200: thoughtval = (imm12 & 0xFF) << 8 thoughtval |= thoughtval << 16 elif imm12 & 0x300 == 0x300: thoughtval = imm12 & 0xFF thoughtval |= thoughtval << 8 thoughtval |= thoughtval << 16 else: thoughtval = ror(0x80 | (imm12 & 0x7F), imm12 >> 7, 32) if thoughtval != self.value: raise ValueNotFoundError imm12 = self._imm(12) ITE = claripy.If CAT = claripy.Concat ROR = claripy.RotateRight imm8 = imm12[7:0] imm7 = imm12[6:0] imm3 = imm12[10:8] imm1 = imm12[11] zero = BVV(0, 8) bit = BVV(1, 1) monster = ITE( imm12[11:10] == 0, ITE( imm12[9] == 0, ITE(imm12[8] == 0, imm12[7:0].zero_extend(32 - 8), CAT(zero, imm8, zero, imm8)), ITE(imm12[8] == 0, CAT(imm8, zero, imm8, zero), CAT(imm8, imm8, imm8, imm8))), ROR( CAT(bit, imm7).zero_extend(32 - 8), imm12[11:7].zero_extend(32 - 5))) self.patch_value_expression = monster self.patch_bytes_expression = claripy.Concat( BVV(armins >> 27, 5), imm1, BVV((armins & 0x03FF8000) >> 15, 11), imm3, BVV((armins & 0xF00) >> 8, 4), imm8) self._test_values = (0xff00ff00, 0x00ff00ff, 0xffffffff, 0xff, 0xff000000) else: raise ValueNotFoundError else: raise FidgetUnsupportedError( "You found a THUMB instruction longer than 32 bits??" ) else: self.bit_length = 64 # aarch64 instructions # can't find a reference doc?????? I'm pulling these from VEX, guest_arm64_toIR.c if armins & 0x7f800000 in (0x28800000, 0x29800000, 0x29000000): # LDP/SDP # line 4791 # 7 bit immediate signed offset, scaled by load size (from MSB) shift = 3 if armins & 0x80000000 else 2 simm7 = (armins & 0x3f8000) >> 15 simm7 = resign_int(simm7, 7) simm7 <<= shift if simm7 != self.value: raise ValueNotFoundError imm7 = self._imm(7) self.patch_value_expression = imm7.sign_extend(self.bits - 7) << shift self.patch_bytes_expression = claripy.Concat( BVV((armins & 0xffc00000) >> 22, 10), imm7, BVV(armins & 0x7fff, 15)) self._test_values = (-0x40 << shift, 0x3f << shift) elif (armins & 0x3f800000 == 0x39000000) or \ (armins & 0x3f800000 == 0x39800000 and \ ((armins >> 30) | ((armins >> 22) & 1)) in (4, 2, 3, 0, 1)): # LDR/STR, LDRS # line 4639, 5008 # 12 bit immediate unsigned offset, scaled by load size (from 2 MSB) shift = (armins & 0xc0000000) >> 30 offs = (armins & 0x3ffc00) >> 10 offs <<= shift if offs != self.value: raise ValueNotFoundError imm12 = self._imm(12) self.patch_value_expression = imm12.zero_extend( self.bits - 12) << shift self.patch_bytes_expression = claripy.Concat( BVV((armins & 0xffc00000) >> 22, 10), imm12, BVV(armins & 0x3ff, 10)) self._test_values = (1 << shift, 0xfff << shift) elif armins & 0x1f000000 == 0x11000000: # ADD/SUB imm # line 2403 # 12 bit shifted unsigned immediate if not armins & 0x80000000: self.bit_length = 32 shift = (armins >> 22) & 3 imm12 = (armins >> 10) & 0xfff imm12 <<= 12 * shift if imm12 != self.value: raise ValueNotFoundError shift = self._imm(1, 'shift') imm12 = self._imm(12) shift_full = shift.zero_extend(self.bits - 1) * 12 self.patch_value_expression = imm12.zero_extend( self.bits - 12) << shift_full self.patch_bytes_expression = claripy.Concat( BVV(armins >> 24, 8), BVV(0, 1), shift, imm12, BVV(armins & 0x3ff, 10)) self._test_values = (1, 0xfff, 0xfff000) elif armins & 0x3fa00000 == 0x38000000: # LDUR/STUR # Line 4680 # 9 bit signed immediate offset imm9 = (armins >> 12) & 0x1ff imm9 = resign_int(imm9, 9) if imm9 != self.value: raise ValueNotFoundError imm9 = self._imm(9) self.patch_value_expression = imm9.sign_extend(self.bits - 9) self.patch_bytes_expression = claripy.Concat( BVV(armins >> 21, 11), imm9, BVV(armins & 0xfff, 12)) self._test_values = (-0x100, 0xff) else: raise ValueNotFoundError if not self.sanity_check(): raise ValueNotFoundError else: insn = self._string_to_insn(self._insbytes) insn = BVV(insn, self._inslen * 8) for word_size in (64, 32, 16, 8): if word_size > self.bits: continue for bit_offset in xrange(0, insn.length - word_size + 1, 8): result = insn[bit_offset + word_size - 1:bit_offset] result = result.sign_extend(self.bits - word_size) if claripy.is_true(result == self.value): imm = self._imm(word_size) self.patch_value_expression = imm.sign_extend( self.bits - word_size) if bit_offset + word_size >= insn.length: acc = imm else: acc = claripy.Concat( insn[insn.length - 1:bit_offset + word_size], imm) if bit_offset != 0: acc = claripy.Concat(acc, insn[bit_offset - 1:0]) if self._project.arch.memory_endness == 'Iend_LE': self.patch_bytes_offset = bit_offset / 8 else: self.patch_bytes_offset = self._inslen - ( bit_offset + word_size) / 8 self.patch_bytes_size = word_size / 8 self.patch_bytes_expression = acc self._test_values = (-(1 << word_size) >> 1, ((1 << word_size) >> 1) - 1) if self.sanity_check(): break # found if self._project.arch.name == 'PPC64': # On PPC64, the lowest two bits of immediate values can be used for other things # Mask those out result = (result & ~3).sign_extend(self.bits - word_size) if not claripy.is_true(result == self.value): continue imm = self._imm(word_size - 2) self.patch_value_expression = claripy.Concat( imm, BVV(0, 2)).sign_extend(self.bits - word_size) if bit_offset + word_size >= insn.length: acc = imm else: acc = claripy.Concat( insn[insn.length - 1:bit_offset + word_size], imm) acc = claripy.Concat(acc, insn[bit_offset + 1:0]) if self._project.arch.memory_endness == 'Iend_LE': self.patch_bytes_offset = bit_offset / 8 else: self.patch_bytes_offset = self._inslen - ( bit_offset + word_size) / 8 self.patch_bytes_size = word_size / 8 self.patch_bytes_expression = acc self._test_values = (-(1 << word_size) >> 1, ((1 << word_size) >> 1) - 4) if self.sanity_check(): break # found else: # inner loop did not break: not found continue # inner loop broke: found break else: # outer loop did not break: inner loop did not break: not found raise ValueNotFoundError # outer loop broke: inner loop broke: found return
def convert_claripy_bool_ast_core(self, cond, memo): if isinstance(cond, ailment.Expr.Expression): return cond if cond.op == "BoolS" and claripy.is_true(cond): return cond if cond.args[0] in self._condition_mapping: return self._condition_mapping[cond.args[0]] def _binary_op_reduce(op, args, annotations: Iterable[claripy.Annotation], signed=False): r = None for arg in args: if r is None: r = self.convert_claripy_bool_ast(arg, memo=memo) else: try: tag_annotation = next(iter(anno for anno in annotations if isinstance(anno, TagsAnnotation))) tags = tag_annotation.tags except StopIteration: tags = {} r = ailment.Expr.BinaryOp(None, op, (r, self.convert_claripy_bool_ast(arg, memo=memo)), signed, **tags ) return r def _unary_op_reduce(op, arg, annotations: Iterable[claripy.Annotation]): r = self.convert_claripy_bool_ast(arg, memo=memo) try: tag_annotation = next(iter(anno for anno in annotations if isinstance(anno, TagsAnnotation))) tags = tag_annotation.tags except StopIteration: tags = {} return ailment.Expr.UnaryOp(None, op, r, **tags) _mapping = { 'Not': lambda cond_: _unary_op_reduce('Not', cond_.args[0], cond_.annotations), 'And': lambda cond_: _binary_op_reduce('LogicalAnd', cond_.args, cond_.annotations), 'Or': lambda cond_: _binary_op_reduce('LogicalOr', cond_.args, cond_.annotations), '__le__': lambda cond_: _binary_op_reduce('CmpLE', cond_.args, cond_.annotations, signed=True), 'SLE': lambda cond_: _binary_op_reduce('CmpLE', cond_.args, cond_.annotations, signed=True), '__lt__': lambda cond_: _binary_op_reduce('CmpLT', cond_.args, cond_.annotations, signed=True), 'SLT': lambda cond_: _binary_op_reduce('CmpLT', cond_.args, cond_.annotations, signed=True), 'UGT': lambda cond_: _binary_op_reduce('CmpGT', cond_.args, cond_.annotations), 'UGE': lambda cond_: _binary_op_reduce('CmpGE', cond_.args, cond_.annotations), '__gt__': lambda cond_: _binary_op_reduce('CmpGT', cond_.args, cond_.annotations, signed=True), '__ge__': lambda cond_: _binary_op_reduce('CmpGE', cond_.args, cond_.annotations, signed=True), 'SGT': lambda cond_: _binary_op_reduce('CmpGT', cond_.args, cond_.annotations, signed=True), 'SGE': lambda cond_: _binary_op_reduce('CmpGE', cond_.args, cond_.annotations, signed=True), 'ULT': lambda cond_: _binary_op_reduce('CmpLT', cond_.args, cond_.annotations), 'ULE': lambda cond_: _binary_op_reduce('CmpLE', cond_.args, cond_.annotations), '__eq__': lambda cond_: _binary_op_reduce('CmpEQ', cond_.args, cond_.annotations), '__ne__': lambda cond_: _binary_op_reduce('CmpNE', cond_.args, cond_.annotations), '__add__': lambda cond_: _binary_op_reduce('Add', cond_.args, cond_.annotations, signed=False), '__sub__': lambda cond_: _binary_op_reduce('Sub', cond_.args, cond_.annotations), '__mul__': lambda cond_: _binary_op_reduce('Mul', cond_.args, cond_.annotations), '__xor__': lambda cond_: _binary_op_reduce('Xor', cond_.args, cond_.annotations), '__or__': lambda cond_: _binary_op_reduce('Or', cond_.args, cond_.annotations, signed=False), '__and__': lambda cond_: _binary_op_reduce('And', cond_.args, cond_.annotations), '__lshift__': lambda cond_: _binary_op_reduce('Shl', cond_.args, cond_.annotations), '__rshift__': lambda cond_: _binary_op_reduce('Sar', cond_.args, cond_.annotations), 'LShR': lambda cond_: _binary_op_reduce('Shr', cond_.args, cond_.annotations), 'BVV': lambda cond_: ailment.Expr.Const(None, None, cond_.args[0], cond_.size()), 'BoolV': lambda cond_: ailment.Expr.Const(None, None, True, 1) if cond_.args[0] is True else ailment.Expr.Const(None, None, False, 1), 'Extract': lambda cond_: self._convert_extract(*cond_.args, cond_.annotations, memo=memo), } if cond.op in _mapping: return _mapping[cond.op](cond) raise NotImplementedError(("Condition variable %s has an unsupported operator %s. " "Consider implementing.") % (cond, cond.op))
def test_rcr(): p = angr.Project(os.path.join(os.path.dirname(__file__), '..', '..', 'binaries', 'tests', 'i386', 'rcr_test'), auto_load_libs=False) result = p.factory.successors(p.factory.entry_state()).successors[0] assert claripy.is_true(result.regs.cl == 8)