예제 #1
0
    def process_dump(
        cls, context: interfaces.context.ContextInterface,
        kernel_table_name: str, pe_table_name: str,
        proc: interfaces.objects.ObjectInterface
    ) -> interfaces.plugins.FileInterface:
        """Extracts the complete data for a process as a FileInterface

        Args:
            context: the context to operate upon
            kernel_table_name: the name for the symbol table containing the kernel's symbols
            pe_table_name: the name for the symbol table containing the PE format symbols
            proc: the process object whose memory should be output

        Returns:
            A FileInterface object containing the complete data for the process
        """

        proc_id = proc.UniqueProcessId
        proc_layer_name = proc.add_process_layer()
        peb = context.object(kernel_table_name + constants.BANG + "_PEB",
                             layer_name=proc_layer_name,
                             offset=proc.Peb)
        dos_header = context.object(pe_table_name + constants.BANG +
                                    "_IMAGE_DOS_HEADER",
                                    offset=peb.ImageBaseAddress,
                                    layer_name=proc_layer_name)
        filedata = interfaces.plugins.FileInterface(
            "pid.{0}.{1:#x}.dmp".format(proc.UniqueProcessId,
                                        peb.ImageBaseAddress))
        for offset, data in dos_header.reconstruct():
            filedata.data.seek(offset)
            filedata.data.write(data)

        return filedata
예제 #2
0
    def process_dump(
            cls, context: interfaces.context.ContextInterface, kernel_table_name: str, pe_table_name: str,
            proc: interfaces.objects.ObjectInterface,
            open_method: Type[interfaces.plugins.FileHandlerInterface]) -> interfaces.plugins.FileHandlerInterface:
        """Extracts the complete data for a process as a FileHandlerInterface

        Args:
            context: the context to operate upon
            kernel_table_name: the name for the symbol table containing the kernel's symbols
            pe_table_name: the name for the symbol table containing the PE format symbols
            proc: the process object whose memory should be output
            open_method: class to provide context manager for opening the file

        Returns:
            An open FileHandlerInterface object containing the complete data for the process or None in the case of failure
        """

        file_handle = None
        try:
            proc_layer_name = proc.add_process_layer()
            peb = context.object(kernel_table_name + constants.BANG + "_PEB",
                                 layer_name = proc_layer_name,
                                 offset = proc.Peb)

            dos_header = context.object(pe_table_name + constants.BANG + "_IMAGE_DOS_HEADER",
                                        offset = peb.ImageBaseAddress,
                                        layer_name = proc_layer_name)
            file_handle = open_method("pid.{0}.{1:#x}.dmp".format(proc.UniqueProcessId, peb.ImageBaseAddress))
            for offset, data in dos_header.reconstruct():
                file_handle.seek(offset)
                file_handle.write(data)
        except Exception as excp:
            vollog.debug("Unable to dump PE with pid {}: {}".format(proc.UniqueProcessId, excp))

        return file_handle
예제 #3
0
    def list_bugcheck_callbacks(
            cls, context: interfaces.context.ContextInterface, layer_name: str,
            symbol_table: str,
            callback_table_name: str) -> Iterable[Tuple[str, int, str]]:
        """Lists all kernel bugcheck callbacks.

        Args:
            context: The context to retrieve required elements (layers, symbol tables) from
            layer_name: The name of the layer on which to operate
            symbol_table: The name of the table containing the kernel symbols
            callback_table_name: The nae of the table containing the callback symbols

        Yields:
            A name, location and optional detail string
        """

        kvo = context.layers[layer_name].config['kernel_virtual_offset']
        ntkrnlmp = context.module(symbol_table,
                                  layer_name=layer_name,
                                  offset=kvo)

        try:
            list_offset = ntkrnlmp.get_symbol(
                "KeBugCheckCallbackListHead").address
        except exceptions.SymbolError:
            vollog.debug("Cannot find KeBugCheckCallbackListHead")
            return

        full_type_name = callback_table_name + constants.BANG + "_KBUGCHECK_CALLBACK_RECORD"
        callback_record = context.object(full_type_name,
                                         offset=kvo + list_offset,
                                         layer_name=layer_name)

        for callback in callback_record.Entry:

            try:
                context.layers[layer_name].is_valid(callback.CallbackRoutine)
            except exceptions.InvalidAddressException:
                continue

            try:
                component = context.object(symbol_table + constants.BANG +
                                           "string",
                                           layer_name=layer_name,
                                           offset=callback.Component,
                                           max_length=64,
                                           errors="replace")
            except exceptions.InvalidAddressException:
                component = renderers.UnreadableValue()

            yield "KeBugCheckCallbackListHead", callback.CallbackRoutine, component
