예제 #1
0
    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
예제 #2
0
    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:
                        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
예제 #3
0
    def get_create_time(self):
        dt_obj = conversion.wintime_to_datetime(self.CreateTime.QuadPart)

        if isinstance(dt_obj, interfaces.renderers.BaseAbsentValue):
            return dt_obj

        # return None if the timestamp seems invalid
        if not (self.MIN_CREATETIME_YEAR < dt_obj.year < self.MAX_CREATETIME_YEAR):
            return None
        else:
            return dt_obj
예제 #4
0
    def _generator(self, layer: crash.WindowsCrashDump32Layer):
        header = layer.get_header()
        uptime = datetime.timedelta(microseconds=int(header.SystemUpTime) / 10)

        if header.DumpType == 0x1:
            dump_type = "Full Dump (0x1)"
        elif header.DumpType == 0x5:
            dump_type = "Bitmap Dump (0x5)"
        else:
            # this should never happen since the crash layer only accepts 0x1 and 0x5
            dump_type = "Unknown/Unsupported ({:#x})".format(header.DumpType)

        if header.DumpType == 0x5:
            summary_header = layer.get_summary_header()
            bitmap_header_size = format_hints.Hex(summary_header.HeaderSize)
            bitmap_size = format_hints.Hex(summary_header.BitmapSize)
            bitmap_pages = format_hints.Hex(summary_header.Pages)
        else:
            bitmap_header_size = bitmap_size = bitmap_pages = renderers.NotApplicableValue(
            )

        yield (0, (
            utility.array_to_string(header.Signature),
            header.MajorVersion,
            header.MinorVersion,
            format_hints.Hex(header.DirectoryTableBase),
            format_hints.Hex(header.PfnDataBase),
            format_hints.Hex(header.PsLoadedModuleList),
            format_hints.Hex(header.PsActiveProcessHead),
            header.MachineImageType,
            header.NumberProcessors,
            format_hints.Hex(header.KdDebuggerDataBlock),
            dump_type,
            str(uptime),
            utility.array_to_string(header.Comment),
            conversion.wintime_to_datetime(header.SystemTime),
            bitmap_header_size,
            bitmap_size,
            bitmap_pages,
        ))
예제 #5
0
    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()

                file_output = "Disabled"
                if self.config['dump']:
                    file_handle = self.dump_pe(
                        self.context,
                        pe_table_name,
                        entry,
                        self.open,
                        proc_layer_name,
                        prefix="pid.{}.".format(proc_id))
                    file_output = "Error outputting file"
                    if file_handle:
                        file_handle.close()
                        file_output = file_handle.preferred_filename

                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, file_output))
예제 #6
0
 def get_exit_time(self):
     return conversion.wintime_to_datetime(self.ExitTime.QuadPart)
예제 #7
0
 def get_create_time(self):
     return conversion.wintime_to_datetime(self.CreateTime.QuadPart)
예제 #8
0
 def get_time(self):
     wintime = (self.High1Time << 32) | self.LowPart
     return conversion.wintime_to_datetime(wintime)
예제 #9
0
    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
