def write_layer(
            cls,
            context: interfaces.context.ContextInterface,
            layer_name: str,
            preferred_name: str,
            open_method: Type[plugins.FileHandlerInterface],
            chunk_size: Optional[int] = None,
            progress_callback: Optional[constants.ProgressCallback] = None) -> Optional[plugins.FileHandlerInterface]:
        """Produces a FileHandler from the named layer in the provided context or None on failure

        Args:
            context: the context from which to read the memory layer
            layer_name: the name of the layer to write out
            preferred_name: a string with the preferred filename for hte file
            chunk_size: an optional size for the chunks that should be written (defaults to 0x500000)
            open_method: class for creating FileHandler context managers
            progress_callback: an optional function that takes a percentage and a string that displays output
        """

        if layer_name not in context.layers:
            raise exceptions.LayerException("Layer not found")
        layer = context.layers[layer_name]

        if chunk_size is None:
            chunk_size = cls.default_block_size

        file_handle = open_method(preferred_name)
        for i in range(0, layer.maximum_address, chunk_size):
            current_chunk_size = min(chunk_size, layer.maximum_address - i)
            data = layer.read(i, current_chunk_size, pad = True)
            file_handle.write(data)
            if progress_callback:
                progress_callback((i / layer.maximum_address) * 100, 'Writing layer {}'.format(layer_name))
        return file_handle

def
write_layer
(
cls
,
context
:
interfaces
.
context
.
ContextInterface
,
layer_name
:
str
,
preferred_name
:
str
,
open_method
:
Type
[
plugins
.
FileHandlerInterface
]
,
chunk_size
:
Optional
[
int
]
=
,
progress_callback
:
Optional
[
constants
.
ProgressCallback
]
=
)
->
Optional
[
plugins
.
FileHandlerInterface
]
:
if
layer_name
not
in
context
.
layers
:
raise
exceptions
.
LayerException
(
"Layer not found"
)
layer
=
context
.
layers
[
layer_name
]
if
chunk_size
is
:
chunk_size
=
cls
.
default_block_size
file_handle
=
open_method
(
preferred_name
)
for
i
in
range
(
0
,
layer
.
maximum_address
,
chunk_size
)
:
current_chunk_size
=
min
(
chunk_size
,
layer
.
maximum_address
i
)
data
=
layer
.
read
(
i
,
current_chunk_size
,
pad
=
True
)
file_handle
.
write
(
data
)
if
progress_callback
:
progress_callback
(
(
i
/
layer
.
maximum_address
)
*
100
,
'Writing layer {}'
.
format
(
layer_name
)
)
return
file_handle


def _generate_layers(self):
        """List layer names from this run"""
        for name in self.context.layers:
            yield (0, (name,))

def _generate_layers ( self ) : for name in self . context . layers : yield ( 0 , ( name , ) )


def locate_banners(cls, context: interfaces.context.ContextInterface, layer_name: str):
        """Identifies banners from a memory image"""
        layer = context.layers[layer_name]
        for offset in layer.scan(
                context = context,
                scanner = scanners.RegExScanner(rb"(Linux version|Darwin Kernel Version) [0-9]+\.[0-9]+\.[0-9]+")):
            data = layer.read(offset, 0xfff)
            data_index = data.find(b'\x00')
            if data_index > 0:
                data = data[:data_index].strip()
                failed = [
                    char for char in data
                    if char not in b' #()+,;/-.0123456789:@ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz~'
                ]
                if not failed:
                    yield format_hints.Hex(offset), str(data, encoding = 'latin-1', errors = '?')


Look up the array of memory protection constants from the memory sample . These don t change often but if they do in the future then finding them dynamically versus hard - coding here will ensure we parse them properly .

def protect_values(cls, context: interfaces.context.ContextInterface, layer_name: str,
                       symbol_table: str) -> Iterable[int]:
        """Look up the array of memory protection constants from the memory
        sample. These don't change often, but if they do in the future, then
        finding them dynamically versus hard-coding here will ensure we parse
        them properly.

        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
        """

        kvo = context.layers[layer_name].config["kernel_virtual_offset"]
        ntkrnlmp = context.module(symbol_table, layer_name = layer_name, offset = kvo)
        addr = ntkrnlmp.get_symbol("MmProtectToValue").address
        values = ntkrnlmp.object(object_type = "array", offset = addr, subtype = ntkrnlmp.get_type("int"), count = 32)
        return values

def protect_values ( cls , context : interfaces . context . ContextInterface , layer_name : str , symbol_table : str ) -> Iterable [ int ] : kvo = context . layers [ layer_name ] . config [ "kernel_virtual_offset" ] ntkrnlmp = context . module ( symbol_table , layer_name = layer_name , offset = kvo ) addr = ntkrnlmp . get_symbol ( "MmProtectToValue" ) . address values = ntkrnlmp . object ( object_type = "array" , offset = addr , subtype = ntkrnlmp . get_type ( "int" ) , count = 32 ) return values


Lists the Virtual Address Descriptors of a specific process .

def list_vads(cls, proc: interfaces.objects.ObjectInterface,
                  filter_func: Callable[[interfaces.objects.ObjectInterface], bool] = lambda _: False) -> \
            Generator[interfaces.objects.ObjectInterface, None, None]:
        """Lists the Virtual Address Descriptors of a specific process.

        Args:
            proc: _EPROCESS object from which to list the VADs
            filter_func: Function to take a virtual address descriptor value and return True if it should be filtered out

        Returns:
            A list of virtual address descriptors based on the process and filtered based on the filter function
        """
        for vad in proc.get_vad_root().traverse():
            if not filter_func(vad):
                yield vad

def list_vads ( cls , proc : interfaces . objects . ObjectInterface , filter_func : Callable [ [ interfaces . objects . ObjectInterface ] , bool ] = lambda _ : False ) -> Generator [ interfaces . objects . ObjectInterface , None , None ] : for vad in proc . get_vad_root ( ) . traverse ( ) : if not filter_func ( vad ) : yield vad


Extracts the complete data for Vad as a FileInterface .

