def map_region(self, addr, length, permissions, init_zero=False): if o.TRACK_MEMORY_MAPPING not in self.state.options: return if self.state.se.symbolic(addr): raise SimMemoryError("cannot map region with a symbolic address") if isinstance(addr, claripy.ast.bv.BV): addr = self.state.se.max_int(addr) base_page_num = addr / self._page_size # round length pages = length / self._page_size if length % self._page_size > 0: pages += 1 if isinstance(permissions, (int, long)): permissions = claripy.BVV(permissions, 3) for page in xrange(pages): page_id = base_page_num + page self._pages[page_id] = self._create_page(page_id, permissions=permissions) self._symbolic_addrs[page_id] = set() if init_zero: if self.state is not None: self.state.scratch.push_priv(True) mo = SimMemoryObject(claripy.BVV(0, self._page_size * self.byte_width), page_id*self._page_size, byte_width=self.byte_width) self._apply_object_to_page(page_id*self._page_size, mo, page=self._pages[page_id]) if self.state is not None: self.state.scratch.pop_priv()
def unmap_region(self, addr, length): if o.TRACK_MEMORY_MAPPING not in self.state.options: return if self.state.se.symbolic(addr): raise SimMemoryError("cannot unmap region with a symbolic address") if isinstance(addr, claripy.ast.bv.BV): addr = self.state.se.max_int(addr) base_page_num = addr / self._page_size pages = length / self._page_size if length % self._page_size > 0: pages += 1 # this check should not be performed when constructing a CFG if self.state.mode != 'fastpath': for page in xrange(pages): if base_page_num + page not in self._pages: l.warning( "unmap_region received address and length combination is not mapped" ) return for page in xrange(pages): del self._pages[base_page_num + page] del self._symbolic_addrs[base_page_num + page]
def replace_memory_object(self, old, new_content): """ Replaces the memory object `old` with a new memory object containing `new_content`. :param old: A SimMemoryObject (i.e., one from :func:`memory_objects_for_hash()` or :func:` memory_objects_for_name()`). :param new_content: The content (claripy expression) for the new memory object. :returns: the new memory object """ if old.object.size() != new_content.size(): raise SimMemoryError( "memory objects can only be replaced by the same length content" ) new = SimMemoryObject(new_content, old.base, byte_width=self.byte_width) for p in self._containing_pages_mo(old): self._get_page(p / self._page_size, write=True).replace_mo(self.state, old, new) if isinstance(new.object, claripy.ast.BV): for b in range(old.base, old.base + old.length): self._update_mappings(b, new.object) return new
def map_region(self, addr, length, permissions, init_zero=False): if o.TRACK_MEMORY_MAPPING not in self.state.options: return if self.state.solver.symbolic(addr): raise SimMemoryError("cannot map region with a symbolic address") if isinstance(addr, claripy.ast.bv.BV): addr = self.state.solver.max_int(addr) base_page_num = addr // self._page_size # round length pages = length // self._page_size if length % self._page_size > 0: pages += 1 # this check should not be performed when constructing a CFG if self.state.mode != 'fastpath': for page in range(pages): page_id = base_page_num + page if page_id * self._page_size in self: err = "map_page received address and length combination which contained mapped page" l.warning(err) raise SimMemoryError(err) if isinstance(permissions, int): permissions = claripy.BVV(permissions, 3) for page in range(pages): page_id = base_page_num + page self._pages[page_id] = self._create_page(page_id, permissions=permissions) self._symbolic_addrs[page_id] = set() if init_zero: if self.state is not None: self.state.scratch.push_priv(True) mo = SimMemoryObject(claripy.BVV( 0, self._page_size * self.byte_width), page_id * self._page_size, byte_width=self.byte_width) self._apply_object_to_page(page_id * self._page_size, mo, page=self._pages[page_id]) if self.state is not None: self.state.scratch.pop_priv()
def _store_with_merge(self, req): req._adjust_condition(self.state) dst = req.addr cnt = req.data size = req.size endness = req.endness req.stored_values = [ ] if options.ABSTRACT_MEMORY not in self.state.options: raise SimMemoryError('store_with_merge is not supported without abstract memory.') l.debug("Doing a store with merging...") addrs = self.concretize_write_addr(dst) if len(addrs) == 1: l.debug("... concretized to 0x%x", addrs[0]) else: l.debug("... concretized to %d values", len(addrs)) if size is None: # Full length length = len(cnt) else: raise NotImplementedError() for addr in addrs: # First we load old values old_val = self._read_from(addr, length // self.state.arch.byte_width) assert isinstance(old_val, claripy.Bits) # FIXME: This is a big hack def is_reversed(o): if isinstance(o, claripy.Bits) and o.op == 'Reverse': return True return False def can_be_reversed(o): om = o._model_vsa if isinstance(om, claripy.vsa.StridedInterval) and om.is_integer: return True return False if endness == 'Iend_LE': cnt = cnt.reversed reverse_it = False if is_reversed(cnt): if is_reversed(old_val): cnt = cnt.args[0] old_val = old_val.args[0] reverse_it = True elif can_be_reversed(old_val): cnt = cnt.args[0] reverse_it = True if isinstance(old_val, (int, long, claripy.bv.BVV)): merged_val = self.state.se.SI(bits=len(old_val), to_conv=old_val) else: merged_val = old_val merged_val = merged_val.union(cnt) if reverse_it: merged_val = merged_val.reversed # Write the new value self.store(addr, merged_val, size=size) req.stored_values.append(merged_val) req.completed = True # TODO: revisit the following lines req.constraints = [ ] return req
def _store(self, req): l.debug("Doing a store...") req._adjust_condition(self.state) max_bytes = req.data.length//self.state.arch.byte_width if req.size is None: req.size = max_bytes if self.state.solver.symbolic(req.size): if options.AVOID_MULTIVALUED_WRITES in self.state.options: return req if options.CONCRETIZE_SYMBOLIC_WRITE_SIZES in self.state.options: new_size = self.state.solver.eval(req.size) self.state.add_constraints(req.size == new_size) req.size = new_size if self.state.solver.symbolic(req.addr) and options.AVOID_MULTIVALUED_WRITES in self.state.options: return req if not self.state.solver.symbolic(req.size) and self.state.solver.eval(req.size) > req.data.length//self.state.arch.byte_width: raise SimMemoryError("Not enough data for requested storage size (size: {}, data: {})".format(req.size, req.data)) if self.state.solver.symbolic(req.size): self.state.add_constraints(self.state.solver.ULE(req.size, max_bytes)) # # First, resolve the addresses # try: req.actual_addresses = sorted(self.concretize_write_addr(req.addr)) except SimMemoryError: if options.CONSERVATIVE_WRITE_STRATEGY in self.state.options: return req else: raise if type(req.addr) not in (int, long) and req.addr.symbolic: conditional_constraint = self.state.solver.Or(*[ req.addr == a for a in req.actual_addresses ]) if (conditional_constraint.symbolic or # if the constraint is symbolic conditional_constraint.is_false()): # if it makes the state go unsat req.constraints.append(conditional_constraint) # # Prepare memory objects # # If we have only one address to write to we handle it as concrete, disregarding symbolic or not is_size_symbolic = self.state.solver.symbolic(req.size) is_addr_symbolic = self.state.solver.symbolic(req.addr) if not is_size_symbolic and len(req.actual_addresses) == 1: store_list = self._store_fully_concrete(req.actual_addresses[0], req.size, req.data, req.endness, req.condition) elif not is_addr_symbolic: store_list = self._store_symbolic_size(req.addr, req.size, req.data, req.endness, req.condition) elif not is_size_symbolic: store_list = self._store_symbolic_addr(req.addr, req.actual_addresses, req.size, req.data, req.endness, req.condition) else: store_list = self._store_fully_symbolic(req.addr, req.actual_addresses, req.size, req.data, req.endness, req.condition) # # store it!!! # req.stored_values = [] if (self.category == 'mem' and options.SIMPLIFY_MEMORY_WRITES in self.state.options) or \ (self.category == 'reg' and options.SIMPLIFY_REGISTER_WRITES in self.state.options): for store_item in store_list: store_item['value'] = self.state.solver.simplify(store_item['value']) if req.endness == "Iend_LE" or (req.endness is None and self.endness == "Iend_LE"): store_item['value'] = store_item['value'].reversed req.stored_values.append(store_item['value']) self._insert_memory_object(store_item['value'], store_item['addr'], store_item['size']) else: for store_item in store_list: if req.endness == "Iend_LE" or (req.endness is None and self.endness == "Iend_LE"): store_item['value'] = store_item['value'].reversed req.stored_values.append(store_item['value']) self._insert_memory_object(store_item['value'], store_item['addr'], store_item['size']) l.debug("... done") req.completed = True return req
def __changed_bytes(self, other): """ Gets the set of changed bytes between `self` and `other`. :type other: SimPagedMemory :returns: A set of differing bytes. """ if self._page_size != other._page_size: raise SimMemoryError( "SimPagedMemory page sizes differ. This is asking for disaster." ) our_pages = set(self._pages.keys()) their_pages = set(other._pages.keys()) their_additions = their_pages - our_pages our_additions = our_pages - their_pages common_pages = our_pages & their_pages candidates = set() for p in their_additions: candidates.update(other._pages[p].keys()) for p in our_additions: candidates.update(self._pages[p].keys()) for p in common_pages: our_page = self._pages[p] their_page = other._pages[p] if our_page is their_page: continue our_keys = set(our_page.keys()) their_keys = set(their_page.keys()) changes = (our_keys - their_keys) | (their_keys - our_keys) | { i for i in (our_keys & their_keys) if our_page.load_mo( self.state, i) is not their_page.load_mo(self.state, i) } candidates.update(changes) #both_changed = our_changes & their_changes #ours_changed_only = our_changes - both_changed #theirs_changed_only = their_changes - both_changed #both_deleted = their_deletions & our_deletions #ours_deleted_only = our_deletions - both_deleted #theirs_deleted_only = their_deletions - both_deleted differences = set() for c in candidates: if c not in self and c in other: differences.add(c) elif c in self and c not in other: differences.add(c) else: if type(self[c]) is not SimMemoryObject: self[c] = SimMemoryObject(self.state.se.BVV( ord(self[c]), self.byte_width), c, byte_width=self.byte_width) if type(other[c]) is not SimMemoryObject: other[c] = SimMemoryObject(self.state.se.BVV( ord(other[c]), self.byte_width), c, byte_width=self.byte_width) if c in self and self[c] != other[c]: # Try to see if the bytes are equal self_byte = self[c].bytes_at(c, 1) other_byte = other[c].bytes_at(c, 1) if self_byte is not other_byte: #l.debug("%s: offset %x, two different bytes %s %s from %s %s", self.id, c, # self_byte, other_byte, # self[c].object.model, other[c].object.model) differences.add(c) else: # this means the byte is in neither memory pass return differences