예제 #4
0
    def method_kdbg_offset(
        self,
        context: interfaces.context.ContextInterface,
        vlayer: layers.intel.Intel,
        progress_callback: constants.ProgressCallback = None
    ) -> ValidKernelsType:
        vollog.debug(
            "Kernel base determination - using KDBG structure for kernel offset"
        )
        valid_kernels = {}  # type: ValidKernelsType
        physical_layer_name = self.get_physical_layer_name(context, vlayer)
        physical_layer = context.layers[physical_layer_name]
        results = physical_layer.scan(context,
                                      scanners.BytesScanner(b"KDBG"),
                                      progress_callback=progress_callback)

        seen = set()  # type: Set[int]
        for result in results:
            # TODO: Identify the specific structure we're finding and document this a bit better
            pointer = context.object("pdbscan!unsigned long long",
                                     offset=result + 8,
                                     layer_name=physical_layer_name)
            address = pointer & vlayer.address_mask
            if address in seen:
                continue
            seen.add(address)

            valid_kernels = self.check_kernel_offset(context, vlayer, address,
                                                     progress_callback)

            if valid_kernels:
                break

        return valid_kernels
예제 #5
0
    def get_kdbg_structure(
            cls, context: interfaces.context.ContextInterface,
            config_path: str, layer_name: str,
            symbol_table: str) -> interfaces.objects.ObjectInterface:
        """Returns the KDDEBUGGER_DATA64 structure for a kernel"""
        ntkrnlmp = cls.get_kernel_module(context, layer_name, symbol_table)

        native_types = context.symbol_space[symbol_table].natives

        kdbg_offset = ntkrnlmp.get_symbol("KdDebuggerDataBlock").address

        kdbg_table_name = intermed.IntermediateSymbolTable.create(
            context,
            interfaces.configuration.path_join(config_path, 'kdbg'),
            "windows",
            "kdbg",
            native_types=native_types,
            class_types=extensions.kdbg.class_types)

        kdbg = context.object(kdbg_table_name + constants.BANG +
                              "_KDDEBUGGER_DATA64",
                              offset=ntkrnlmp.offset + kdbg_offset,
                              layer_name=layer_name)

        return kdbg
예제 #6
0
    def get_ntheader_structure(
            cls, context: interfaces.context.ContextInterface,
            config_path: str,
            layer_name: str) -> interfaces.objects.ObjectInterface:
        """Gets the ntheader structure for the kernel of the specified layer"""
        virtual_layer = context.layers[layer_name]
        if not isinstance(virtual_layer, layers.intel.Intel):
            raise TypeError("Virtual Layer is not an intel layer")

        kvo = virtual_layer.config["kernel_virtual_offset"]

        pe_table_name = intermed.IntermediateSymbolTable.create(
            context,
            interfaces.configuration.path_join(config_path, 'pe'),
            "windows",
            "pe",
            class_types=extensions.pe.class_types)

        dos_header = context.object(pe_table_name + constants.BANG +
                                    "_IMAGE_DOS_HEADER",
                                    offset=kvo,
                                    layer_name=layer_name)

        nt_header = dos_header.get_nt_header()

        return nt_header
예제 #7
0
    def method_module_offset(self,
                             context: interfaces.context.ContextInterface,
                             vlayer: layers.intel.Intel,
                             progress_callback: constants.ProgressCallback = None) -> ValidKernelsType:
        """Method for finding a suitable kernel offset based on a module
        table."""
        vollog.debug("Kernel base determination - searching layer module list structure")
        valid_kernels = {}  # type: ValidKernelsType
        # If we're here, chances are high we're in a Win10 x64 image with kernel base randomization
        virtual_layer_name = vlayer.name
        physical_layer_name = self.get_physical_layer_name(context, vlayer)
        physical_layer = context.layers[physical_layer_name]
        # TODO:  On older windows, this might be \WINDOWS\system32\nt rather than \SystemRoot\system32\nt
        results = physical_layer.scan(context,
                                      scanners.BytesScanner(b"\\SystemRoot\\system32\\nt"),
                                      progress_callback = progress_callback)
        seen = set()  # type: Set[int]
        # Because this will launch a scan of the virtual layer, we want to be careful
        for result in results:
            # TODO: Identify the specific structure we're finding and document this a bit better
            pointer = context.object("pdbscan!unsigned long long",
                                     offset = (result - 16 - int(vlayer.bits_per_register / 8)),
                                     layer_name = physical_layer_name)
            address = pointer & vlayer.address_mask
            if address in seen:
                continue
            seen.add(address)

            valid_kernels = self.check_kernel_offset(context, vlayer, address, progress_callback)

            if valid_kernels:
                break
        return valid_kernels
