def collect(self): for task in self.filter_processes(): task_as = task.get_process_address_space() # Skip kernel and invalid processes. for module in task.get_load_modules(): process_offset = task_as.vtop(task.obj_offset) if process_offset: # Skip the modules which do not match the regex. if not self.plugin_args.regex.search( utils.SmartUnicode(module.BaseDllName)): continue base_name = os.path.basename( utils.SmartUnicode(module.BaseDllName)) dump_file = "module.{0}.{1:x}.{2:x}.{3}".format( task.UniqueProcessId, process_offset, module.DllBase, utils.EscapeForFilesystem(base_name)) yield (task, module.DllBase, module.BaseDllName, dump_file) # Use the procdump module to dump out the binary: with self.session.GetRenderer().open( filename=dump_file, directory=self.dump_dir, mode="wb") as fd: self.pedump.WritePEFile(fd, task_as, module.DllBase) else: self.session.logging.error("Cannot dump %s@%s at %#x\n", task.ImageFileName, module.BaseDllName, int(module.DllBase))
def PrecacheSids(self): """Search for known sids that we can cache.""" sid_cache = self.context["sid_cache"] sid_cache.update(getsids.well_known_sids) # Search for all known user sids. for hive_offset in self.hive_offsets: hive_address_space = registry.HiveAddressSpace( base=self.kernel_address_space, hive_addr=hive_offset, profile=self.profile) reg = registry.Registry(profile=self.profile, address_space=hive_address_space) # We get the user names according to the name of the diretory where # their profile is. This is not very accurate - should we check the # SAM instead? profiles = reg.open_key( 'Microsoft\\Windows NT\\CurrentVersion\\ProfileList') for profile in profiles.subkeys(): path = profile.open_value("ProfileImagePath").DecodedData if path: sid_cache[utils.SmartUnicode( profile.Name)] = (utils.SmartUnicode( ntpath.basename(path))) # Search for all service sids. getservicesids = self.get_plugin("getservicesids") for sid, service_name in getservicesids.get_service_sids(): sid_cache[sid] = "(Service: %s)" % service_name
def _EnsureInitialized(self): if self._initialized: return self.modules_by_name = {} symbols = {} # Insert a psuedo module for each section module_end = self.image_base # If the executable has a pdb file, we use that as its .text module # name. if self.pe_helper.RSDS.Filename: module_name = self.NormalizeModuleName( self.pe_helper.RSDS.Filename) else: module_name = "" # Find the highest address covered in this executable image. for _, name, virtual_address, length in self.pe_helper.Sections(): if self.image_base + virtual_address + length > module_end: module_end = virtual_address + length + self.image_base # Make a single module which covers the entire length of the executable # in virtual memory. module = PESectionModule(module_name, self.image_base, module_end - self.image_base) self.modules_by_name[module.name] = module self.section_map.insert((module.base, module)) if "Export" in self.session.GetParameter("name_resolution_strategies"): # Extract all exported symbols into the profile's symbol table. for _, func, name, _ in self.pe_helper.ExportDirectory(): func_address = func.v() try: symbols[utils.SmartUnicode(name)] = func_address except ValueError: continue if "Symbol" in self.session.GetParameter("name_resolution_strategies"): # Load the profile for this binary. self.pe_profile = self.session.LoadProfile( "%s/GUID/%s" % (utils.SmartUnicode( self.pe_helper.RSDS.Filename).split(".")[0], self.pe_helper.RSDS.GUID_AGE)) else: self.pe_profile = windows.BasicPEProfile(session=self.session) self.pe_profile.image_base = self.image_base self.pe_profile.add_constants(constants_are_addresses=True, relative_to_image_base=False, **symbols) self._initialized = True
def RekallCompleter(self, text): """Sophisticated command line completer for Rekall.""" try: command_parts = self.line_buffer.split(" ") command = command_parts[0] if command.startswith("plugins."): command = command[len("plugins."):] global_matches = set(self.global_matches(command)) # Complete strings which look like symbol names. m = re.match("\"([^!]+![^\"]*)$", command_parts[-1]) if m: session = self.namespace.get("session") # If this is the only match, close the quotes to save typing. result = session.address_resolver.search_symbol(m.group(1) + "*") if len(result) == 1: result = [result[0] + "\""] result = [utils.SmartUnicode(x.split("!", 1)[1]) for x in result] return result # Only complete if there is exactly one object which matches and a space # was typed after it. e.g.: pslist <cursor> if (command in global_matches and len(command_parts) > 1): # Get the object and ask it about the list of args that it supports. obj = self.namespace.get(command) if obj: try: matches = [ "%s=" % x["name"] for x in obj.Metadata()["arguments"] ] return [ utils.SmartUnicode(x) for x in matches if x.startswith(text) ] except Exception: pass return [] # Wide exception is necessary here because otherwise the completer will # swallow all errors. except Exception as e: logging.debug(e) return []
def GetData(self, value, **options): if isinstance(value, (int, float, long)): return value return utils.SmartUnicode( self._GetDelegateObjectRenderer(value).render_row( value, **options))
def filter_processes(self): """Filters proc list using phys_proc and pids lists.""" # No filtering required: procs = sorted(self.session.plugins.collect("proc"), key=lambda proc: proc.pid) if not self.filtering_requested: for proc in procs: yield proc else: # We need to filter by phys_proc for offset in self.phys_proc: yield self.virtual_process_from_physical_offset(offset) for offset in self.proc: yield self.profile.proc(vm=self.kernel_address_space, offset=int(offset)) # We need to filter by pids for proc in procs: if int(proc.p_pid) in self.pids: yield proc elif self.proc_regex and self.proc_regex.match( utils.SmartUnicode(proc.p_comm)): yield proc
def render(self, renderer): renderer.table_header([("_OBJECT_HEADER", "offset_v", "[addrpad]"), dict(name="_EPROCESS", type="_EPROCESS", cname="_EPROCESS"), ("Handle", "handle", "[addr]"), ("Access", "access", "[addr]"), ("Type", "obj_type", "16"), ("Details", "details", "")]) for task in self.filter_processes(): for count, (handle, object_type, name) in enumerate( self.enumerate_handles(task)): self.session.report_progress("%s: %s handles" % ( task.ImageFileName, count)) if self.silent: if len(utils.SmartUnicode(name).replace("'", "")) == 0: continue renderer.table_row( handle, task, handle.HandleValue, handle.GrantedAccess, object_type, name)
def enumerate_handles(self, task): if task.ObjectTable.HandleTableList: for handle in task.ObjectTable.handles(): name = "" object_type = handle.get_object_type(self.kernel_address_space) if object_type == "File": file_obj = handle.dereference_as("_FILE_OBJECT") name = file_obj.file_name_with_device() elif object_type == "Key": key_obj = handle.dereference_as("_CM_KEY_BODY") name = key_obj.full_key_name() elif object_type == "Process": proc_obj = handle.dereference_as("_EPROCESS") name = u"{0}({1})".format( utils.SmartUnicode(proc_obj.ImageFileName), proc_obj.UniqueProcessId) elif object_type == "Thread": thrd_obj = handle.dereference_as("_ETHREAD") name = u"TID {0} PID {1}".format( thrd_obj.Cid.UniqueThread, thrd_obj.Cid.UniqueProcess) elif handle.NameInfo.Name == None: name = "" else: name = handle.NameInfo.Name yield handle, object_type, name
def render_full(self, target, **_): value = target.v() name = target.choices.get( utils.SmartStr(value), target.default) or (u"UNKNOWN (%s)" % utils.SmartUnicode(value)) return text.Cell(name)
def write(self, data): # Encode the data according to the output encoding. data = utils.SmartUnicode(data).encode(self.encoding, "replace") if sys.platform == "win32": data = data.replace("\n", "\r\n") if self.fd is not None: # Suppress terminal output. Output is buffered in self.fd and will # be sent to the pager. self.fd.write(data) # No paging limit specified - just dump to terminal. elif self.paging_limit is None: self.term_fd.write(data) self.term_fd.flush() # If there is not enough output yet, just write it to the terminal and # store it locally. elif len(self.data.splitlines()) < self.paging_limit: self.term_fd.write(data) self.term_fd.flush() self.data += data # Now create a tempfile and dump the rest of the output there. else: self.term_fd.write( self.colorizer.Render("Please wait while the rest is paged...", foreground="YELLOW") + "\r\n") self.term_fd.flush() fd = self.GetTempFile() fd.write(self.data + data)
def render(self, renderer): for task in self.filter_processes(): task_as = task.get_process_address_space() # Skip kernel and invalid processes. for module in task.get_load_modules(): process_offset = task_as.vtop(task.obj_offset) if process_offset: # Skip the modules which do not match the regex. if not self.regex.search( utils.SmartUnicode(module.BaseDllName)): continue dump_file = "module.{0}.{1:x}.{2:x}.dll".format( task.UniqueProcessId, process_offset, module.DllBase) renderer.format( "Dumping {0}, Process: {1}, Base: {2:8x} " "output: {3}\n", module.BaseDllName, task.ImageFileName, module.DllBase, dump_file) # Use the procdump module to dump out the binary: path = os.path.join(self.dump_dir, dump_file) with open(path, "wb") as fd: self.pedump.WritePEFile(fd, task_as, module.DllBase) else: renderer.format( "Cannot dump {0}@{1} at {2:8x}\n", task.ImageFileName, module.BaseDllName, module.DllBase)
def render_full(self, target, **_): """Full render of a struct outputs every field.""" result = repr(target) + "\n" width_name = 0 fields = [] # Print all the fields sorted by offset within the struct. for k in target.members: width_name = max(width_name, len(k)) obj = getattr(target, k) if obj == None: obj = target.m(k) fields.append( (getattr(obj, "obj_offset", target.obj_offset) - target.obj_offset, k, utils.SmartUnicode(repr(obj)))) fields.sort() result = result + u"\n".join([ u" 0x%02X %s%s %s" % (offset, k, " " * (width_name - len(k)), v) for offset, k, v in fields ]) + "\n" return text.Cell(result)
def render(self, renderer): renderer.table_header([("Offset (V)", "offset_v", "[addrpad]"), ("Pid", "pid", ">6"), ("Handle", "handle", "[addr]"), ("Access", "access", "[addr]"), ("Type", "obj_type", "16"), ("Details", "details", "")]) for task in self.filter_processes(): for count, (handle, object_type, name) in enumerate(self.enumerate_handles(task)): self.session.report_progress("%s: %s handles" % (task.ImageFileName, count)) if self.object_list and object_type not in self.object_list: continue if self.silent: if len(utils.SmartUnicode(name).replace("'", "")) == 0: continue offset = handle.Body.obj_offset renderer.table_row(offset, task.UniqueProcessId, handle.HandleValue, handle.GrantedAccess, object_type, name)
def GetState(self, item, **options): state = super(JsonAttributedStringRenderer, self).GetState(item, **options) state["value"] = utils.SmartUnicode(item.value) state["highlights"] = item.highlights return state
def render(self, renderer): if self.verbosity > 5: self.PrecacheSids() renderer.table_header([("TimeWritten", "timestamp", ""), ("Filename", "filename", ""), ("Computer", "computer", ""), ("Sid", "sid", ""), ("Source", "source", ""), ("Event Id", "event_id", ""), ("Event Type", "event_type", ""), ("Message", "message", "")]) for task, vad in self.FindEVTFiles(): filename = ntpath.basename( utils.SmartUnicode(vad.ControlArea.FilePointer.FileName)) for event in self.ScanEvents(vad, task.get_process_address_space()): args = ";".join( repr(utils.SmartStr(x)) for x in event.Data) renderer.table_row( event.TimeWritten, filename, event.Computer, event.Sid, event.Source, event.EventID, event.EventType, args)
def __init__(self, hive_offsets=None, hive_regex=None, **kwargs): """Operate on in memory registry hives. Args: hive_offset: A list of hive offsets as found by hivelist (virtual address). If not provided we call hivescan ourselves and list the key on all hives. """ super(RegistryPlugin, self).__init__(**kwargs) # Install our specific implementation of registry support. RekallRegisteryImplementation(self.profile) self.hive_offsets = hive_offsets if not self.hive_offsets: self.hive_offsets = list(self.list_hives()) if hive_regex is not None: hive_offsets = [] for hive in self.hive_offsets: m = re.search(hive_regex, utils.SmartUnicode(hive.Name)) if m: hive_offsets.append(hive) self.hive_offsets = hive_offsets
def RebuildHelp(): """Rebuilds the plugin help profile.""" help_dict = {} plugin_metadata = {} result = { "$METADATA": dict(Type="Profile", ProfileClass="PluginHelp"), "$HELP": help_dict, "$PLUGINS": plugin_metadata, } for cls in plugin.Command.classes.values(): session.report_progress("Rebuilding profile help: %s.", cls.__name__) # Use the info class to build docstrings for all plugins. info_plugin = session.plugins.info(cls) default_args = [x for x, _ in info_plugin.get_default_args()] doc = utils.SmartUnicode(info_plugin) help_dict[cls.__name__] = [default_args, doc] command_metadata = config.CommandMetadata(cls) plugin_metadata[cls.__name__] = command_metadata.Metadata() with gzip.GzipFile(filename="help_doc.gz", mode="wb") as outfd: outfd.write(json.dumps(result))
def Render(self, string, foreground=None, background=None): """Decorate the string with the ansii escapes for the color.""" if (not self.terminal_capable or foreground not in self.COLOR_MAP or foreground not in self.COLOR_MAP): return utils.SmartUnicode(string) escape_seq = "" if background: escape_seq += self.tparm(["setb", "setab"], self.COLOR_MAP[background]) if foreground: escape_seq += self.tparm(["setf", "setaf"], self.COLOR_MAP[foreground]) return (escape_seq + utils.SmartUnicode(string) + self.tparm(["sgr0"]))
def path(self): dentry_ = self path_components = [] # Check for deleted dentry_. if self.d_flags.DCACHE_UNHASHED and not self.is_root: return " (deleted) " while len(path_components) < 50: if dentry_.is_root: break component = utils.SmartUnicode(dentry_.d_name.name.deref()) path_components = [component] + path_components dentry_ = dentry_.d_parent result = '/'.join(filter(None, path_components)) if result.startswith(("socket:", "pipe:")): if result.find("]") == -1: result += ":[{0}]".format(self.d_inode.i_ino) elif result != "inotify": result = '/' + result return result
def collect(self, hint, ifnets): for entity in ifnets: ifnet = entity["MemoryObject/base_object"] yield [ entity.identity, definitions.NetworkInterface( name="%s%d" % (ifnet.if_name.deref(), ifnet.if_unit))] l2_addr = None l3_addrs = [] # Parse all the addresses on the interface. There should be exactly # one link layer (L2) address. for tqe in ifnet.if_addrhead.tqh_first.walk_list( "ifa_link.tqe_next"): family = tqe.ifa_addr.sa_family if family == "AF_LINK": l2_addr = utils.SmartUnicode(tqe.ifa_addr.deref()) continue if family == "AF_INET": l3_proto = "IPv4" elif family == "AF_INET6": l3_proto = "IPv6" else: l3_proto = utils.SmartUnicode(family).replace("AF_", "") l3_addrs.append((l3_proto, unicode(tqe.ifa_addr.deref()))) # Yield all the endpoints as the shared L2 + each L3. for l3_proto, l3_addr in l3_addrs: endpoint_identity = self.manager.identify({ ("Endpoint/interface", "OSILayer3/address", "OSILayer2/address"): (entity.identity, l3_addr, l2_addr)}) yield [ endpoint_identity, definitions.Endpoint( local=True, interface=entity.identity), definitions.OSILayer2( address=l2_addr, protocol="MAC"), definitions.OSILayer3( address=l3_addr, protocol=unicode(l3_proto))]
def createservicesid(self, service_name): """Calculate the Service SID.""" # We depend on service name to be a unicode string here. service_name = utils.SmartUnicode(service_name) sha = hashlib.sha1(service_name.encode("utf-16-le").upper()).digest() return 'S-1-5-80-' + '-'.join( [str(n) for n in struct.unpack("<IIIII", sha)])
def _collect_serialized_object(self, flow_obj, depth=0, ignore_fields=None): for descriptor in flow_obj.get_descriptors(): # Skip hidden fields if verbosity is low. if self.plugin_args.verbosity < 2 and descriptor.get("hidden"): continue field = descriptor["name"] # Only show requested fields in non-verbose mode. if (not self.plugin_args.verbosity and ignore_fields and field in ignore_fields): continue if not flow_obj.HasMember(field): continue value = flow_obj.GetMember(field) if isinstance(value, serializer.SerializedObject): display_value = "(%s)" % value.__class__.__name__ elif isinstance(value, str): display_value = base64.b64encode(value) elif isinstance(value, unicode): display_value = value elif isinstance(value, list): for x in self._collect_list(value, field, descriptor, depth): yield x continue elif isinstance(value, dict): for x in self._collect_dict(value, field, descriptor, depth): yield x continue else: display_value = utils.SmartUnicode(value) if (not self.plugin_args.verbosity and len(display_value) > 45): display_value = display_value[:45] + " ..." yield dict(Field=field, Value=display_value, Description=descriptor.get("doc", ""), highlight="important" if descriptor.get("user") else "", depth=depth) if (isinstance(value, serializer.SerializedObject)): for row in self._explain(value, depth=depth + 1): yield row
def RunPlugin(self, plugin_obj, *args, **kwargs): """Launch a plugin and its render() method automatically. We use the pager specified in session.GetParameter("pager"). Args: plugin_obj: A string naming the plugin, or the plugin instance itself. *pos_args: Args passed to the plugin if it is not an instance. **kwargs: kwargs passed to the plugin if it is not an instance. """ kwargs = self._CorrectKWArgs(kwargs) output = kwargs.pop("output", self.GetParameter("output")) ui_renderer = kwargs.pop("format", None) result = None if ui_renderer is None: ui_renderer = self.GetRenderer(output=output) self.renderers.append(ui_renderer) # Set the renderer so we can transport log messages. self._log_handler.SetRenderer(ui_renderer) try: plugin_name = self._GetPluginName(plugin_obj) except Exception as e: raise ValueError("Invalid plugin_obj parameter (%s)." % repr(plugin)) # On multiple calls to RunPlugin, we need to make sure the # HoardingLogHandler doesn't send messages to the wrong renderer. # We reset the renderer and make it hoard messages until we have the # new one. self.logging.debug(u"Running plugin (%s) with args (%s) kwargs (%s)", plugin_name, args, utils.SmartUnicode(kwargs)[:1000]) with ui_renderer.start(plugin_name=plugin_name, kwargs=kwargs): try: original_plugin_obj = plugin_obj plugin_obj = self._GetPluginObj(plugin_obj, *args, **kwargs) if not plugin_obj: raise ValueError("Invalid plugin: %s" % original_plugin_obj) result = plugin_obj.render(ui_renderer) or plugin_obj self.last = plugin_obj except (Exception, KeyboardInterrupt) as e: self._HandleRunPluginException(ui_renderer, e) finally: self.renderers.pop(-1) # At this point, the ui_renderer will have flushed all data. # Further logging will be lost. return result
def NormalizeModuleName(self, module): try: module_name = module.name except AttributeError: module_name = module module_name = utils.SmartUnicode(module_name) module_name = re.split(r"[/\\]", module_name)[-1] result = module_name.split(".")[0] return result.lower()
def collect(self): for task in self.filter_processes(): for count, (handle, object_type, name) in enumerate(self.enumerate_handles(task)): self.session.report_progress("%s: %s handles" % (task.ImageFileName, count)) yield (handle, task, utils.HexInteger(handle.HandleValue), utils.HexInteger(handle.GrantedAccess), object_type, utils.SmartUnicode(name))
def parse_extended_format(self, value, formatstring=None, header=False, **options): """Parse the format string into the format specification. We support some extended forms of format string which we process especially here: [addrpad] - This is a padded address to width renderer.address_size. [addr] - This is a non padded address. [wrap:width] - This wraps a stringified version of the target in the cell. Args: formatstring: The formatstring we parse. options: An options dict. We may populate it with some options which are encoded in the extended format. Returns: A Cell instance. """ _ = options extended_format = None # This means unlimited and uncontrolled width. if not formatstring: extended_format = "s" elif formatstring == "[addrpad]": if header: extended_format = "^%ss" % self.address_size else: extended_format = "#0%sx" % self.address_size if value == None: extended_format = "<%ss" % self.address_size elif formatstring == "[addr]": if header: extended_format = "^%ss" % self.address_size else: extended_format = ">#%sx" % self.address_size else: # Look for the wrap specifier. m = re.match(r"\[wrap:([^\]]+)\]", formatstring) if m: width = int(m.group(1)) return Cell.wrap(utils.SmartUnicode(value), width) if extended_format is not None: return Cell.FromString(self.format_field(value, extended_format))
def write(self, data): # Encode the data according to the output encoding. data = utils.SmartUnicode(data).encode(self.encoding, "replace") try: if sys.platform in ["win32"]: data = data.replace("\n", "\r\n") os.write(self.fd, data) # This can happen if the pager disappears in the middle of the write. except IOError: pass
def format_type_s(self, value, fields): try: # This is required to allow BaseObject to pass non unicode returns # from __unicode__ (e.g. NoneObject). result = value.__unicode__() except AttributeError: result = utils.SmartUnicode(value) formatstring = (u"{0:" + (fields.get("align") or "") + (fields.get("width") or "") + "s}") return formatstring.format(result)
def render(self, renderer): renderer.table_header([("_EPROCESS", "eprocess", "[addrpad]"), ("Name", "name", "16"), ("Base", "base", "[addrpad]"), ("Module", "module", "20s"), ("Dump File", "filename", "")]) for task in self.filter_processes(): task_as = task.get_process_address_space() # Skip kernel and invalid processes. for module in task.get_load_modules(): process_offset = task_as.vtop(task.obj_offset) if process_offset: # Skip the modules which do not match the regex. if not self.regex.search( utils.SmartUnicode(module.BaseDllName)): continue base_name = os.path.basename( utils.SmartUnicode(module.BaseDllName)) dump_file = "module.{0}.{1:x}.{2:x}.{3}".format( task.UniqueProcessId, process_offset, module.DllBase, base_name) renderer.table_row( task, task.name, module.DllBase, module.BaseDllName, dump_file) # Use the procdump module to dump out the binary: with renderer.open(filename=dump_file, directory=self.dump_dir, mode="wb") as fd: self.pedump.WritePEFile(fd, task_as, module.DllBase) else: renderer.format( "Cannot dump {0}@{1} at {2:8x}\n", task.ImageFileName, module.BaseDllName, module.DllBase)
def _EnsureInitialized(self): if self._initialized: return symbols = {} self.pe_profile = None # Get a usable profile. if "Symbol" in self.session.GetParameter("name_resolution_strategies"): # Load the profile for this binary. self.pe_profile = self.session.LoadProfile( "%s/GUID/%s" % (self.NormalizeModuleName(self.pe_helper.RSDS.Filename), self.pe_helper.RSDS.GUID_AGE)) if self.pe_profile == None: self.pe_profile = pe_vtypes.BasicPEProfile(session=self.session) if "Export" in self.session.GetParameter("name_resolution_strategies"): # Extract all exported symbols into the profile's symbol table. for _, func, name, _ in self.pe_helper.ExportDirectory(): func_address = func.v() name = utils.SmartUnicode(name) symbols[name] = func_address - self.image_base self.pe_profile.image_base = self.image_base self.pe_profile.add_constants(constants_are_addresses=True, constants=symbols) # A section for the header. self.AddModule( PESectionModule(start=self.image_base, end=self.image_base + 0x1000, name="pe", profile=self.pe_profile, session=self.session)) # Insert a psuedo module for each section module_end = self.image_base # Find the highest address covered in this executable image. for _, name, virtual_address, length in self.pe_helper.Sections(): if length > 0: virtual_address += self.image_base self.AddModule( PESectionModule(start=virtual_address, end=virtual_address + length, name=self.NormalizeModuleName(name), profile=self.pe_profile, session=self.session)) self._initialized = True