예제 #10
0
    def _generator(self):
        layer = self.context.layers[self.config['primary']]

        # Yara Rule to scan for MFT Header Signatures
        rules = yarascan.YaraScan.process_yara_options(
            {'yara_rules': '/FILE0|FILE\*|BAAD/'})

        # Read in the Symbol File
        symbol_table = intermed.IntermediateSymbolTable.create(
            context=self.context,
            config_path=self.config_path,
            sub_path="windows",
            filename="mft",
            class_types={
                'FILE_NAME_ENTRY': mft.MFTFileName,
                'MFT_ENTRY': mft.MFTEntry
            })

        # get each of the individual Field Sets
        mft_object = symbol_table + constants.BANG + "MFT_ENTRY"
        attribute_object = symbol_table + constants.BANG + "ATTRIBUTE"
        header_object = symbol_table + constants.BANG + "ATTR_HEADER"
        si_object = symbol_table + constants.BANG + "STANDARD_INFORMATION_ENTRY"
        fn_object = symbol_table + constants.BANG + "FILE_NAME_ENTRY"

        # Scan the layer for Raw MFT records and parse the fields
        for offset, _rule_name, _name, _value in layer.scan(
                context=self.context,
                scanner=yarascan.YaraScanner(rules=rules)):
            try:
                mft_record = self.context.object(mft_object,
                                                 offset=offset,
                                                 layer_name=layer.name)
                # We will update this on each pass in the next loop and use it as the new offset.
                attr_base_offset = mft_record.FirstAttrOffset

                attr_header = self.context.object(header_object,
                                                  offset=offset +
                                                  attr_base_offset,
                                                  layer_name=layer.name)

                # There is no field that has a count of Attributes
                # Keep Attempting to read attributes until we get an invalid attr_header.AttrType

                while attr_header.AttrType.is_valid_choice:
                    vollog.debug(f"Attr Type: {attr_header.AttrType.lookup()}")

                    # Offset past the headers to the attribute data
                    attr_data_offset = offset + attr_base_offset + self.context.symbol_space.get_type(
                        attribute_object).relative_child_offset("Attr_Data")

                    # MFT Flags determine the file type or dir
                    # If we don't have a valid enum, coerce to hex so we can keep the record
                    try:
                        mft_flag = mft_record.Flags.lookup()
                    except ValueError:
                        mft_flag = hex(mft_record.Flags)

                    # Standard Information Attribute
                    if attr_header.AttrType.lookup() == 'STANDARD_INFORMATION':
                        attr_data = self.context.object(
                            si_object,
                            offset=attr_data_offset,
                            layer_name=layer.name)

                        yield 0, (
                            format_hints.Hex(attr_data_offset),
                            mft_record.get_signature(),
                            mft_record.RecordNumber,
                            mft_record.LinkCount,
                            mft_flag,
                            renderers.NotApplicableValue(),
                            attr_header.AttrType.lookup(),
                            conversion.wintime_to_datetime(
                                attr_data.CreationTime),
                            conversion.wintime_to_datetime(
                                attr_data.ModifiedTime),
                            conversion.wintime_to_datetime(
                                attr_data.UpdatedTime),
                            conversion.wintime_to_datetime(
                                attr_data.AccessedTime),
                            renderers.NotApplicableValue(),
                        )

                    # File Name Attribute
                    if attr_header.AttrType.lookup() == 'FILE_NAME':
                        attr_data = self.context.object(
                            fn_object,
                            offset=attr_data_offset,
                            layer_name=layer.name)
                        file_name = attr_data.get_full_name()

                        # If we don't have a valid enum, coerce to hex so we can keep the record
                        try:
                            permissions = attr_data.Flags.lookup()
                        except ValueError:
                            permissions = hex(attr_data.Flags)

                        yield 1, (format_hints.Hex(attr_data_offset),
                                  mft_record.get_signature(),
                                  mft_record.RecordNumber,
                                  mft_record.LinkCount, mft_flag, permissions,
                                  attr_header.AttrType.lookup(),
                                  conversion.wintime_to_datetime(
                                      attr_data.CreationTime),
                                  conversion.wintime_to_datetime(
                                      attr_data.ModifiedTime),
                                  conversion.wintime_to_datetime(
                                      attr_data.UpdatedTime),
                                  conversion.wintime_to_datetime(
                                      attr_data.AccessedTime), file_name)

                    # If there's no advancement the loop will never end, so break it now
                    if attr_header.Length == 0:
                        break

                    # Update the base offset to point to the next attribute
                    attr_base_offset += attr_header.Length
                    # Get the next attribute
                    attr_header = self.context.object(header_object,
                                                      offset=offset +
                                                      attr_base_offset,
                                                      layer_name=layer.name)

            except exceptions.PagedInvalidAddressException:
                pass