def vad_dump(cls,
                 context: interfaces.context.ContextInterface,
                 proc: interfaces.objects.ObjectInterface,
                 vad: interfaces.objects.ObjectInterface,
                 open_method: Type[
                     interfaces.plugins.FileHandlerInterface],
                 maxsize: int = MAXSIZE_DEFAULT) -> Optional[interfaces.plugins.FileHandlerInterface]:
        """Extracts the complete data for Vad as a FileInterface.

        Args:
            context: The context to retrieve required elements (layers, symbol tables) from
            proc: an _EPROCESS instance
            vad: The suspected VAD to extract (ObjectInterface)
            open_method: class to provide context manager for opening the file
            maxsize: Max size of VAD section (default MAXSIZE_DEFAULT)

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

        try:
            vad_start = vad.get_start()
            vad_end = vad.get_end()
        except AttributeError:
            vollog.debug("Unable to find the starting/ending VPN member")
            return

        if maxsize > 0 and (vad_end - vad_start) > maxsize:
            vollog.debug("Skip VAD dump {0:#x}-{1:#x} due to maxsize limit".format(vad_start, vad_end))
            return

        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))
            return None

        proc_layer = context.layers[proc_layer_name]
        file_name = "pid.{0}.vad.{1:#x}-{2:#x}.dmp".format(proc_id, vad_start, vad_end)
        try:
            file_handle = open_method(file_name)
            chunk_size = 1024 * 1024 * 10
            offset = vad_start
            while offset < vad_end:
                to_read = min(chunk_size, vad_end - offset)
                data = proc_layer.read(offset, to_read, pad = True)
                if not data:
                    break
                file_handle.write(data)
                offset += to_read

        except Exception as excp:
            vollog.debug("Unable to dump VAD {}: {}".format(file_name, excp))
            return

        return file_handle


Enumerate the registry for all the users .

def lookup_user_sids(self) -> Dict[str, str]:
        """
        Enumerate the registry for all the users.

        Returns:
            An dictionary of {sid: user name}
        """

        key = "Microsoft\\Windows NT\\CurrentVersion\\ProfileList"
        val = "ProfileImagePath"

        sids = {}
        for hive in hivelist.HiveList.list_hives(context = self.context,
                                                 base_config_path = self.config_path,
                                                 layer_name = self.config['primary'],
                                                 symbol_table = self.config['nt_symbols'],
                                                 hive_offsets = None):

            try:
                for subkey in hive.get_key(key).get_subkeys():
                    sid = str(subkey.get_name())
                    path = ""
                    for node in subkey.get_values():
                        try:
                            value_node_name = node.get_name() or "(Default)"
                        except (exceptions.InvalidAddressException, layers.registry.RegistryFormatException) as excp:
                            continue
                        try:
                            value_data = node.decode_data()
                            if isinstance(value_data, int):
                                value_data = format_hints.MultiTypeData(value_data, encoding = 'utf-8')
                            elif registry.RegValueTypes.get(node.Type) == registry.RegValueTypes.REG_BINARY:
                                value_data = format_hints.MultiTypeData(value_data, show_hex = True)
                            elif registry.RegValueTypes.get(node.Type) == registry.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')
                            if value_node_name == val:
                                path = str(value_data).replace('\\x00', '')[:-1]
                                user = ntpath.basename(path)
                                sids[sid] = user
                        except (ValueError, exceptions.InvalidAddressException,
                                layers.registry.RegistryFormatException) as excp:
                            continue
            except (KeyError, exceptions.InvalidAddressException):
                continue

        return sids


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 .

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


Given a base address and a list of layer names find a layer that can access the specified address .

def find_session_layer(cls, context: interfaces.context.ContextInterface, session_layers: Iterable[str],
                           base_address: int):
        """Given a base address and a list of layer names, find a layer that
        can access the specified address.

        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
            session_layers: A list of session layer names
            base_address: The base address to identify the layers that can access it

        Returns:
            Layer name or None if no layers that contain the base address can be found
        """

        for layer_name in session_layers:
            if context.layers[layer_name].is_valid(base_address):
                return layer_name

        return None

def find_session_layer ( cls , context : interfaces . context . ContextInterface , session_layers : Iterable [ str ] , base_address : int ) : for layer_name in session_layers : if context . layers [ layer_name ] . is_valid ( base_address ) : return layer_name return None


Lists all the modules in the primary layer .

def list_modules(cls, context: interfaces.context.ContextInterface, layer_name: str,
                     symbol_table: str) -> Iterable[interfaces.objects.ObjectInterface]:
        """Lists all the modules in the primary layer.

        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

        Returns:
            A list of Modules as retrieved from PsLoadedModuleList
        """

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

        try:
            # use this type if its available (starting with windows 10)
            ldr_entry_type = ntkrnlmp.get_type("_KLDR_DATA_TABLE_ENTRY")
        except exceptions.SymbolError:
            ldr_entry_type = ntkrnlmp.get_type("_LDR_DATA_TABLE_ENTRY")

        type_name = ldr_entry_type.type_name.split(constants.BANG)[1]

        list_head = ntkrnlmp.get_symbol("PsLoadedModuleList").address
        list_entry = ntkrnlmp.object(object_type = "_LIST_ENTRY", offset = list_head)
        reloff = ldr_entry_type.relative_child_offset("InLoadOrderLinks")
        module = ntkrnlmp.object(object_type = type_name, offset = list_entry.vol.offset - reloff, absolute = True)

        for mod in module.InLoadOrderLinks:
            yield mod


Windows encodes pointers to objects and decodes them on the fly before using them .

def _decode_pointer(self, value, magic):
        """Windows encodes pointers to objects and decodes them on the fly
        before using them.

        This function mimics the decoding routine so we can generate the
        proper pointer values as well.
        """

        value = value & 0xFFFFFFFFFFFFFFF8
        value = value >> magic
        # if (value & (1 << 47)):
        #    value = value | 0xFFFF000000000000

        return value

def
_decode_pointer
(
self
,
value
,
magic
)
:
value
=
value
&
0xFFFFFFFFFFFFFFF8
value
=
value
>>
magic
# if (value & (1 << 47)):
#    value = value | 0xFFFF000000000000
return
value


Given a handle table entry ( _HANDLE_TABLE_ENTRY ) structure from a process handle table determine where the corresponding object s _OBJECT_HEADER can be found .

def _get_item(self, handle_table_entry, handle_value):
        """Given  a handle table entry (_HANDLE_TABLE_ENTRY) structure from a
        process' handle table, determine where the corresponding object's
        _OBJECT_HEADER can be found."""

        virtual = self.config["primary"]

        try:
            # before windows 7

            if not self.context.layers[virtual].is_valid(handle_table_entry.Object):
                return None

            fast_ref = handle_table_entry.Object.cast("_EX_FAST_REF")
            object_header = fast_ref.dereference().cast("_OBJECT_HEADER")
            object_header.GrantedAccess = handle_table_entry.GrantedAccess
        except AttributeError:
            # starting with windows 8

            if handle_table_entry.LowValue == 0:
                return None

            magic = self.find_sar_value()
            # is this the right thing to raise here?
            if magic is None:
                return None
                #if not has_capstone:
                #    raise AttributeError("Unable to find the SAR value for decoding handle table pointers")
                #else:
                #    raise exceptions.MissingModuleException("capstone","Unable to find the SAR value for decoding handle table pointers")

            offset = self._decode_pointer(handle_table_entry.LowValue, magic)
            # print("LowValue: {0:#x} Magic: {1:#x} Offset: {2:#x}".format(handle_table_entry.InfoTable, magic, offset))
            object_header = self.context.object(self.config["nt_symbols"] + constants.BANG + "_OBJECT_HEADER",
                                                virtual,
                                                offset = offset)
            object_header.GrantedAccess = handle_table_entry.GrantedAccessBits

        object_header.HandleValue = handle_value
        return object_header


Locate ObpCaptureHandleInformationEx if it exists in the sample .

def find_sar_value(self):
        """Locate ObpCaptureHandleInformationEx if it exists in the sample.

        Once found, parse it for the SAR value that we need to decode
        pointers in the _HANDLE_TABLE_ENTRY which allows us to find the
        associated _OBJECT_HEADER.
        """

        if self._sar_value is None:

            if not has_capstone:
                return None

            virtual_layer_name = self.config['primary']
            kvo = self.context.layers[virtual_layer_name].config['kernel_virtual_offset']
            ntkrnlmp = self.context.module(self.config["nt_symbols"], layer_name = virtual_layer_name, offset = kvo)

            try:
                func_addr = ntkrnlmp.get_symbol("ObpCaptureHandleInformationEx").address
            except exceptions.SymbolError:
                return None

            data = self.context.layers.read(virtual_layer_name, kvo + func_addr, 0x200)
            if data is None:
                return None

            md = capstone.Cs(capstone.CS_ARCH_X86, capstone.CS_MODE_64)

            for (address, size, mnemonic, op_str) in md.disasm_lite(data, kvo + func_addr):
                # print("{} {} {} {}".format(address, size, mnemonic, op_str))

                if mnemonic.startswith("sar"):
                    # if we don't want to parse op strings, we can disasm the
                    # single sar instruction again, but we use disasm_lite for speed
                    self._sar_value = int(op_str.split(",")[1].strip(), 16)
                    break

        return self._sar_value


List the executive object types ( _OBJECT_TYPE ) using the ObTypeIndexTable or ObpObjectTypes symbol ( differs per OS ) . This method will be necessary for determining what type of object we have given an object header .

def get_type_map(cls, context: interfaces.context.ContextInterface, layer_name: str,
                     symbol_table: str) -> Dict[int, str]:
        """List the executive object types (_OBJECT_TYPE) using the
        ObTypeIndexTable or ObpObjectTypes symbol (differs per OS). This method
        will be necessary for determining what type of object we have given an
        object header.

        Note:
            The object type index map was hard coded into profiles in previous versions of volatility.
            It is now generated dynamically.

        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

        Returns:
            A mapping of type indicies to type names
        """

        type_map = {}  # type: Dict[int, str]

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

        try:
            table_addr = ntkrnlmp.get_symbol("ObTypeIndexTable").address
        except exceptions.SymbolError:
            table_addr = ntkrnlmp.get_symbol("ObpObjectTypes").address

        trans_layer = context.layers[layer_name]

        if not trans_layer.is_valid(kvo + table_addr):
            return type_map

        ptrs = ntkrnlmp.object(object_type = "array",
                               offset = table_addr,
                               subtype = ntkrnlmp.get_type("pointer"),
                               count = 100)

        for i, ptr in enumerate(ptrs):  # type: ignore
            # the first entry in the table is always null. break the
            # loop when we encounter the first null entry after that
            if i > 0 and ptr == 0:
                break

            try:
                objt = ptr.dereference().cast(symbol_table + constants.BANG + "_OBJECT_TYPE")
                type_name = objt.Name.String
            except exceptions.InvalidAddressException:
                vollog.log(constants.LOGLEVEL_VVV,
                           "Cannot access _OBJECT_HEADER Name at {0:#x}".format(objt.vol.offset))
                continue

            type_map[i] = type_name

        return type_map


Find the ObHeaderCookie value ( if it exists )

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)

def
find_cookie
(
cls
,
context
:
interfaces
.
context
.
ContextInterface
,
layer_name
:
str
,
symbol_table
:
str
)
->
Optional
[
interfaces
.
objects
.
ObjectInterface
]
:
try
:
offset
=
context
.
symbol_space
.
get_symbol
(
symbol_table
+
constants
.
BANG
+
"ObHeaderCookie"
)
.
address
except
exceptions
.
SymbolError
:
return
kvo
=
context
.
layers
[
layer_name
]
.
config
[
'kernel_virtual_offset'
]
return
context
.
object
(
symbol_table
+
constants
.
BANG
+
"unsigned int"
,
layer_name
,
offset
=
kvo
+
offset
)


Parse a process handle table and yield valid handle table entries going as deep into the table levels as necessary .

def _make_handle_array(self, offset, level, depth = 0):
        """Parse a process' handle table and yield valid handle table entries,
        going as deep into the table "levels" as necessary."""
        virtual = self.config["primary"]
        kvo = self.context.layers[virtual].config['kernel_virtual_offset']

        ntkrnlmp = self.context.module(self.config["nt_symbols"], layer_name = virtual, offset = kvo)

        if level > 0:
            subtype = ntkrnlmp.get_type("pointer")
            count = 0x1000 / subtype.size
        else:
            subtype = ntkrnlmp.get_type("_HANDLE_TABLE_ENTRY")
            count = 0x1000 / subtype.size

        if not self.context.layers[virtual].is_valid(offset):
            yield None

        table = ntkrnlmp.object(object_type = "array",
                                offset = offset,
                                subtype = subtype,
                                count = int(count),
                                absolute = True)

        layer_object = self.context.layers[virtual]
        masked_offset = (offset & layer_object.maximum_address)

        for entry in table:

            if level > 0:
                for x in self._make_handle_array(entry, level - 1, depth):
                    yield x
                depth += 1
            else:
                handle_multiplier = 4
                handle_level_base = depth * count * handle_multiplier

                handle_value = ((entry.vol.offset - masked_offset) /
                                (subtype.size / handle_multiplier)) + handle_level_base

                item = self._get_item(entry, handle_value)

                if item is None:
                    continue
                try:
                    if item.TypeIndex != 0x0:
                        yield item
                except AttributeError:
                    if item.Type.Name:
                        yield item
                except exceptions.InvalidAddressException:
                    continue

def _make_handle_array ( self , offset , level , depth = 0 ) : virtual = self . config [ "primary" ] kvo = self . context . layers [ virtual ] . config [ 'kernel_virtual_offset' ] ntkrnlmp = self . context . module ( self . config [ "nt_symbols" ] , layer_name = virtual , offset = kvo ) if level > 0 : subtype = ntkrnlmp . get_type ( "pointer" ) count = 0x1000 / subtype . size else : subtype = ntkrnlmp . get_type ( "_HANDLE_TABLE_ENTRY" ) count = 0x1000 / subtype . size if not self . context . layers [ virtual ] . is_valid ( offset ) : yield None table = ntkrnlmp . object ( object_type = "array" , offset = offset , subtype = subtype , count = int ( count ) , absolute = True ) layer_object = self . context . layers [ virtual ] masked_offset = ( offset & layer_object . maximum_address ) for entry in table : if level > 0 : for x in self . _make_handle_array ( entry , level - 1 , depth ) : yield x depth += 1 else : handle_multiplier = 4 handle_level_base = depth * count * handle_multiplier handle_value = ( ( entry . vol . offset - masked_offset ) / ( subtype . size / handle_multiplier ) ) + handle_level_base item = self . _get_item ( entry , handle_value ) if item is None : continue try : if item . TypeIndex != 0x0 : yield item except AttributeError : if item . Type . Name : yield item except exceptions . InvalidAddressException : continue


Scans for file objects using the poolscanner module and constraints .

def scan_files(cls,
                   context: interfaces.context.ContextInterface,
                   layer_name: str,
                   symbol_table: str) -> \
            Iterable[interfaces.objects.ObjectInterface]:
        """Scans for file objects using the poolscanner module and constraints.

        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

        Returns:
            A list of File objects as found from the `layer_name` layer based on File pool signatures
        """

        constraints = poolscanner.PoolScanner.builtin_constraints(symbol_table, [b'Fil\xe5', b'File'])

        for result in poolscanner.PoolScanner.generate_pool_scan(context, layer_name, symbol_table, constraints):

            _constraint, mem_object, _header = result
            yield mem_object

def scan_files ( cls , context : interfaces . context . ContextInterface , layer_name : str , symbol_table : str ) -> Iterable [ interfaces . objects . ObjectInterface ] : constraints = poolscanner . PoolScanner . builtin_constraints ( symbol_table , [ b'Fil\xe5' , b'File' ] ) for result in poolscanner . PoolScanner . generate_pool_scan ( context , layer_name , symbol_table , constraints ) : _constraint , mem_object , _header = result yield mem_object


def createservicesid(svc) -> str:
    """ Calculate the Service SID """
    uni = ''.join([c + '\x00' for c in svc])
    sha = hashlib.sha1(uni.upper().encode("utf-8")).digest()  # pylint: disable-msg=E1101
    dec = list()
    for i in range(5):
        ## The use of struct here is OK. It doesn't make much sense
        ## to leverage obj.Object inside this loop.
        dec.append(struct.unpack('<I', sha[i * 4:i * 4 + 4])[0])
    return 'S-1-5-80-' + '-'.join([str(n) for n in dec])


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

def get_cmdline ( cls , context : interfaces . context . ContextInterface , kernel_table_name : str , proc ) : 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


Scans for mutants using the poolscanner module and constraints .

def scan_mutants(cls,
                     context: interfaces.context.ContextInterface,
                     layer_name: str,
                     symbol_table: str) -> \
            Iterable[interfaces.objects.ObjectInterface]:
        """Scans for mutants using the poolscanner module and constraints.

        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

        Returns:
              A list of Mutant objects found by scanning memory for the Mutant pool signatures
        """

        constraints = poolscanner.PoolScanner.builtin_constraints(symbol_table, [b'Mut\xe1', b'Muta'])

        for result in poolscanner.PoolScanner.generate_pool_scan(context, layer_name, symbol_table, constraints):

            _constraint, mem_object, _header = result
            yield mem_object

def scan_mutants ( cls , context : interfaces . context . ContextInterface , layer_name : str , symbol_table : str ) -> Iterable [ interfaces . objects . ObjectInterface ] : constraints = poolscanner . PoolScanner . builtin_constraints ( symbol_table , [ b'Mut\xe1' , b'Muta' ] ) for result in poolscanner . PoolScanner . generate_pool_scan ( context , layer_name , symbol_table , constraints ) : _constraint , mem_object , _header = result yield mem_object


Finds how deep the pid is in the processes list .

def find_level(self, pid: objects.Pointer) -> None:
        """Finds how deep the pid is in the processes list."""
        seen = set([])
        seen.add(pid)
        level = 0
        proc = self._processes.get(pid, None)
        while proc is not None and proc.InheritedFromUniqueProcessId not in seen:
            child_list = self._children.get(proc.InheritedFromUniqueProcessId, set([]))
            child_list.add(proc.UniqueProcessId)
            self._children[proc.InheritedFromUniqueProcessId] = child_list
            proc = self._processes.get(proc.InheritedFromUniqueProcessId, None)
            level += 1
        self._levels[pid] = level

def find_level ( self , pid : objects . Pointer ) -> None : seen = set ( [ ] ) seen . add ( pid ) level = 0 proc = self . _processes . get ( pid , None ) while proc is not None and proc . InheritedFromUniqueProcessId not in seen : child_list = self . _children . get ( proc . InheritedFromUniqueProcessId , set ( [ ] ) ) child_list . add ( proc . UniqueProcessId ) self . _children [ proc . InheritedFromUniqueProcessId ] = child_list proc = self . _processes . get ( proc . InheritedFromUniqueProcessId , None ) level += 1 self . _levels [ pid ] = level


def _generator(self):
        """Generates the Tree of processes."""
        for proc in pslist.PsList.list_processes(self.context, self.config['primary'], self.config['nt_symbols']):

            if not self.config.get('physical', pslist.PsList.PHYSICAL_DEFAULT):
                offset = proc.vol.offset
            else:
                layer_name = self.config['primary']
                memory = self.context.layers[layer_name]
                (_, _, offset, _, _) = list(memory.mapping(offset = proc.vol.offset, length = 0))[0]

            self._processes[proc.UniqueProcessId] = proc

        # Build the child/level maps
        for pid in self._processes:
            self.find_level(pid)

        def yield_processes(pid):
            proc = self._processes[pid]
            row = (proc.UniqueProcessId, proc.InheritedFromUniqueProcessId,
                   proc.ImageFileName.cast("string", max_length = proc.ImageFileName.vol.count, errors = 'replace'),
                   format_hints.Hex(offset), proc.ActiveThreads, proc.get_handle_count(), proc.get_session_id(),
                   proc.get_is_wow64(), proc.get_create_time(), proc.get_exit_time())

            yield (self._levels[pid] - 1, row)
            for child_pid in self._children.get(pid, []):
                yield from yield_processes(child_pid)

        for pid in self._levels:
            if self._levels[pid] == 1:
                yield from yield_processes(pid)

def
_generator
(
self
)
:
for
proc
in
pslist
.
PsList
.
list_processes
(
self
.
context
,
self
.
config
[
'primary'
]
,
self
.
config
[
'nt_symbols'
]
)
:
if
not
self
.
config
.
get
(
'physical'
,
pslist
.
PsList
.
PHYSICAL_DEFAULT
)
:
offset
=
proc
.
vol
.
offset
else
:
layer_name
=
self
.
config
[
'primary'
]
memory
=
self
.
context
.
layers
[
layer_name
]
(
_
,
_
,
offset
,
_
,
_
)
=
list
(
memory
.
mapping
(
offset
=
proc
.
vol
.
offset
,
length
=
0
)
)
[
0
]
self
.
_processes
[
proc
.
UniqueProcessId
]
=
proc
# Build the child/level maps
for
pid
in
self
.
_processes
:
self
.
find_level
(
pid
)
def
yield_processes
(
pid
)
:
proc
=
self
.
_processes
[
pid
]
row
=
(
proc
.
UniqueProcessId
,
proc
.
InheritedFromUniqueProcessId
,
proc
.
ImageFileName
.
cast
(
"string"
,
max_length
=
proc
.
ImageFileName
.
vol
.
count
,
errors
=
'replace'
)
,
format_hints
.
Hex
(
offset
)
,
proc
.
ActiveThreads
,
proc
.
get_handle_count
(
)
,
proc
.
get_session_id
(
)
,
proc
.
get_is_wow64
(
)
,
proc
.
get_create_time
(
)
,
proc
.
get_exit_time
(
)
)
yield
(
self
.
_levels
[
pid
]
1
,
row
)
for
child_pid
in
self
.
_children
.
get
(
pid
,
[
]
)
:
yield
from
yield_processes
(
child_pid
)
for
pid
in
self
.
_levels
:
if
self
.
_levels
[
pid
]
==
1
:
yield
from
yield_processes
(
pid
)


def build_module_collection(cls, context: interfaces.context.ContextInterface, layer_name: str,
                                symbol_table: str) -> contexts.ModuleCollection:
        """Builds a collection of modules.

        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

        Returns:
            A Module collection of available modules based on `Modules.list_modules`
        """

        mods = modules.Modules.list_modules(context, layer_name, symbol_table)
        context_modules = []

        for mod in mods:

            try:
                module_name_with_ext = mod.BaseDllName.get_string()
            except exceptions.InvalidAddressException:
                # there's no use for a module with no name?
                continue

            module_name = os.path.splitext(module_name_with_ext)[0]

            symbol_table_name = None
            if module_name in constants.windows.KERNEL_MODULE_NAMES:
                symbol_table_name = symbol_table

            context_module = contexts.SizedModule(context,
                                                  module_name,
                                                  layer_name,
                                                  mod.DllBase,
                                                  mod.SizeOfImage,
                                                  symbol_table_name = symbol_table_name)

            context_modules.append(context_module)

        return contexts.ModuleCollection(context_modules)


Returns the virtual map from a windows kernel module .

def determine_map(cls, module: interfaces.context.ModuleInterface) -> \
            Dict[str, List[Tuple[int, int]]]:
        """Returns the virtual map from a windows kernel module."""
        layer = module.context.layers[module.layer_name]
        if not isinstance(layer, intel.Intel):
            raise

        result = {}  # type: Dict[str, List[Tuple[int, int]]]
        system_va_type = module.get_enumeration('_MI_SYSTEM_VA_TYPE')
        large_page_size = (layer.page_size ** 2) // module.get_type("_MMPTE").size

        if module.has_symbol('MiVisibleState'):
            symbol = module.get_symbol('MiVisibleState')
            visible_state = module.object(object_type = 'pointer',
                                          offset = symbol.address,
                                          subtype = module.get_type('_MI_VISIBLE_STATE')).dereference()
            if hasattr(visible_state, 'SystemVaRegions'):
                for i in range(visible_state.SystemVaRegions.count):
                    lookup = system_va_type.lookup(i)
                    region_range = result.get(lookup, [])
                    region_range.append(
                        (visible_state.SystemVaRegions[i].BaseAddress, visible_state.SystemVaRegions[i].NumberOfBytes))
                    result[lookup] = region_range
            elif hasattr(visible_state, 'SystemVaType'):
                system_range_start = module.object(object_type = "pointer",
                                                   offset = module.get_symbol("MmSystemRangeStart").address)
                result = cls._enumerate_system_va_type(large_page_size, system_range_start, module,
                                                       visible_state.SystemVaType)
            else:
                raise exceptions.SymbolError(None, module.name, "Required structures not found")
        elif module.has_symbol('MiSystemVaType'):
            system_range_start = module.object(object_type = "pointer",
                                               offset = module.get_symbol("MmSystemRangeStart").address)
            symbol = module.get_symbol('MiSystemVaType')
            array_count = (0xFFFFFFFF + 1 - system_range_start) // large_page_size
            type_array = module.object(object_type = 'array',
                                       offset = symbol.address,
                                       count = array_count,
                                       subtype = module.get_type('char'))

            result = cls._enumerate_system_va_type(large_page_size, system_range_start, module, type_array)
        else:
            raise exceptions.SymbolError(None, module.name, "Required structures not found")

        return result


Scans for modules using the poolscanner module and constraints .

def scan_modules(cls,
                     context: interfaces.context.ContextInterface,
                     layer_name: str,
                     symbol_table: str) -> \
            Iterable[interfaces.objects.ObjectInterface]:
        """Scans for modules using the poolscanner module and constraints.

        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

        Returns:
            A list of Driver objects as found from the `layer_name` layer based on Driver pool signatures
        """

        constraints = poolscanner.PoolScanner.builtin_constraints(symbol_table, [b'MmLd'])

        for result in poolscanner.PoolScanner.generate_pool_scan(context, layer_name, symbol_table, constraints):

            _constraint, mem_object, _header = result
            yield mem_object

def scan_modules ( cls , context : interfaces . context . ContextInterface , layer_name : str , symbol_table : str ) -> Iterable [ interfaces . objects . ObjectInterface ] : constraints = poolscanner . PoolScanner . builtin_constraints ( symbol_table , [ b'MmLd' ] ) for result in poolscanner . PoolScanner . generate_pool_scan ( context , layer_name , symbol_table , constraints ) : _constraint , mem_object , _header = result yield mem_object


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


def find_session_layer(cls, context: interfaces.context.ContextInterface, session_layers: Iterable[str],
                           base_address: int):
        """Given a base address and a list of layer names, find a layer that
        can access the specified address.

        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
            session_layers: A list of session layer names
            base_address: The base address to identify the layers that can access it

        Returns:
            Layer name or None if no layers that contain the base address can be found
        """

        for layer_name in session_layers:
            if context.layers[layer_name].is_valid(base_address):
                return layer_name

        return None

def find_session_layer ( cls , context : interfaces . context . ContextInterface , session_layers : Iterable [ str ] , base_address : int ) : for layer_name in session_layers : if context . layers [ layer_name ] . is_valid ( base_address ) : return layer_name return None


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

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
=
,
prefix
:
str
=
''
)
->
Optional
[
interfaces
.
plugins
.
FileHandlerInterface
]
:
try
:
try
:
name
=
dll_entry
.
FullDllName
.
get_string
(
)
except
exceptions
.
InvalidAddressException
:
name
=
'UnreadbleDLLName'
if
layer_name
is
:
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
return
file_handle


Check if a VAD region is either entirely unavailable due to paging entirely consisting of zeros or a combination of the two . This helps ignore false positives whose VAD flags match task . _injection_filter requirements but there s no data and thus not worth reporting it .

def is_vad_empty(cls, proc_layer, vad):
        """Check if a VAD region is either entirely unavailable due to paging,
        entirely consisting of zeros, or a combination of the two. This helps
        ignore false positives whose VAD flags match task._injection_filter
        requirements but there's no data and thus not worth reporting it.

        Args:
            proc_layer: the process layer
            vad: the MMVAD structure to test

        Returns:
            A boolean indicating whether a vad is empty or not
        """

        CHUNK_SIZE = 0x1000
        all_zero_page = "\x00" * CHUNK_SIZE

        offset = 0
        vad_length = vad.get_end() - vad.get_start()

        while offset < vad_length:
            next_addr = vad.get_start() + offset
            if proc_layer.is_valid(next_addr, CHUNK_SIZE) and proc_layer.read(next_addr, CHUNK_SIZE) != all_zero_page:
                return False
            offset += CHUNK_SIZE

        return True

def is_vad_empty ( cls , proc_layer , vad ) : CHUNK_SIZE = 0x1000 all_zero_page = "\x00" * CHUNK_SIZE offset = 0 vad_length = vad . get_end ( ) - vad . get_start ( ) while offset < vad_length : next_addr = vad . get_start ( ) + offset if proc_layer . is_valid ( next_addr , CHUNK_SIZE ) and proc_layer . read ( next_addr , CHUNK_SIZE ) != all_zero_page : return False offset += CHUNK_SIZE return True


Generate memory regions for a process that may contain injected code .

def list_injections(
            cls, context: interfaces.context.ContextInterface, kernel_layer_name: str, symbol_table: str,
            proc: interfaces.objects.ObjectInterface) -> Iterable[Tuple[interfaces.objects.ObjectInterface, bytes]]:
        """Generate memory regions for a process that may contain injected
        code.

        Args:
            context: The context to retrieve required elements (layers, symbol tables) from
            kernel_layer_name: The name of the kernel layer from which to read the VAD protections
            symbol_table: The name of the table containing the kernel symbols
            proc: an _EPROCESS instance

        Returns:
            An iterable of VAD instances and the first 64 bytes of data containing in that region
        """
        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))
            return

        proc_layer = context.layers[proc_layer_name]

        for vad in proc.get_vad_root().traverse():
            protection_string = vad.get_protection(
                vadinfo.VadInfo.protect_values(context, kernel_layer_name, symbol_table), vadinfo.winnt_protections)
            write_exec = "EXECUTE" in protection_string and "WRITE" in protection_string

            # the write/exec check applies to everything
            if not write_exec:
                continue

            if (vad.get_private_memory() == 1
                and vad.get_tag() == "VadS") or (vad.get_private_memory() == 0
                                                 and protection_string != "PAGE_EXECUTE_WRITECOPY"):
                if cls.is_vad_empty(proc_layer, vad):
                    continue

                data = proc_layer.read(vad.get_start(), 64, pad = True)
                yield vad, data


Get built - in PoolConstraints given a list of pool tags .

def builtin_constraints(symbol_table: str, tags_filter: List[bytes] = None) -> List[PoolConstraint]:
        """Get built-in PoolConstraints given a list of pool tags.

        The tags_filter is a list of pool tags, and the associated
        PoolConstraints are  returned. If tags_filter is empty or
        not supplied, then all builtin constraints are returned.

        Args:
            symbol_table: The name of the symbol table to prepend to the types used
            tags_filter: List of tags to return or None to return all

        Returns:
            A list of well-known constructed PoolConstraints that match the provided tags
        """

        builtins = [
            # atom tables
            PoolConstraint(b'AtmT',
                           type_name = symbol_table + constants.BANG + "_RTL_ATOM_TABLE",
                           size = (200, None),
                           page_type = PoolType.PAGED | PoolType.NONPAGED | PoolType.FREE),
            # processes on windows before windows 8
            PoolConstraint(b'Pro\xe3',
                           type_name = symbol_table + constants.BANG + "_EPROCESS",
                           object_type = "Process",
                           size = (600, None),
                           skip_type_test = True,
                           page_type = PoolType.PAGED | PoolType.NONPAGED | PoolType.FREE),
            # processes on windows starting with windows 8
            PoolConstraint(b'Proc',
                           type_name = symbol_table + constants.BANG + "_EPROCESS",
                           object_type = "Process",
                           size = (600, None),
                           page_type = PoolType.PAGED | PoolType.NONPAGED | PoolType.FREE),
            # files on windows before windows 8
            PoolConstraint(b'Fil\xe5',
                           type_name = symbol_table + constants.BANG + "_FILE_OBJECT",
                           object_type = "File",
                           size = (150, None),
                           page_type = PoolType.PAGED | PoolType.NONPAGED | PoolType.FREE),
            # files on windows starting with windows 8
            PoolConstraint(b'File',
                           type_name = symbol_table + constants.BANG + "_FILE_OBJECT",
                           object_type = "File",
                           size = (150, None),
                           page_type = PoolType.PAGED | PoolType.NONPAGED | PoolType.FREE),
            # mutants on windows before windows 8
            PoolConstraint(b'Mut\xe1',
                           type_name = symbol_table + constants.BANG + "_KMUTANT",
                           object_type = "Mutant",
                           size = (64, None),
                           page_type = PoolType.PAGED | PoolType.NONPAGED | PoolType.FREE),
            # mutants on windows starting with windows 8
            PoolConstraint(b'Muta',
                           type_name = symbol_table + constants.BANG + "_KMUTANT",
                           object_type = "Mutant",
                           size = (64, None),
                           page_type = PoolType.PAGED | PoolType.NONPAGED | PoolType.FREE),
            # drivers on windows before windows 8
            PoolConstraint(b'Dri\xf6',
                           type_name = symbol_table + constants.BANG + "_DRIVER_OBJECT",
                           object_type = "Driver",
                           size = (248, None),
                           page_type = PoolType.PAGED | PoolType.NONPAGED | PoolType.FREE),
            # drivers on windows starting with windows 8
            PoolConstraint(b'Driv',
                           type_name = symbol_table + constants.BANG + "_DRIVER_OBJECT",
                           object_type = "Driver",
                           size = (248, None),
                           page_type = PoolType.PAGED | PoolType.NONPAGED | PoolType.FREE),
            # kernel modules
            PoolConstraint(b'MmLd',
                           type_name = symbol_table + constants.BANG + "_LDR_DATA_TABLE_ENTRY",
                           size = (76, None),
                           page_type = PoolType.PAGED | PoolType.NONPAGED | PoolType.FREE),
            # symlinks on windows before windows 8
            PoolConstraint(b'Sym\xe2',
                           type_name = symbol_table + constants.BANG + "_OBJECT_SYMBOLIC_LINK",
                           object_type = "SymbolicLink",
                           size = (72, None),
                           page_type = PoolType.PAGED | PoolType.NONPAGED | PoolType.FREE),
            # symlinks on windows starting with windows 8
            PoolConstraint(b'Symb',
                           type_name = symbol_table + constants.BANG + "_OBJECT_SYMBOLIC_LINK",
                           object_type = "SymbolicLink",
                           size = (72, None),
                           page_type = PoolType.PAGED | PoolType.NONPAGED | PoolType.FREE),
            # registry hives
            PoolConstraint(b'CM10',
                           type_name = symbol_table + constants.BANG + "_CMHIVE",
                           size = (800, None),
                           page_type = PoolType.PAGED | PoolType.NONPAGED | PoolType.FREE,
                           skip_type_test = True),
        ]

        if not tags_filter:
            return builtins

        return [constraint for constraint in builtins if constraint.tag in tags_filter]


def generate_pool_scan(cls,
                           context: interfaces.context.ContextInterface,
                           layer_name: str,
                           symbol_table: str,
                           constraints: List[PoolConstraint]) \
            -> Generator[Tuple[
                             PoolConstraint, interfaces.objects.ObjectInterface, interfaces.objects.ObjectInterface], None, None]:
        """

        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
            constraints: List of pool constraints used to limit the scan results

        Returns:
            Iterable of tuples, containing the constraint that matched, the object from memory, the object header used to determine the object
        """

        # get the object type map
        type_map = handles.Handles.get_type_map(context = context, layer_name = layer_name, symbol_table = symbol_table)

        cookie = handles.Handles.find_cookie(context = context, layer_name = layer_name, symbol_table = symbol_table)

        is_windows_10 = versions.is_windows_10(context, symbol_table)
        is_windows_8_or_later = versions.is_windows_8_or_later(context, symbol_table)

        # start off with the primary virtual layer
        scan_layer = layer_name

        # switch to a non-virtual layer if necessary
        if not is_windows_10:
            scan_layer = context.layers[scan_layer].config['memory_layer']

        if symbols.symbol_table_is_64bit(context, symbol_table):
            alignment = 0x10
        else:
            alignment = 8

        for constraint, header in cls.pool_scan(context, scan_layer, symbol_table, constraints, alignment = alignment):

            mem_object = header.get_object(type_name = constraint.type_name,
                                           use_top_down = is_windows_8_or_later,
                                           executive = constraint.object_type is not None,
                                           native_layer_name = 'primary',
                                           kernel_symbol_table = symbol_table)

            if mem_object is None:
                vollog.log(constants.LOGLEVEL_VVV, "Cannot create an instance of {}".format(constraint.type_name))
                continue

            if constraint.object_type is not None and not constraint.skip_type_test:
                try:
                    if mem_object.get_object_header().get_object_type(type_map, cookie) != constraint.object_type:
                        continue
                except exceptions.InvalidAddressException:
                    vollog.log(constants.LOGLEVEL_VVV,
                               "Cannot test instance type check for {}".format(constraint.type_name))
                    continue

            yield constraint, mem_object, header


Returns the _POOL_HEADER object ( based on the symbol_table template ) after scanning through layer_name returning all headers that match any of the constraints provided . Only one constraint can be provided per tag .

def pool_scan(cls,
                  context: interfaces.context.ContextInterface,
                  layer_name: str,
                  symbol_table: str,
                  pool_constraints: List[PoolConstraint],
                  alignment: int = 8,
                  progress_callback: Optional[constants.ProgressCallback] = None) \
            -> Generator[Tuple[PoolConstraint, interfaces.objects.ObjectInterface], None, None]:
        """Returns the _POOL_HEADER object (based on the symbol_table template)
        after scanning through layer_name returning all headers that match any
        of the constraints provided.  Only one constraint can be provided per
        tag.

        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
            pool_constraints: List of pool constraints used to limit the scan results
            alignment: An optional value that all pool headers will be aligned to
            progress_callback: An optional function to provide progress feedback whilst scanning

        Returns:
            An Iterable of pool constraints and the pool headers associated with them
        """
        # Setup the pattern
        constraint_lookup = {}  # type: Dict[bytes, PoolConstraint]
        for constraint in pool_constraints:
            if constraint.tag in constraint_lookup:
                raise ValueError("Constraint tag is used for more than one constraint: {}".format(repr(constraint.tag)))
            constraint_lookup[constraint.tag] = constraint

        pool_header_table_name = cls.get_pool_header_table(context, symbol_table)
        module = context.module(pool_header_table_name, layer_name, offset = 0)

        # Run the scan locating the offsets of a particular tag
        layer = context.layers[layer_name]
        scanner = PoolHeaderScanner(module, constraint_lookup, alignment)
        yield from layer.scan(context, scanner, progress_callback)


Returns the appropriate symbol_table containing a _POOL_HEADER type even if the original symbol table doesn t contain one .

def get_pool_header_table(cls, context: interfaces.context.ContextInterface, symbol_table: str) -> str:
        """Returns the appropriate symbol_table containing a _POOL_HEADER type, even if the original symbol table
        doesn't contain one.

        Args:
            context: The context that the symbol tables does (or will) reside in
            symbol_table: The expected symbol_table to contain the _POOL_HEADER type
        """
        # Setup the pool header and offset differential
        try:
            context.symbol_space.get_type(symbol_table + constants.BANG + "_POOL_HEADER")
            table_name = symbol_table
        except exceptions.SymbolError:
            # We have to manually load a symbol table

            if symbols.symbol_table_is_64bit(context, symbol_table):
                is_win_7 = versions.is_windows_7(context, symbol_table)
                if is_win_7:
                    pool_header_json_filename = "poolheader-x64-win7"
                else:
                    pool_header_json_filename = "poolheader-x64"
            else:
                pool_header_json_filename = "poolheader-x86"

            # set the class_type to match the normal WindowsKernelIntermedSymbols
            is_vista_or_later = versions.is_vista_or_later(context, symbol_table)
            if is_vista_or_later:
                class_type = extensions.pool.POOL_HEADER_VISTA
            else:
                class_type = extensions.pool.POOL_HEADER

            table_name = intermed.IntermediateSymbolTable.create(context = context,
                                                                 config_path = configuration.path_join(
                                                                     context.symbol_space[symbol_table].config_path,
                                                                     "poolheader"),
                                                                 sub_path = "windows",
                                                                 filename = pool_header_json_filename,
                                                                 table_mapping = {'nt_symbols': symbol_table},
                                                                 class_types = {'_POOL_HEADER': class_type})
        return table_name


Get the data from the cache and separate it into the username domain name and hash data

def parse_decrypted_cache(self, dec_data, uname_len, domain_len, domain_name_len):
        """Get the data from the cache and separate it into the username, domain name, and hash data"""
        uname_offset = 72
        pad = 2 * ((uname_len / 2) % 2)
        domain_offset = int(uname_offset + uname_len + pad)
        pad = 2 * ((domain_len / 2) % 2)
        domain_name_offset = int(domain_offset + domain_len + pad)
        hashh = dec_data[:0x10]
        username = dec_data[uname_offset:uname_offset + uname_len]
        username = username.decode('utf-16-le', 'replace')
        domain = dec_data[domain_offset:domain_offset + domain_len]
        domain = domain.decode('utf-16-le', 'replace')
        domain_name = dec_data[domain_name_offset:domain_name_offset + domain_name_len]
        domain_name = domain_name.decode('utf-16-le', 'replace')

        return (username, domain, domain_name, hashh)

def parse_decrypted_cache ( self , dec_data , uname_len , domain_len , domain_name_len ) : uname_offset = 72 pad = 2 * ( ( uname_len / 2 ) % 2 ) domain_offset = int ( uname_offset + uname_len + pad ) pad = 2 * ( ( domain_len / 2 ) % 2 ) domain_name_offset = int ( domain_offset + domain_len + pad ) hashh = dec_data [ : 0x10 ] username = dec_data [ uname_offset : uname_offset + uname_len ] username = username . decode ( 'utf-16-le' , 'replace' ) domain = dec_data [ domain_offset : domain_offset + domain_len ] domain = domain . decode ( 'utf-16-le' , 'replace' ) domain_name = dec_data [ domain_name_offset : domain_name_offset + domain_name_len ] domain_name = domain_name . decode ( 'utf-16-le' , 'replace' ) return ( username , domain , domain_name , hashh )


Constructs a symbol table containing the symbols for services depending upon the operating system in use .

def create_service_table(context: interfaces.context.ContextInterface, symbol_table: str, config_path: str) -> str:
        """Constructs a symbol table containing the symbols for services
        depending upon the operating system in use.

        Args:
            context: The context to retrieve required elements (layers, symbol tables) from
            symbol_table: The name of the table containing the kernel symbols
            config_path: The configuration path for any settings required by the new table

        Returns:
            A symbol table containing the symbols necessary for services
        """
        native_types = context.symbol_space[symbol_table].natives
        is_64bit = symbols.symbol_table_is_64bit(context, symbol_table)

        if versions.is_windows_xp(context = context, symbol_table = symbol_table) and not is_64bit:
            symbol_filename = "services-xp-x86"
        elif versions.is_xp_or_2003(context = context, symbol_table = symbol_table) and is_64bit:
            symbol_filename = "services-xp-2003-x64"
        elif versions.is_win10_16299_or_later(context = context, symbol_table = symbol_table) and is_64bit:
            symbol_filename = "services-win10-16299-x64"
        elif versions.is_win10_16299_or_later(context = context, symbol_table = symbol_table) and not is_64bit:
            symbol_filename = "services-win10-16299-x86"
        elif versions.is_win10_up_to_15063(context = context, symbol_table = symbol_table) and is_64bit:
            symbol_filename = "services-win8-x64"
        elif versions.is_win10_up_to_15063(context = context, symbol_table = symbol_table) and not is_64bit:
            symbol_filename = "services-win8-x86"
        elif versions.is_win10_15063(context = context, symbol_table = symbol_table) and is_64bit:
            symbol_filename = "services-win10-15063-x64"
        elif versions.is_win10_15063(context = context, symbol_table = symbol_table) and not is_64bit:
            symbol_filename = "services-win10-15063-x86"
        elif versions.is_windows_8_or_later(context = context, symbol_table = symbol_table) and is_64bit:
            symbol_filename = "services-win8-x64"
        elif versions.is_windows_8_or_later(context = context, symbol_table = symbol_table) and not is_64bit:
            symbol_filename = "services-win8-x86"
        elif versions.is_vista_or_later(context = context, symbol_table = symbol_table) and is_64bit:
            symbol_filename = "services-vista-x64"
        elif versions.is_vista_or_later(context = context, symbol_table = symbol_table) and not is_64bit:
            symbol_filename = "services-vista-x86"
        else:
            raise NotImplementedError("This version of Windows is not supported!")

        return intermed.IntermediateSymbolTable.create(context,
                                                       config_path,
                                                       "windows",
                                                       symbol_filename,
                                                       class_types = services.class_types,
                                                       native_types = native_types)


Creates a map of start / end addresses within a virtual address descriptor tree .

def get_vad_maps(task: interfaces.objects.ObjectInterface) -> Iterable[Tuple[int, int]]:
        """Creates a map of start/end addresses within a virtual address
        descriptor tree.

        Args:
            task: The EPROCESS object of which to traverse the vad tree

        Returns:
            An iterable of tuples containing start and end addresses for each descriptor
        """
        vad_root = task.get_vad_root()
        for vad in vad_root.traverse():
            end = vad.get_end()
            start = vad.get_start()
            yield (start, end - start)

def get_vad_maps ( task : interfaces . objects . ObjectInterface ) -> Iterable [ Tuple [ int , int ] ] : vad_root = task . get_vad_root ( ) for vad in vad_root . traverse ( ) : end = vad . get_end ( ) start = vad . get_start ( ) yield ( start , end - start )


Based on code from http : // lab . mediaservice . net / code / cachedump . rb

def decrypt_aes(cls, secret, key):
        """
        Based on code from http://lab.mediaservice.net/code/cachedump.rb
        """
        sha = SHA256.new()
        sha.update(key)
        for _i in range(1, 1000 + 1):
            sha.update(secret[28:60])
        aeskey = sha.digest()

        data = b""
        for i in range(60, len(secret), 16):
            aes = AES.new(aeskey, AES.MODE_CBC, b'\x00' * 16)
            buf = secret[i:i + 16]
            if len(buf) < 16:
                buf += (16 - len(buf)) * "\00"
            data += aes.decrypt(buf)

        return data

def decrypt_aes ( cls , secret , key ) : sha = SHA256 . new ( ) sha . update ( key ) for _i in range ( 1 , 1000 + 1 ) : sha . update ( secret [ 28 : 60 ] ) aeskey = sha . digest ( ) data = b"" for i in range ( 60 , len ( secret ) , 16 ) : aes = AES . new ( aeskey , AES . MODE_CBC , b'\x00' * 16 ) buf = secret [ i : i + 16 ] if len ( buf ) < 16 : buf += ( 16 - len ( buf ) ) * "\00" data += aes . decrypt ( buf ) return data


Python implementation of SystemFunction005 .

def decrypt_secret(cls, secret, key):
        """Python implementation of SystemFunction005.

        Decrypts a block of data with DES using given key.
        Note that key can be longer than 7 bytes."""
        decrypted_data = b''
        j = 0  # key index

        for i in range(0, len(secret), 8):
            enc_block = secret[i:i + 8]
            block_key = key[j:j + 7]
            des_key = hashdump.Hashdump.sidbytes_to_key(block_key)
            des = DES.new(des_key, DES.MODE_ECB)
            enc_block = enc_block + b"\x00" * int(abs(8 - len(enc_block)) % 8)
            decrypted_data += des.decrypt(enc_block)
            j += 7
            if len(key[j:j + 7]) < 7:
                j = len(key[j:j + 7])

        (dec_data_len, ) = unpack("<L", decrypted_data[:4])

        return decrypted_data[8:8 + dec_data_len]

def
decrypt_secret
(
cls
,
secret
,
key
)
:
decrypted_data
=
b''
j
=
0
# key index
for
i
in
range
(
0
,
len
(
secret
)
,
8
)
:
enc_block
=
secret
[
i
:
i
+
8
]
block_key
=
key
[
j
:
j
+
7
]
des_key
=
hashdump
.
Hashdump
.
sidbytes_to_key
(
block_key
)
des
=
DES
.
new
(
des_key
,
DES
.
MODE_ECB
)
enc_block
=
enc_block
+
b"\x00"
*
int
(
abs
(
8
len
(
enc_block
)
)
%
8
)
decrypted_data
+=
des
.
decrypt
(
enc_block
)
j
+=
7
if
len
(
key
[
j
:
j
+
7
]
)
<
7
:
j
=
len
(
key
[
j
:
j
+
7
]
)
(
dec_data_len
,
)
=
unpack
(
"<L"
,
decrypted_data
[
:
4
]
)
return
decrypted_data
[
8
:
8
+
dec_data_len
]


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

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
:
file_handle
=
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


A factory for producing filter functions that filter based on a list of process IDs .

def create_pid_filter(cls, pid_list: List[int] = None) -> Callable[[interfaces.objects.ObjectInterface], bool]:
        """A factory for producing filter functions that filter based on a list
        of process IDs.

        Args:
            pid_list: A list of process IDs that are acceptable, all other processes will be filtered out

        Returns:
            Filter function for passing to the `list_processes` method
        """
        filter_func = lambda _: False
        # FIXME: mypy #4973 or #2608
        pid_list = pid_list or []
        filter_list = [x for x in pid_list if x is not None]
        if filter_list:
            filter_func = lambda x: x.UniqueProcessId not in filter_list
        return filter_func

def
create_pid_filter
(
cls
,
pid_list
:
List
[
int
]
=
)
->
Callable
[
[
interfaces
.
objects
.
ObjectInterface
]
,
bool
]
:
filter_func
=
lambda
_
:
False
# FIXME: mypy #4973 or #2608
pid_list
=
pid_list
or
[
]
filter_list
=
[
x
for
x
in
pid_list
if
x
is
not
]
if
filter_list
:
filter_func
=
lambda
x
:
x
.
UniqueProcessId
not
in
filter_list
return
filter_func


A factory for producing filter functions that filter based on a list of process names .

def create_name_filter(cls, name_list: List[str] = None) -> Callable[[interfaces.objects.ObjectInterface], bool]:
        """A factory for producing filter functions that filter based on a list
        of process names.

        Args:
            name_list: A list of process names that are acceptable, all other processes will be filtered out

        Returns:
            Filter function for passing to the `list_processes` method
        """
        filter_func = lambda _: False
        # FIXME: mypy #4973 or #2608
        name_list = name_list or []
        filter_list = [x for x in name_list if x is not None]
        if filter_list:
            filter_func = lambda x: utility.array_to_string(x.ImageFileName) not in filter_list
        return filter_func

def
create_name_filter
(
cls
,
name_list
:
List
[
str
]
=
)
->
Callable
[
[
interfaces
.
objects
.
ObjectInterface
]
,
bool
]
:
filter_func
=
lambda
_
:
False
# FIXME: mypy #4973 or #2608
name_list
=
name_list
or
[
]
filter_list
=
[
x
for
x
in
name_list
if
x
is
not
]
if
filter_list
:
filter_func
=
lambda
x
:
utility
.
array_to_string
(
x
.
ImageFileName
)
not
in
filter_list
return
filter_func


Lists all the processes in the primary layer that are in the pid config option .

def list_processes(cls,
                       context: interfaces.context.ContextInterface,
                       layer_name: str,
                       symbol_table: str,
                       filter_func: Callable[[interfaces.objects.ObjectInterface], bool] = lambda _: False) -> \
            Iterable[interfaces.objects.ObjectInterface]:
        """Lists all the processes in the primary layer that are in the pid
        config option.

        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
            filter_func: A function which takes an EPROCESS object and returns True if the process should be ignored/filtered

        Returns:
            The list of EPROCESS objects from the `layer_name` layer's PsActiveProcessHead list after filtering
        """

        # We only use the object factory to demonstrate how to use one
        kvo = context.layers[layer_name].config['kernel_virtual_offset']
        ntkrnlmp = context.module(symbol_table, layer_name = layer_name, offset = kvo)

        ps_aph_offset = ntkrnlmp.get_symbol("PsActiveProcessHead").address
        list_entry = ntkrnlmp.object(object_type = "_LIST_ENTRY", offset = ps_aph_offset)

        # This is example code to demonstrate how to use symbol_space directly, rather than through a module:
        #
        # ```
        # reloff = self.context.symbol_space.get_type(
        #          self.config['nt_symbols'] + constants.BANG + "_EPROCESS").relative_child_offset(
        #          "ActiveProcessLinks")
        # ```
        #
        # Note: "nt_symbols!_EPROCESS" could have been used, but would rely on the "nt_symbols" symbol table not already
        # having been present.  Strictly, the value of the requirement should be joined with the BANG character
        # defined in the constants file
        reloff = ntkrnlmp.get_type("_EPROCESS").relative_child_offset("ActiveProcessLinks")
        eproc = ntkrnlmp.object(object_type = "_EPROCESS", offset = list_entry.vol.offset - reloff, absolute = True)

        for proc in eproc.ActiveProcessLinks:
            if not filter_func(proc):
                yield proc


Returns the big page pool objects from the kernel PoolBigPageTable array .

def list_big_pools(cls,
                       context: interfaces.context.ContextInterface,
                       layer_name: str,
                       symbol_table: str,
                       tags: Optional[list] = None):
        """Returns the big page pool objects from the kernel PoolBigPageTable array.

        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
            tags: An optional list of pool tags to filter big page pool tags by

        Yields:
            A big page pool object
        """
        kvo = context.layers[layer_name].config['kernel_virtual_offset']
        ntkrnlmp = context.module(symbol_table, layer_name = layer_name, offset = kvo)

        big_page_table_offset = ntkrnlmp.get_symbol("PoolBigPageTable").address
        big_page_table = ntkrnlmp.object(object_type = "unsigned long long", offset = big_page_table_offset)

        big_page_table_size_offset = ntkrnlmp.get_symbol("PoolBigPageTableSize").address
        big_page_table_size = ntkrnlmp.object(object_type = "unsigned long", offset = big_page_table_size_offset)

        try:
            big_page_table_type = ntkrnlmp.get_type("_POOL_TRACKER_BIG_PAGES")
        except exceptions.SymbolError:
            # We have to manually load a symbol table
            is_vista_or_later = versions.is_vista_or_later(context, symbol_table)
            is_win10 = versions.is_win10(context, symbol_table)
            if is_win10:
                big_pools_json_filename = "bigpools-win10"
            elif is_vista_or_later:
                big_pools_json_filename = "bigpools-vista"
            else:
                big_pools_json_filename = "bigpools"

            if symbols.symbol_table_is_64bit(context, symbol_table):
                big_pools_json_filename += "-x64"
            else:
                big_pools_json_filename += "-x86"

            new_table_name = intermed.IntermediateSymbolTable.create(
                context = context,
                config_path = configuration.path_join(context.symbol_space[symbol_table].config_path, "bigpools"),
                sub_path = "windows",
                filename = big_pools_json_filename,
                table_mapping = {'nt_symbols': symbol_table},
                class_types = {'_POOL_TRACKER_BIG_PAGES': extensions.pool.POOL_TRACKER_BIG_PAGES})
            module = context.module(new_table_name, layer_name, offset = 0)
            big_page_table_type = module.get_type("_POOL_TRACKER_BIG_PAGES")

        big_pools = ntkrnlmp.object(object_type = "array",
                                    offset = big_page_table,
                                    subtype = big_page_table_type,
                                    count = big_page_table_size,
                                    absolute = True)

        for big_pool in big_pools:
            if big_pool.is_valid():
                if tags is None or big_pool.get_key() in tags:
                    yield big_pool


Get File and Product version information from PE files .

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 TypeError("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

def
get_version_information
(
cls
,
context
:
interfaces
.
context
.
ContextInterface
,
pe_table_name
:
str
,
layer_name
:
str
,
base_address
:
int
)
->
Tuple
[
int
,
int
,
int
,
int
]
:
if
layer_name
is
:
raise
TypeError
(
"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


Generates a list of PE file version info for processes dlls and modules .

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)
            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))


Creates a symbol table for a set of callbacks .

def create_callback_table(context: interfaces.context.ContextInterface, symbol_table: str, config_path: str) -> str:
        """Creates a symbol table for a set of callbacks.

        Args:
            context: The context to retrieve required elements (layers, symbol tables) from
            symbol_table: The name of an existing symbol table containing the kernel symbols
            config_path: The configuration path within the context of the symbol table to create

        Returns:
            The name of the constructed callback table
        """
        native_types = context.symbol_space[symbol_table].natives
        is_64bit = symbols.symbol_table_is_64bit(context, symbol_table)
        table_mapping = {"nt_symbols": symbol_table}

        if is_64bit:
            symbol_filename = "callbacks-x64"
        else:
            symbol_filename = "callbacks-x86"

        return intermed.IntermediateSymbolTable.create(context,
                                                       config_path,
                                                       "windows",
                                                       symbol_filename,
                                                       native_types = native_types,
                                                       table_mapping = table_mapping)

def create_callback_table ( context : interfaces . context . ContextInterface , symbol_table : str , config_path : str ) -> str : native_types = context . symbol_space [ symbol_table ] . natives is_64bit = symbols . symbol_table_is_64bit ( context , symbol_table ) table_mapping = { "nt_symbols" : symbol_table } if is_64bit : symbol_filename = "callbacks-x64" else : symbol_filename = "callbacks-x86" return intermed . IntermediateSymbolTable . create ( context , config_path , "windows" , symbol_filename , native_types = native_types , table_mapping = table_mapping )


Lists all kernel notification routines .

def list_notify_routines(cls, context: interfaces.context.ContextInterface, layer_name: str, symbol_table: str,
                             callback_table_name: str) -> Iterable[Tuple[str, int, Optional[str]]]:
        """Lists all kernel notification routines.

        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)

        is_vista_or_later = versions.is_vista_or_later(context = context, symbol_table = symbol_table)
        full_type_name = callback_table_name + constants.BANG + "_GENERIC_CALLBACK"

        symbol_names = [("PspLoadImageNotifyRoutine", False), ("PspCreateThreadNotifyRoutine", True),
                        ("PspCreateProcessNotifyRoutine", True)]

        for symbol_name, extended_list in symbol_names:

            try:
                symbol_offset = ntkrnlmp.get_symbol(symbol_name).address
            except exceptions.SymbolError:
                vollog.debug("Cannot find {}".format(symbol_name))
                continue

            if is_vista_or_later and extended_list:
                count = 64
            else:
                count = 8

            fast_refs = ntkrnlmp.object(object_type = "array",
                                        offset = symbol_offset,
                                        subtype = ntkrnlmp.get_type("_EX_FAST_REF"),
                                        count = count)

            for fast_ref in fast_refs:
                try:
                    callback = fast_ref.dereference().cast(full_type_name)
                except exceptions.InvalidAddressException:
                    continue

                if callback.Callback != 0:
                    yield symbol_name, callback.Callback, None

