def add_lib_handler(self, libimp, namespace): """Add search for handler based on a @libimp libimp instance Known functions will be looked by {name}_symb or {name}_{ord}_symb in the @namespace """ namespace = dict( (force_bytes(name), func) for name, func in viewitems(namespace)) # lambda cannot contain statement def default_func(dse): fname = libimp.fad2cname[dse.jitter.pc] if isinstance(fname, tuple): fname = b"%s_%d_symb" % (force_bytes(fname[0]), fname[1]) else: fname = b"%s_symb" % force_bytes(fname) raise RuntimeError("Symbolic stub '%s' not found" % fname) for addr, fname in viewitems(libimp.fad2cname): if isinstance(fname, tuple): fname = b"%s_%d_symb" % (force_bytes(fname[0]), fname[1]) else: fname = b"%s_symb" % force_bytes(fname) func = namespace.get(fname, None) if func is not None: self.add_handler(addr, func) else: self.add_handler(addr, default_func)
def default_func(dse): fname = libimp.fad2cname[dse.jitter.pc] if isinstance(fname, tuple): fname = b"%s_%d_symb" % (force_bytes(fname[0]), fname[1]) else: fname = b"%s_symb" % force_bytes(fname) raise RuntimeError("Symbolic stub '%s' not found" % fname)
def __init__(self, *args, **kwargs): Sandbox.__init__(self, *args, **kwargs) # Pre-stack some arguments if self.options.mimic_env: env_ptrs = [] for env in self.envp: env = force_bytes(env) env += b"\x00" self.jitter.cpu.SP -= len(env) ptr = self.jitter.cpu.SP self.jitter.vm.set_mem(ptr, env) env_ptrs.append(ptr) argv_ptrs = [] for arg in self.argv: arg = force_bytes(arg) arg += b"\x00" self.jitter.cpu.SP -= len(arg) ptr = self.jitter.cpu.SP self.jitter.vm.set_mem(ptr, arg) argv_ptrs.append(ptr) self.jitter.push_uint64_t(0) for ptr in reversed(env_ptrs): self.jitter.push_uint64_t(ptr) self.jitter.push_uint64_t(0) for ptr in reversed(argv_ptrs): self.jitter.push_uint64_t(ptr) self.jitter.push_uint64_t(len(self.argv)) self.jitter.cpu.LR = self.CALL_FINISH_ADDR # Set the runtime guard self.jitter.add_breakpoint(self.CALL_FINISH_ADDR, self.__class__.code_sentinelle)
def canon_libname_libfunc(libname, libfunc): libname = force_bytes(libname) dn = libname.split(b'.')[0] if isinstance(libfunc, int_types): return str(dn), libfunc else: libfunc = force_bytes(libfunc) return b"%s_%s" % (dn, libfunc)
def __init__(self, loc_db, *args, **kwargs): super(Sandbox_Linux_ppc32b, self).__init__(loc_db, *args, **kwargs) # Init stack self.jitter.stack_size = self.STACK_SIZE self.jitter.stack_base = self.STACK_BASE self.jitter.init_stack() self.jitter.cpu.R1 -= 8 # Pre-stack some arguments if self.options.mimic_env: env_ptrs = [] for env in self.envp: env = force_bytes(env) env += b"\x00" self.jitter.cpu.R1 -= len(env) ptr = self.jitter.cpu.R1 self.jitter.vm.set_mem(ptr, env) env_ptrs.append(ptr) argv_ptrs = [] for arg in self.argv: arg = force_bytes(arg) arg += b"\x00" self.jitter.cpu.R1 -= len(arg) ptr = self.jitter.cpu.R1 self.jitter.vm.set_mem(ptr, arg) argv_ptrs.append(ptr) self.jitter.push_uint32_t(0) for ptr in reversed(env_ptrs): self.jitter.push_uint32_t(ptr) self.jitter.cpu.R5 = self.jitter.cpu.R1 # envp self.jitter.push_uint32_t(0) for ptr in reversed(argv_ptrs): self.jitter.push_uint32_t(ptr) self.jitter.cpu.R4 = self.jitter.cpu.R1 # argv self.jitter.cpu.R3 = len(self.argv) # argc self.jitter.push_uint32_t(self.jitter.cpu.R3) self.jitter.cpu.R6 = 0 # auxp self.jitter.cpu.R7 = 0 # termination function # From the glibc, we should push a 0 here to distinguish a # dynamically linked executable from a statically linked one. # We actually do not do it and attempt to be somehow compatible # with both types of executables. #self.jitter.push_uint32_t(0) self.jitter.cpu.LR = self.CALL_FINISH_ADDR # Set the runtime guard self.jitter.add_breakpoint( self.CALL_FINISH_ADDR, self.__class__.code_sentinelle )
def __init__(self, *args, **kwargs): super(Sandbox_Linux_ppc32b, self).__init__(*args, **kwargs) # Init stack self.jitter.stack_size = self.STACK_SIZE self.jitter.stack_base = self.STACK_BASE self.jitter.init_stack() self.jitter.cpu.R1 -= 8 # Pre-stack some arguments if self.options.mimic_env: env_ptrs = [] for env in self.envp: env = force_bytes(env) env += b"\x00" self.jitter.cpu.R1 -= len(env) ptr = self.jitter.cpu.R1 self.jitter.vm.set_mem(ptr, env) env_ptrs.append(ptr) argv_ptrs = [] for arg in self.argv: arg = force_bytes(arg) arg += b"\x00" self.jitter.cpu.R1 -= len(arg) ptr = self.jitter.cpu.R1 self.jitter.vm.set_mem(ptr, arg) argv_ptrs.append(ptr) self.jitter.push_uint32_t(0) for ptr in reversed(env_ptrs): self.jitter.push_uint32_t(ptr) self.jitter.cpu.R5 = self.jitter.cpu.R1 # envp self.jitter.push_uint32_t(0) for ptr in reversed(argv_ptrs): self.jitter.push_uint32_t(ptr) self.jitter.cpu.R4 = self.jitter.cpu.R1 # argv self.jitter.cpu.R3 = len(self.argv) # argc self.jitter.push_uint32_t(self.jitter.cpu.R3) self.jitter.cpu.R6 = 0 # auxp self.jitter.cpu.R7 = 0 # termination function # From the glibc, we should push a 0 here to distinguish a # dynamically linked executable from a statically linked one. # We actually do not do it and attempt to be somehow compatible # with both types of executables. #self.jitter.push_uint32_t(0) self.jitter.cpu.LR = self.CALL_FINISH_ADDR # Set the runtime guard self.jitter.add_breakpoint( self.CALL_FINISH_ADDR, self.__class__.code_sentinelle )
def get_name_location(self, name): """ Return the LocKey of @name if any, None otherwise. @name: target name """ name = force_bytes(name) return self._name_to_loc_key.get(name)
def add_name(self, name): name = force_bytes(name) name = name + b"\x00" if name in self.content: return self.content.find(name) n = len(self.content) self.content = bytes(self.content) + name return n
def getsectionbyname(self, name): name = force_bytes(name) for s in self.sh: try: if s.sh.name.strip(b'\x00') == name: return s except UnicodeDecodeError: pass return None
def get_or_create_name_location(self, name): """ Return the LocKey of @name if any, create one otherwise. @name: target name """ name = force_bytes(name) loc_key = self._name_to_loc_key.get(name) if loc_key is not None: return loc_key return self.add_location(name=name)
def get_name_offset(self, name): """ Return the offset of @name if any, None otherwise. @name: target name """ name = force_bytes(name) loc_key = self.get_name_location(name) if loc_key is None: return None return self.get_location_offset(loc_key)
def __init__(self, *args, **kwargs): Sandbox.__init__(self, *args, **kwargs) # Pre-stack some arguments if self.options.mimic_env: env_ptrs = [] for env in self.envp: env = force_bytes(env) env += b"\x00" self.jitter.cpu.SP -= len(env) ptr = self.jitter.cpu.SP self.jitter.vm.set_mem(ptr, env) env_ptrs.append(ptr) argv_ptrs = [] for arg in self.argv: arg = force_bytes(arg) arg += b"\x00" self.jitter.cpu.SP -= len(arg) ptr = self.jitter.cpu.SP self.jitter.vm.set_mem(ptr, arg) argv_ptrs.append(ptr) # Round SP to 4 self.jitter.cpu.SP = self.jitter.cpu.SP & ~ 3 self.jitter.push_uint32_t(0) for ptr in reversed(env_ptrs): self.jitter.push_uint32_t(ptr) self.jitter.push_uint32_t(0) for ptr in reversed(argv_ptrs): self.jitter.push_uint32_t(ptr) self.jitter.push_uint32_t(len(self.argv)) self.jitter.cpu.LR = self.CALL_FINISH_ADDR # Set the runtime guard self.jitter.add_breakpoint( self.CALL_FINISH_ADDR, self.__class__.code_sentinelle )
def add_location_name(self, loc_key, name): """Associate a name @name to a given @loc_key @name: str instance @loc_key: LocKey instance """ name = force_bytes(name) assert loc_key in self._loc_keys already_existing_loc = self._name_to_loc_key.get(name) if already_existing_loc is not None and already_existing_loc != loc_key: raise KeyError("%r is already associated to a different loc_key " "(%r)" % (name, already_existing_loc)) self._loc_key_to_names.setdefault(loc_key, set()).add(name) self._name_to_loc_key[name] = loc_key
def add_lib_handler(self, libimp, namespace): """Add search for handler based on a @libimp libimp instance Known functions will be looked by {name}_symb in the @namespace """ namespace = dict( (force_bytes(name), func) for name, func in viewitems(namespace) ) # lambda cannot contain statement def default_func(dse): fname = b"%s_symb" % libimp.fad2cname[dse.jitter.pc] raise RuntimeError("Symbolic stub '%s' not found" % fname) for addr, fname in viewitems(libimp.fad2cname): fname = force_bytes(fname) fname = b"%s_symb" % fname func = namespace.get(fname, None) if func is not None: self.add_handler(addr, func) else: self.add_handler(addr, default_func)
def pack(self): out = b'' for field in self._fields: cpt = None if len(field) == 2: fname, ffmt = field elif len(field) == 3: fname, ffmt, cpt = field value = getattr(self, fname + self.__class__.field_suffix) if ffmt in type2realtype or (isinstance(ffmt, str) and re.match(r'\d+s', ffmt)): # basic types fmt = real_fmt(ffmt, self._wsize) if cpt == None: if value == None: o = struct.calcsize(fmt) * b"\x00" elif ffmt.endswith('s'): new_value = force_bytes(value) o = struct.pack(self.sex + fmt, new_value) else: o = struct.pack(self.sex + fmt, value) else: o = b"" for v in value: if value == None: o += struct.calcsize(fmt) * b"\x00" else: o += struct.pack(self.sex + fmt, v) elif ffmt == "sz": # null terminated special case o = value + b'\x00' elif ffmt in all_cstructs: # sub structures if cpt == None: o = bytes(value) else: o = b"" for v in value: o += bytes(v) elif isinstance(ffmt, tuple): f_get, f_set = ffmt o = f_set(self, value) else: raise ValueError('unknown class', ffmt) out += o return out
def find_free_name(self, name): """ If @name is not known in DB, return it Else append an index to it corresponding to the next unknown name @name: string """ name = force_bytes(name) if self.get_name_location(name) is None: return name i = 0 while True: new_name = "%s_%d" % (name, i) if self.get_name_location(new_name) is None: return new_name i += 1
def remove_location_name(self, loc_key, name): """Disassociate a name @name from a given @loc_key Fail if @name is not already associated to @loc_key @name: str instance @loc_key: LocKey instance """ assert loc_key in self._loc_keys name = force_bytes(name) already_existing_loc = self._name_to_loc_key.get(name) if already_existing_loc is None: raise KeyError("%r is not already associated" % name) if already_existing_loc != loc_key: raise KeyError("%r is already associated to a different loc_key " "(%r)" % (name, already_existing_loc)) del self._name_to_loc_key[name] self._loc_key_to_names[loc_key].remove(name)
def lib_get_add_base(self, name): name = force_bytes(name) name = name.lower().strip(b' ') if not b"." in name: log.debug('warning adding .dll to modulename') name += b'.dll' log.debug(name) if name in self.name2off: ad = self.name2off[name] else: ad = self.libbase_ad log.warning("Create dummy entry for %r", name) self.fake_libs.add(name) self.name2off[name] = ad self.libbase2lastad[ad] = ad + 0x4 self.lib_imp2ad[ad] = {} self.lib_imp2dstad[ad] = {} self.libbase_ad += 0x1000 return ad
def default_func(dse): fname = b"%s_symb" % force_bytes(libimp.fad2cname[dse.jitter.pc]) raise RuntimeError("Symbolic stub '%s' not found" % fname)
def add_location(self, name=None, offset=None, strict=True): """Add a new location in the locationDB. Returns the corresponding LocKey. If @name is set, also associate a name to this new location. If @offset is set, also associate an offset to this new location. Strict mode (set by @strict, default): If a location with @offset or @name already exists, an error will be raised. Otherwise: If a location with @offset or @name already exists, the corresponding LocKey may be updated and will be returned. """ name = force_bytes(name) # Deprecation handling if is_int(name): assert offset is None or offset == name warnings.warn( "Deprecated API: use 'add_location(offset=)' instead." " An additional 'name=' can be provided to also " "associate a name (there is no more default name)") offset = name name = None # Argument cleaning offset_loc_key = None if offset is not None: offset = int(offset) offset_loc_key = self.get_offset_location(offset) # Test for collisions name_loc_key = None if name is not None: name_loc_key = self.get_name_location(name) if strict: if name_loc_key is not None: raise ValueError("An entry for %r already exists (%r), and " "strict mode is enabled" % (name, name_loc_key)) if offset_loc_key is not None: raise ValueError("An entry for 0x%x already exists (%r), and " "strict mode is enabled" % (offset, offset_loc_key)) else: # Non-strict mode if name_loc_key is not None: known_offset = self.get_offset_location(name_loc_key) if known_offset is None: if offset is not None: self.set_location_offset(name_loc_key, offset) elif known_offset != offset: raise ValueError( "Location with name '%s' already have an offset: 0x%x " "(!= 0x%x)" % (name, offset, known_offset)) # Name already known, same offset -> nothing to do return name_loc_key elif offset_loc_key is not None: if name is not None: # Check for already known name are checked above return self.add_location_name(offset_loc_key, name) # Offset already known, no name specified return offset_loc_key # No collision, this is a brand new location loc_key = LocKey(self._loc_key_num) self._loc_key_num += 1 self._loc_keys.add(loc_key) if offset is not None: assert offset not in self._offset_to_loc_key self._offset_to_loc_key[offset] = loc_key self._loc_key_to_offset[loc_key] = offset if name is not None: self._name_to_loc_key[name] = loc_key self._loc_key_to_names[loc_key] = set([name]) return loc_key
def add_location(self, name=None, offset=None, strict=True): """Add a new location in the locationDB. Returns the corresponding LocKey. If @name is set, also associate a name to this new location. If @offset is set, also associate an offset to this new location. Strict mode (set by @strict, default): If a location with @offset or @name already exists, an error will be raised. Otherwise: If a location with @offset or @name already exists, the corresponding LocKey may be updated and will be returned. """ name = force_bytes(name) # Deprecation handling if is_int(name): assert offset is None or offset == name warnings.warn("Deprecated API: use 'add_location(offset=)' instead." " An additional 'name=' can be provided to also " "associate a name (there is no more default name)") offset = name name = None # Argument cleaning offset_loc_key = None if offset is not None: offset = int(offset) offset_loc_key = self.get_offset_location(offset) # Test for collisions name_loc_key = None if name is not None: name_loc_key = self.get_name_location(name) if strict: if name_loc_key is not None: raise ValueError("An entry for %r already exists (%r), and " "strict mode is enabled" % ( name, name_loc_key )) if offset_loc_key is not None: raise ValueError("An entry for 0x%x already exists (%r), and " "strict mode is enabled" % ( offset, offset_loc_key )) else: # Non-strict mode if name_loc_key is not None: known_offset = self.get_offset_location(name_loc_key) if known_offset is None: if offset is not None: self.set_location_offset(name_loc_key, offset) elif known_offset != offset: raise ValueError( "Location with name '%s' already have an offset: 0x%x " "(!= 0x%x)" % (name, offset, known_offset) ) # Name already known, same offset -> nothing to do return name_loc_key elif offset_loc_key is not None: if name is not None: # Check for already known name are checked above return self.add_location_name(offset_loc_key, name) # Offset already known, no name specified return offset_loc_key # No collision, this is a brand new location loc_key = LocKey(self._loc_key_num) self._loc_key_num += 1 self._loc_keys.add(loc_key) if offset is not None: assert offset not in self._offset_to_loc_key self._offset_to_loc_key[offset] = loc_key self._loc_key_to_offset[loc_key] = offset if name is not None: self._name_to_loc_key[name] = loc_key self._loc_key_to_names[loc_key] = set([name]) return loc_key
def set_str_ansi(value): value = force_bytes(value) return value + b"\x00"