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)