def parse_userassist_data(self, reg_val): """Reads the raw data of a _CM_KEY_VALUE and returns a dict of userassist fields.""" item = { "id": renderers.UnparsableValue(), "count": renderers.UnparsableValue(), "focus": renderers.UnparsableValue(), "time": renderers.UnparsableValue(), "lastupdated": renderers.UnparsableValue(), "rawdata": renderers.UnparsableValue(), } userassist_data = reg_val.decode_data() if userassist_data is None: return item item["rawdata"] = userassist_data if self._win7 is None: # if OS is still unknown at this point, return the default item which just has the rawdata return item if len(userassist_data) < self._userassist_size: return item userassist_layer_name = self.context.layers.free_layer_name( "userassist_buffer") buffer = BufferDataLayer(self.context, self._config_path, userassist_layer_name, userassist_data) self.context.add_layer(buffer) userassist_obj = self.context.object(object_type=self._reg_table_name + constants.BANG + self._userassist_type_name, layer_name=userassist_layer_name, offset=0) if self._win7: item["id"] = renderers.NotApplicableValue() item["count"] = int(userassist_obj.Count) seconds = (userassist_obj.FocusTime + 500) / 1000.0 time = datetime.timedelta( seconds=seconds) if seconds > 0 else userassist_obj.FocusTime item["focus"] = int(userassist_obj.FocusCount) item["time"] = str(time) else: item["id"] = int(userassist_obj.ID) item["count"] = int(userassist_obj.CountStartingAtFive if userassist_obj.CountStartingAtFive < 5 else userassist_obj.CountStartingAtFive - 5) item["focus"] = renderers.NotApplicableValue() item["time"] = renderers.NotApplicableValue() item["lastupdated"] = conversion.wintime_to_datetime( userassist_obj.LastUpdated.QuadPart) return item
def _generator(self): symbol_table = self.config["nt_symbols"] constraints = self.builtin_constraints(symbol_table) for constraint, mem_object, header in self.generate_pool_scan( self.context, self.config["primary"], symbol_table, constraints): # generate some type-specific info for sanity checking if constraint.object_type == "Process": name = mem_object.ImageFileName.cast( "string", max_length=mem_object.ImageFileName.vol.count, errors="replace") elif constraint.object_type == "File": try: name = mem_object.FileName.String except exceptions.InvalidAddressException: vollog.log( constants.LOGLEVEL_VVV, "Skipping file at {0:#x}".format( mem_object.vol.offset)) continue else: name = renderers.NotApplicableValue() yield (0, (constraint.type_name, format_hints.Hex(header.vol.offset), header.vol.layer_name, name))
def get_number_of_bytes(self) -> Union[int, interfaces.renderers.BaseAbsentValue]: """Returns the NumberOfBytes value on applicable systems""" # Not applicable until Vista try: return self.NumberOfBytes except AttributeError: return renderers.NotApplicableValue()
def _generator(self): collection = ssdt.SSDT.build_module_collection( self.context, self.config['primary'], self.config['nt_symbols']) for driver in driverscan.DriverScan.scan_drivers( self.context, self.config['primary'], self.config['nt_symbols']): try: driver_name = driver.get_driver_name() except exceptions.InvalidAddressException: driver_name = renderers.NotApplicableValue() for i, address in enumerate(driver.MajorFunction): module_symbols = collection.get_module_symbols_by_absolute_location( address) for module_name, symbol_generator in module_symbols: symbols_found = False for symbol in symbol_generator: symbols_found = True yield (0, (format_hints.Hex(driver.vol.offset), driver_name, MAJOR_FUNCTIONS[i], format_hints.Hex(address), module_name, symbol.split(constants.BANG)[1])) if not symbols_found: yield (0, (format_hints.Hex(driver.vol.offset), driver_name, MAJOR_FUNCTIONS[i], format_hints.Hex(address), module_name, renderers.NotAvailableValue()))
def _generator(self, procs): pe_table_name = intermed.IntermediateSymbolTable.create( self.context, self.config_path, "windows", "pe", class_types=pe.class_types) kuser = info.Info.get_kuser_structure(self.context, self.config['primary'], self.config['nt_symbols']) nt_major_version = int(kuser.NtMajorVersion) nt_minor_version = int(kuser.NtMinorVersion) # LoadTime only applies to versions higher or equal to Window 7 (6.1 and higher) dll_load_time_field = (nt_major_version > 6) or ( nt_major_version == 6 and nt_minor_version >= 1) for proc in procs: proc_id = proc.UniqueProcessId proc_layer_name = proc.add_process_layer() for entry in proc.load_order_modules(): BaseDllName = FullDllName = renderers.UnreadableValue() try: BaseDllName = entry.BaseDllName.get_string() # We assume that if the BaseDllName points to an invalid buffer, so will FullDllName FullDllName = entry.FullDllName.get_string() except exceptions.InvalidAddressException: pass if dll_load_time_field: # Versions prior to 6.1 won't have the LoadTime attribute # and 32bit version shouldn't have the Quadpart according to MSDN try: DllLoadTime = conversion.wintime_to_datetime( entry.LoadTime.QuadPart) except exceptions.InvalidAddressException: DllLoadTime = renderers.UnreadableValue() else: DllLoadTime = renderers.NotApplicableValue() dumped = False if self.config['dump']: filedata = self.dump_pe(self.context, pe_table_name, entry, proc_layer_name) if filedata: filedata.preferred_filename = "pid.{0}.".format( proc_id) + filedata.preferred_filename dumped = True self.produce_file(filedata) yield (0, (proc.UniqueProcessId, proc.ImageFileName.cast( "string", max_length=proc.ImageFileName.vol.count, errors='replace'), format_hints.Hex(entry.DllBase), format_hints.Hex(entry.SizeOfImage), BaseDllName, FullDllName, DllLoadTime, dumped))
def get_session_id(self): try: if self.has_member("Session"): if self.Session == 0: return renderers.NotApplicableValue() symbol_table_name = self.get_symbol_table_name() kvo = self._context.layers[ self.vol.native_layer_name].config['kernel_virtual_offset'] ntkrnlmp = self._context.module( symbol_table_name, layer_name=self.vol.native_layer_name, offset=kvo, native_layer_name=self.vol.native_layer_name) session = ntkrnlmp.object(object_type="_MM_SESSION_SPACE", offset=self.Session, absolute=True) if session.has_member("SessionId"): return session.SessionId except exceptions.InvalidAddressException: vollog.log( constants.LOGLEVEL_VVV, "Cannot access _EPROCESS.Session.SessionId at {0:#x}".format( self.vol.offset)) return renderers.UnreadableValue()
def _generator(self, runable_plugins: List[TimeLinerInterface]) -> Optional[Iterable[Tuple[int, Tuple]]]: """Takes a timeline, sorts it and output the data from each relevant row from each plugin.""" # Generate the results for each plugin data = [] for plugin in runable_plugins: plugin_name = plugin.__class__.__name__ self._progress_callback((runable_plugins.index(plugin) * 100) // len(runable_plugins), "Running plugin {}...".format(plugin_name)) try: vollog.log(logging.INFO, "Running {}".format(plugin_name)) for (item, timestamp_type, timestamp) in plugin.generate_timeline(): times = self.timeline.get((plugin_name, item), {}) if times.get(timestamp_type, None) is not None: vollog.debug("Multiple timestamps for the same plugin/file combination found: {} {}".format( plugin_name, item)) times[timestamp_type] = timestamp self.timeline[(plugin_name, item)] = times data.append((0, [ plugin_name, item, times.get(TimeLinerType.CREATED, renderers.NotApplicableValue()), times.get(TimeLinerType.MODIFIED, renderers.NotApplicableValue()), times.get(TimeLinerType.ACCESSED, renderers.NotApplicableValue()), times.get(TimeLinerType.CHANGED, renderers.NotApplicableValue()) ])) except Exception: vollog.log(logging.INFO, "Exception occurred running plugin: {}".format(plugin_name)) vollog.log(logging.DEBUG, traceback.format_exc()) for data_item in sorted(data, key = self._sort_function): yield data_item # Write out a body file if necessary if self.config.get('create-bodyfile', True): with self.open("volatility.body") as file_data: with io.TextIOWrapper(file_data, write_through = True) as fp: for (plugin_name, item) in self.timeline: times = self.timeline[(plugin_name, item)] # Body format is: MD5|name|inode|mode_as_string|UID|GID|size|atime|mtime|ctime|crtime if self._any_time_present(times): fp.write("|{} - {}||||||{}|{}|{}|{}\n".format( plugin_name, self._sanitize_body_format(item), self._text_format(times.get(TimeLinerType.ACCESSED, "")), self._text_format(times.get(TimeLinerType.MODIFIED, "")), self._text_format(times.get(TimeLinerType.CHANGED, "")), self._text_format(times.get(TimeLinerType.CREATED, ""))))
def _generator( self, runable_plugins: List[TimeLinerInterface] ) -> Optional[Iterable[Tuple[int, Tuple]]]: """Takes a timeline, sorts it and output the data from each relevant row from each plugin.""" # Generate the results for each plugin for plugin in runable_plugins: plugin_name = plugin.__class__.__name__ self._progress_callback( (runable_plugins.index(plugin) * 100) // len(runable_plugins), "Running plugin {}...".format(plugin_name)) try: vollog.log(logging.INFO, "Running {}".format(plugin_name)) for (item, timestamp_type, timestamp) in plugin.generate_timeline(): times = self.timeline.get((plugin_name, item), {}) if times.get(timestamp_type, None) is not None: vollog.debug( "Multiple timestamps for the same plugin/file combination found: {} {}" .format(plugin_name, item)) times[timestamp_type] = timestamp self.timeline[(plugin_name, item)] = times except Exception: # FIXME: traceback shouldn't be printed directly, but logged instead traceback.print_exc() vollog.log( logging.INFO, "Exception occurred running plugin: {}".format( plugin_name)) for (plugin_name, item) in self.timeline: times = self.timeline[(plugin_name, item)] data = (0, [ plugin_name, item, times.get(TimeLinerType.CREATED, renderers.NotApplicableValue()), times.get(TimeLinerType.MODIFIED, renderers.NotApplicableValue()), times.get(TimeLinerType.ACCESSED, renderers.NotApplicableValue()), times.get(TimeLinerType.CHANGED, renderers.NotApplicableValue()) ]) yield data
def get_pool_type(self) -> Union[str, interfaces.renderers.BaseAbsentValue]: """Returns the enum name for the PoolType value on applicable systems""" # Not applicable until Vista if hasattr(self, 'PoolType'): if not self.pool_type_lookup: self._generate_pool_type_lookup() return self.pool_type_lookup.get(self.PoolType, "Unknown choice {}".format(self.PoolType)) else: return renderers.NotApplicableValue()
def _generator(self): for mutant in self.scan_mutants(self.context, self.config['primary'], self.config['nt_symbols']): try: name = mutant.get_name() except (ValueError, exceptions.InvalidAddressException): name = renderers.NotApplicableValue() yield (0, (format_hints.Hex(mutant.vol.offset), name))
def get_pid(self) -> Union[int, interfaces.renderers.BaseAbsentValue]: """Return the pid of the process, if any.""" if self.State.description != "SERVICE_RUNNING" or "PROCESS" not in self.get_type( ): return renderers.NotApplicableValue() try: return self.ServiceProcess.ProcessId except exceptions.InvalidAddressException: return renderers.UnreadableValue()
def get_wait_reason(self) -> str: dictWaitReason = {0: 'Executive', 1: 'FreePage', 2: 'PageIn', 3: 'PoolAllocation', 4: 'DelayExecution', 5: 'Suspended', 6: 'UserRequest', 7: 'WrExecutive', 8: 'WrFreePage', 9: 'WrPageIn', 10: 'WrPoolAllocation', 11: 'WrDelayExecution', 12: 'WrSuspended', 13: 'WrUserRequest', 14: 'WrEventPair', 15: 'WrQueue', 16: 'WrLpcReceive', 17: 'WrLpcReply', 18: 'WrVirtualMemory', 19: 'WrPageOut', 20: 'WrRendezvous', 21: 'Spare2', 22: 'Spare3', 23: 'Spare4', 24: 'Spare5', 25: 'Spare6', 26: 'WrKernel', 27: 'WrResource', 28: 'WrPushLock', 29: 'WrMutex', 30: 'WrQuantumEnd', 31: 'WrDispatchInt', 32: 'WrPreempted',33: 'WrYieldExecution', 34: 'WrFastMutex', 35: 'WrGuardedMutex', 36: 'WrRundown', 37: 'MaximumWaitReason'} return dictWaitReason.get(self.WaitReason, renderers.NotApplicableValue())
def wintime_to_datetime( wintime: int ) -> Union[interfaces.renderers.BaseAbsentValue, datetime.datetime]: unix_time = wintime // 10000000 if unix_time == 0: return renderers.NotApplicableValue() unix_time = unix_time - 11644473600 try: return datetime.datetime.utcfromtimestamp(unix_time) # Windows sometimes throws OSErrors rather than ValueErrors when it can't convert a value except (ValueError, OSError): return renderers.UnparsableValue()
def _generator(self): callback_table_name = self.create_callback_table( self.context, self.config["nt_symbols"], self.config_path) collection = ssdt.SSDT.build_module_collection( self.context, self.config['primary'], self.config['nt_symbols']) callback_methods = (self.list_notify_routines, self.list_bugcheck_callbacks, self.list_bugcheck_reason_callbacks, self.list_registry_callbacks) for callback_method in callback_methods: for callback_type, callback_address, callback_detail in callback_method( self.context, self.config['primary'], self.config['nt_symbols'], callback_table_name): if callback_detail is None: detail = renderers.NotApplicableValue() else: detail = callback_detail module_symbols = list( collection.get_module_symbols_by_absolute_location( callback_address)) if module_symbols: for module_name, symbol_generator in module_symbols: symbols_found = False # we might have multiple symbols pointing to the same location for symbol in symbol_generator: symbols_found = True yield (0, (callback_type, format_hints.Hex(callback_address), module_name, symbol.split(constants.BANG)[1], detail)) # no symbols, but we at least can report the module name if not symbols_found: yield (0, (callback_type, format_hints.Hex(callback_address), module_name, renderers.NotAvailableValue(), detail)) else: # no module was found at the absolute location yield (0, (callback_type, format_hints.Hex(callback_address), renderers.NotAvailableValue(), renderers.NotAvailableValue(), detail))
def get_state(self) -> str: dictState = { 0: 'Initialized', 1: 'Ready', 2: 'Running', 3: 'Standby', 4: 'Terminated', 5: 'Waiting', 6: 'Transition', 7: 'DeferredReady', 8: 'GateWait' } return dictState.get(self.State, renderers.NotApplicableValue())
def _generator(self): for driver in self.scan_drivers(self.context, self.config['primary'], self.config['nt_symbols']): try: driver_name = driver.get_driver_name() except exceptions.InvalidAddressException: driver_name = renderers.NotApplicableValue() try: service_key = driver.DriverExtension.ServiceKeyName.String except exceptions.InvalidAddressException: service_key = renderers.NotApplicableValue() try: name = driver.DriverName.String except exceptions.InvalidAddressException: name = renderers.NotApplicableValue() yield (0, (format_hints.Hex(driver.vol.offset), format_hints.Hex(driver.DriverStart), format_hints.Hex(driver.DriverSize), service_key, driver_name, name))
def get_file_name(self): """Get the name of the file mapped into the memory range (if any)""" file_name = renderers.NotApplicableValue() try: # this is for xp and 2003 if self.has_member("ControlArea"): file_name = self.ControlArea.FilePointer.FileName.get_string() # this is for vista through windows 7 else: file_name = self.Subsection.ControlArea.FilePointer.dereference().cast( "_FILE_OBJECT").FileName.get_string() except exceptions.InvalidAddressException: pass return file_name
def get_binary(self) -> Union[str, interfaces.renderers.BaseAbsentValue]: """Returns the binary associated with the service.""" if self.State.description != "SERVICE_RUNNING": return renderers.NotApplicableValue() # depending on whether the service is for a process # or kernel driver, the binary path is stored differently try: if "PROCESS" in self.get_type(): return self.ServiceProcess.BinaryPath.dereference().cast( "string", encoding="utf-16", errors="replace", max_length=512) else: return self.DriverName.dereference().cast("string", encoding="utf-16", errors="replace", max_length=512) except exceptions.InvalidAddressException: return renderers.UnreadableValue()
def get_file_name(self): """Only long(er) vads have mapped files.""" return renderers.NotApplicableValue()
def _printkey_iterator(self, hive: RegistryHive, node_path: Sequence[objects.StructType] = None, recurse: bool = False): """Method that wraps the more generic key_iterator, to provide output for printkey specifically. Args: hive: The registry hive to walk node_path: The list of nodes that make up the recurse: Traverse down the node tree or stay only on the same level Yields: The depth, and a tuple of results (last write time, hive offset, type, path, name, data and volatile) """ for depth, is_key, last_write_time, key_path, volatile, node in self.key_iterator( hive, node_path, recurse): if is_key: try: key_node_name = node.get_name() except (exceptions.InvalidAddressException, RegistryFormatException) as excp: vollog.debug(excp) key_node_name = renderers.UnreadableValue() yield (depth, (last_write_time, renderers.format_hints.Hex(hive.hive_offset), "Key", key_path, key_node_name, renderers.NotApplicableValue(), volatile)) else: try: value_node_name = node.get_name() or "(Default)" except (exceptions.InvalidAddressException, RegistryFormatException) as excp: vollog.debug(excp) value_node_name = renderers.UnreadableValue() try: value_type = RegValueTypes.get(node.Type).name except (exceptions.InvalidAddressException, RegistryFormatException) as excp: vollog.debug(excp) value_type = renderers.UnreadableValue() if isinstance(value_type, renderers.UnreadableValue): vollog.debug( "Couldn't read registry value type, so data is unreadable" ) value_data = renderers.UnreadableValue() else: try: value_data = node.decode_data( ) # type: Union[interfaces.renderers.BaseAbsentValue, bytes] if isinstance(value_data, int): value_data = format_hints.MultiTypeData( value_data, encoding='utf-8') elif RegValueTypes.get( node.Type) == RegValueTypes.REG_BINARY: value_data = format_hints.MultiTypeData( value_data, show_hex=True) elif RegValueTypes.get( node.Type) == RegValueTypes.REG_MULTI_SZ: value_data = format_hints.MultiTypeData( value_data, encoding='utf-16-le', split_nulls=True) else: value_data = format_hints.MultiTypeData( value_data, encoding='utf-16-le') except (ValueError, exceptions.InvalidAddressException, RegistryFormatException) as excp: vollog.debug(excp) value_data = renderers.UnreadableValue() result = (depth, (last_write_time, renderers.format_hints.Hex(hive.hive_offset), value_type, key_path, value_node_name, value_data, volatile)) yield result
def _generator(self, procs: Generator[interfaces.objects.ObjectInterface, None, None], mods: Generator[interfaces.objects.ObjectInterface, None, None], session_layers: Generator[str, None, None]): """Generates a list of PE file version info for processes, dlls, and modules. Args: procs: <generator> of processes mods: <generator> of modules session_layers: <generator> of layers in the session to be checked """ pe_table_name = intermed.IntermediateSymbolTable.create(self.context, self.config_path, "windows", "pe", class_types = pe.class_types) for mod in mods: try: BaseDllName = mod.BaseDllName.get_string() except exceptions.InvalidAddressException: BaseDllName = renderers.UnreadableValue() session_layer_name = modules.Modules.find_session_layer(self.context, session_layers, mod.DllBase) (major, minor, product, build) = [ renderers.NotAvailableValue() ] * 4 # type: Tuple[Union[int, interfaces.renderers.BaseAbsentValue],Union[int, interfaces.renderers.BaseAbsentValue],Union[int, interfaces.renderers.BaseAbsentValue],Union[int, interfaces.renderers.BaseAbsentValue]] try: (major, minor, product, build) = self.get_version_information(self._context, pe_table_name, session_layer_name, mod.DllBase) except (exceptions.InvalidAddressException, TypeError, AttributeError): (major, minor, product, build) = [renderers.UnreadableValue()] * 4 # the pid and process are not applicable for kernel modules yield (0, (renderers.NotApplicableValue(), renderers.NotApplicableValue(), format_hints.Hex(mod.DllBase), BaseDllName, major, minor, product, build)) # now go through the process and dll lists for proc in procs: proc_id = "Unknown" try: proc_id = proc.UniqueProcessId proc_layer_name = proc.add_process_layer() except exceptions.InvalidAddressException as excp: vollog.debug("Process {}: invalid address {} in layer {}".format(proc_id, excp.invalid_address, excp.layer_name)) continue for entry in proc.load_order_modules(): try: BaseDllName = entry.BaseDllName.get_string() except exceptions.InvalidAddressException: BaseDllName = renderers.UnreadableValue() try: DllBase = format_hints.Hex(entry.DllBase) except exceptions.InvalidAddressException: DllBase = renderers.UnreadableValue() try: (major, minor, product, build) = self.get_version_information(self._context, pe_table_name, proc_layer_name, entry.DllBase) except (exceptions.InvalidAddressException, ValueError, AttributeError): (major, minor, product, build) = [renderers.UnreadableValue()] * 4 yield (0, (proc.UniqueProcessId, proc.ImageFileName.cast("string", max_length = proc.ImageFileName.vol.count, errors = "replace"), DllBase, BaseDllName, major, minor, product, build))
def list_userassist( self, hive: RegistryHive) -> Generator[Tuple[int, Tuple], None, None]: """Generate userassist data for a registry hive.""" hive_name = hive.hive.cast(self.config["nt_symbols"] + constants.BANG + "_CMHIVE").get_name() if self._win7 is None: try: self._win7 = self._win7_or_later() except exceptions.SymbolError: # self._win7 will be None and only registry value rawdata will be output pass self._determine_userassist_type() userassist_node_path = hive.get_key( "software\\microsoft\\windows\\currentversion\\explorer\\userassist", return_list=True) if not userassist_node_path: vollog.warning( "list_userassist did not find a valid node_path (or None)") return if not isinstance(userassist_node_path, list): vollog.warning( "userassist_node_path did not return a list as expected") return userassist_node = userassist_node_path[-1] # iterate through the GUIDs under the userassist key for guidkey in userassist_node.get_subkeys(): # each guid key should have a Count key in it for countkey in guidkey.get_subkeys(): countkey_path = countkey.get_key_path() countkey_last_write_time = conversion.wintime_to_datetime( countkey.LastWriteTime.QuadPart) # output the parent Count key result = ( 0, (renderers.format_hints.Hex(hive.hive_offset), hive_name, countkey_path, countkey_last_write_time, "Key", renderers.NotApplicableValue(), renderers.NotApplicableValue(), renderers.NotApplicableValue(), renderers.NotApplicableValue(), renderers.NotApplicableValue(), renderers.NotApplicableValue(), renderers.NotApplicableValue()) ) # type: Tuple[int, Tuple[format_hints.Hex, Any, Any, Any, Any, Any, Any, Any, Any, Any, Any, Any]] yield result # output any subkeys under Count for subkey in countkey.get_subkeys(): subkey_name = subkey.get_name() result = (1, ( renderers.format_hints.Hex(hive.hive_offset), hive_name, countkey_path, countkey_last_write_time, "Subkey", subkey_name, renderers.NotApplicableValue(), renderers.NotApplicableValue(), renderers.NotApplicableValue(), renderers.NotApplicableValue(), renderers.NotApplicableValue(), renderers.NotApplicableValue(), )) yield result # output any values under Count for value in countkey.get_values(): value_name = value.get_name() try: value_name = codecs.encode(value_name, "rot_13") except UnicodeDecodeError: pass if self._win7: guid = value_name.split("\\")[0] if guid in self._folder_guids: value_name = value_name.replace( guid, self._folder_guids[guid]) userassist_data_dict = self.parse_userassist_data(value) result = (1, ( renderers.format_hints.Hex(hive.hive_offset), hive_name, countkey_path, countkey_last_write_time, "Value", value_name, userassist_data_dict["id"], userassist_data_dict["count"], userassist_data_dict["focus"], userassist_data_dict["time"], userassist_data_dict["lastupdated"], format_hints.HexBytes(userassist_data_dict["rawdata"]), )) yield result