예제 #8
0
    def find_cookie(cls, context: interfaces.context.ContextInterface, layer_name: str,
                    symbol_table: str) -> Optional[interfaces.objects.ObjectInterface]:
        """Find the ObHeaderCookie value (if it exists)"""

        try:
            offset = context.symbol_space.get_symbol(symbol_table + constants.BANG + "ObHeaderCookie").address
        except exceptions.SymbolError:
            return None

        kvo = context.layers[layer_name].config['kernel_virtual_offset']
        return context.object(symbol_table + constants.BANG + "unsigned int", layer_name, offset = kvo + offset)
예제 #9
0
    def get_session_layers(
            cls,
            context: interfaces.context.ContextInterface,
            layer_name: str,
            symbol_table: str,
            pids: List[int] = None) -> Generator[str, None, None]:
        """Build a cache of possible virtual layers, in priority starting with
        the primary/kernel layer. Then keep one layer per session by cycling
        through the process list.

        Args:
            context: The context to retrieve required elements (layers, symbol tables) from
            layer_name: The name of the layer on which to operate
            symbol_table: The name of the table containing the kernel symbols
            pids: A list of process identifiers to include exclusively or None for no filter

        Returns:
            A list of session layer names
        """
        seen_ids = []  # type: List[interfaces.objects.ObjectInterface]
        filter_func = pslist.PsList.create_pid_filter(pids or [])

        for proc in pslist.PsList.list_processes(context=context,
                                                 layer_name=layer_name,
                                                 symbol_table=symbol_table,
                                                 filter_func=filter_func):
            proc_id = "Unknown"
            try:
                proc_id = proc.UniqueProcessId
                proc_layer_name = proc.add_process_layer()

                # create the session space object in the process' own layer.
                # not all processes have a valid session pointer.
                session_space = context.object(symbol_table + constants.BANG +
                                               "_MM_SESSION_SPACE",
                                               layer_name=layer_name,
                                               offset=proc.Session)

                if session_space.SessionId in seen_ids:
                    continue

            except exceptions.InvalidAddressException:
                vollog.log(
                    constants.LOGLEVEL_VVV,
                    "Process {} does not have a valid Session or a layer could not be constructed for it"
                    .format(proc_id))
                continue

            # save the layer if we haven't seen the session yet
            seen_ids.append(session_space.SessionId)
            yield proc_layer_name
예제 #10
0
    def dump_pe(
            cls,
            context: interfaces.context.ContextInterface,
            pe_table_name: str,
            dll_entry: interfaces.objects.ObjectInterface,
            open_method: Type[interfaces.plugins.FileHandlerInterface],
            layer_name: str = None,
            prefix: str = ''
    ) -> Optional[interfaces.plugins.FileHandlerInterface]:
        """Extracts the complete data for a process as a FileInterface

        Args:
            context: the context to operate upon
            pe_table_name: the name for the symbol table containing the PE format symbols
            dll_entry: the object representing the module
            layer_name: the layer that the DLL lives within
            open_method: class for constructing output files

        Returns:
            An open FileHandlerInterface object containing the complete data for the DLL or None in the case of failure
            """
        try:
            try:
                name = dll_entry.FullDllName.get_string()
            except exceptions.InvalidAddressException:
                name = 'UnreadbleDLLName'

            if layer_name is None:
                layer_name = dll_entry.vol.layer_name

            file_handle = open_method("{}{}.{:#x}.{:#x}.dmp".format(
                prefix, ntpath.basename(name), dll_entry.vol.offset,
                dll_entry.DllBase))

            dos_header = context.object(pe_table_name + constants.BANG +
                                        "_IMAGE_DOS_HEADER",
                                        offset=dll_entry.DllBase,
                                        layer_name=layer_name)

            for offset, data in dos_header.reconstruct():
                file_handle.seek(offset)
                file_handle.write(data)
        except (IOError, exceptions.VolatilityException, OverflowError,
                ValueError) as excp:
            vollog.debug("Unable to dump dll at offset {}: {}".format(
                dll_entry.DllBase, excp))
            return None
        return file_handle
