def key_iterator( cls, hive: RegistryHive, node_path: Sequence[objects.StructType] = None, recurse: bool = False ) -> Iterable[Tuple[int, bool, datetime.datetime, str, bool, interfaces.objects.ObjectInterface]]: """Walks through a set of nodes from a given node (last one in node_path). Avoids loops by not traversing into nodes already present in the node_path. 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: A tuple of results (depth, is_key, last write time, path, volatile, and the node). """ if not node_path: node_path = [hive.get_node(hive.root_cell_offset)] if not isinstance(node_path, list) or len(node_path) < 1: vollog.warning( "Hive walker was not passed a valid node_path (or None)") return node = node_path[-1] key_path_items = [hive] + node_path[1:] key_path = '\\'.join([k.get_name() for k in key_path_items]) if node.vol.type_name.endswith(constants.BANG + '_CELL_DATA'): raise RegistryFormatException( hive.name, "Encountered _CELL_DATA instead of _CM_KEY_NODE") last_write_time = conversion.wintime_to_datetime( node.LastWriteTime.QuadPart) for key_node in node.get_subkeys(): result = (len(node_path), True, last_write_time, key_path, key_node.get_volatile(), key_node) yield result if recurse: if key_node.vol.offset not in [ x.vol.offset for x in node_path ]: try: sub_node_name = key_node.get_name() except exceptions.InvalidAddressException as excp: vollog.debug(excp) continue yield from cls.key_iterator(hive, node_path + [key_node], recurse=recurse) for value_node in node.get_values(): result = (len(node_path), False, last_write_time, key_path, node.get_volatile(), value_node) yield result
def _get_subkeys_recursive( self, hive: RegistryHive, node: interfaces.objects.ObjectInterface ) -> Iterable[interfaces.objects.ObjectInterface]: """Recursively descend a node returning subkeys.""" # The keylist appears to include 4 bytes of key name after each value # We can either double the list and only use the even items, or # We could change the array type to a struct with both parts try: signature = node.cast('string', max_length=2, encoding='latin-1') except (exceptions.InvalidAddressException, RegistryFormatException): return listjump = None if signature == 'ri': listjump = 1 elif signature == 'lh' or signature == 'lf': listjump = 2 elif node.vol.type_name.endswith(constants.BANG + "_CM_KEY_NODE"): yield node else: vollog.debug( "Unexpected node type encountered when traversing subkeys: {}, signature: {}" .format(node.vol.type_name, signature)) if listjump: node.List.count = node.Count * listjump for subnode_offset in node.List[::listjump]: if (subnode_offset & 0x7fffffff) > hive.maximum_address: vollog.log( constants.LOGLEVEL_VVV, "Node found with address outside the valid Hive size: {}" .format(hex(subnode_offset))) else: try: subnode = hive.get_node(subnode_offset) except (exceptions.InvalidAddressException, RegistryFormatException): vollog.log( constants.LOGLEVEL_VVV, "Failed to get node at {}, skipping".format( hex(subnode_offset))) continue yield from self._get_subkeys_recursive(hive, subnode)
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