def
list_notify_routines
(
cls
,
context
:
interfaces
.
context
.
ContextInterface
,
layer_name
:
str
,
symbol_table
:
str
,
callback_table_name
:
str
)
->
Iterable
[
Tuple
[
str
,
int
,
Optional
[
str
]
]
]
:
kvo
=
context
.
layers
[
layer_name
]
.
config
[
'kernel_virtual_offset'
]
ntkrnlmp
=
context
.
module
(
symbol_table
,
layer_name
=
layer_name
,
offset
=
kvo
)
is_vista_or_later
=
versions
.
is_vista_or_later
(
context
=
context
,
symbol_table
=
symbol_table
)
full_type_name
=
callback_table_name
+
constants
.
BANG
+
"_GENERIC_CALLBACK"
symbol_names
=
[
(
"PspLoadImageNotifyRoutine"
,
False
)
,
(
"PspCreateThreadNotifyRoutine"
,
True
)
,
(
"PspCreateProcessNotifyRoutine"
,
True
)
]
for
symbol_name
,
extended_list
in
symbol_names
:
try
:
symbol_offset
=
ntkrnlmp
.
get_symbol
(
symbol_name
)
.
address
except
exceptions
.
SymbolError
:
vollog
.
debug
(
"Cannot find {}"
.
format
(
symbol_name
)
)
continue
if
is_vista_or_later
and
extended_list
:
count
=
64
else
:
count
=
8
fast_refs
=
ntkrnlmp
.
object
(
object_type
=
"array"
,
offset
=
symbol_offset
,
subtype
=
ntkrnlmp
.
get_type
(
"_EX_FAST_REF"
)
,
count
=
count
)
for
fast_ref
in
fast_refs
:
try
:
callback
=
fast_ref
.
dereference
(
)
.
cast
(
full_type_name
)
except
exceptions
.
InvalidAddressException
:
continue
if
callback
.
Callback
!=
0
:
yield
symbol_name
,
callback
.
Callback
,