예제 #11
0
    def get_version_information(
            cls, context: interfaces.context.ContextInterface,
            pe_table_name: str, layer_name: str,
            base_address: int) -> Tuple[int, int, int, int]:
        """Get File and Product version information from PE files.

        Args:
            context: volatility context on which to operate
            pe_table_name: name of the PE table
            layer_name: name of the layer containing the PE file
            base_address: base address of the PE (where MZ is found)
        """

        if layer_name is None:
            raise ValueError("Layer must be a string not None")

        pe_data = io.BytesIO()

        dos_header = context.object(pe_table_name + constants.BANG +
                                    "_IMAGE_DOS_HEADER",
                                    offset=base_address,
                                    layer_name=layer_name)

        for offset, data in dos_header.reconstruct():
            pe_data.seek(offset)
            pe_data.write(data)

        pe = pefile.PE(data=pe_data.getvalue(), fast_load=True)
        pe.parse_data_directories(
            [pefile.DIRECTORY_ENTRY["IMAGE_DIRECTORY_ENTRY_RESOURCE"]])

        if isinstance(pe.VS_FIXEDFILEINFO, list):
            # pefile >= 2018.8.8 (estimated)
            version_struct = pe.VS_FIXEDFILEINFO[0]
        else:
            # pefile <= 2017.11.5 (estimated)
            version_struct = pe.VS_FIXEDFILEINFO

        major = version_struct.ProductVersionMS >> 16
        minor = version_struct.ProductVersionMS & 0xFFFF
        product = version_struct.ProductVersionLS >> 16
        build = version_struct.ProductVersionLS & 0xFFFF

        pe_data.close()

        return major, minor, product, build
예제 #12
0
    def dump_pe(cls,
                context: interfaces.context.ContextInterface,
                pe_table_name: str,
                dll_entry: interfaces.objects.ObjectInterface,
                layer_name: str = None) -> interfaces.plugins.FileInterface:
        """Extracts the complete data for a process as a FileInterface

        Args:
            context: the context to operate upon
            pe_table_name: the name for the symbol table containing the PE format symbols
            dll_entry: the object representing the module
            layer_name: the layer that the DLL lives within

        Returns:
            A FileInterface object containing the complete data for the DLL or None in the case of failure"""
        filedata = None
        try:
            try:
                name = dll_entry.FullDllName.get_string()
            except exceptions.InvalidAddressException:
                name = 'UnreadbleDLLName'

            if layer_name is None:
                layer_name = dll_entry.vol.layer_name

            filedata = interfaces.plugins.FileInterface(
                "{0}.{1:#x}.{2:#x}.dmp".format(ntpath.basename(name),
                                               dll_entry.vol.offset,
                                               dll_entry.DllBase))

            dos_header = context.object(pe_table_name + constants.BANG +
                                        "_IMAGE_DOS_HEADER",
                                        offset=dll_entry.DllBase,
                                        layer_name=layer_name)

            for offset, data in dos_header.reconstruct():
                filedata.data.seek(offset)
                filedata.data.write(data)
        except Exception as excp:
            vollog.debug("Unable to dump dll at offset {}: {}".format(
                dll_entry.DllBase, excp))
        return filedata
예제 #13
0
    def get_cmdline(cls, context: interfaces.context.ContextInterface,
                    kernel_table_name: str, proc):
        """Extracts the cmdline from PEB

        Args:
            context: the context to operate upon
            kernel_table_name: the name for the symbol table containing the kernel's symbols
            proc: the process object

        Returns:
            A string with the command line
        """

        proc_layer_name = proc.add_process_layer()

        peb = context.object(kernel_table_name + constants.BANG + "_PEB",
                             layer_name=proc_layer_name,
                             offset=proc.Peb)
        result_text = peb.ProcessParameters.CommandLine.get_string()

        return result_text