def list_registry_callbacks(cls, context: interfaces.context.ContextInterface, layer_name: str, symbol_table: str,
                                callback_table_name: str) -> Iterable[Tuple[str, int, None]]:
        """Lists all registry callbacks.

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

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

        kvo = context.layers[layer_name].config['kernel_virtual_offset']
        ntkrnlmp = context.module(symbol_table, layer_name = layer_name, offset = kvo)
        full_type_name = callback_table_name + constants.BANG + "_EX_CALLBACK_ROUTINE_BLOCK"

        try:
            symbol_offset = ntkrnlmp.get_symbol("CmpCallBackVector").address
            symbol_count_offset = ntkrnlmp.get_symbol("CmpCallBackCount").address
        except exceptions.SymbolError:
            vollog.debug("Cannot find CmpCallBackVector or CmpCallBackCount")
            return

        callback_count = ntkrnlmp.object(object_type = "unsigned int", offset = symbol_count_offset)

        if callback_count == 0:
            return

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

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

            if callback.Function != 0:
                yield "CmRegisterCallback", callback.Function, None


Lists all kernel bugcheck reason callbacks .

def list_bugcheck_reason_callbacks(cls, context: interfaces.context.ContextInterface, layer_name: str,
                                       symbol_table: str, callback_table_name: str) -> Iterable[Tuple[str, int, str]]:
        """Lists all kernel bugcheck reason callbacks.

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

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

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

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

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

        for callback in callback_record.Entry:
            if not context.layers[layer_name].is_valid(callback.CallbackRoutine, 64):
                continue

            try:
                component = ntkrnlmp.object(
                    "string", absolute = True, offset = callback.Component, max_length = 64, errors = "replace"
                )  # type: Union[interfaces.renderers.BaseAbsentValue, interfaces.objects.ObjectInterface]
            except exceptions.InvalidAddressException:
                component = renderers.UnreadableValue()

            yield "KeBugCheckReasonCallbackListHead", callback.CallbackRoutine, component


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

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

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

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

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

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

        for callback in callback_record.Entry:

            if not context.layers[layer_name].is_valid(callback.CallbackRoutine, 64):
                continue

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

            yield "KeBugCheckCallbackListHead", callback.CallbackRoutine, component


List the dependencies of a given layer .

def get_depends(cls,
                    context: interfaces.context.ContextInterface,
                    layer_name: str,
                    index: int = 0) -> Iterable[Tuple[int, interfaces.layers.DataLayerInterface]]:
        """List the dependencies of a given layer.

        Args:
            context: The context to retrieve required layers from
            layer_name: the name of the starting layer
            index: the index/order of the layer

        Returns:
            An iterable containing the levels and layer objects for all dependent layers
        """
        layer = context.layers[layer_name]
        yield index, layer
        try:
            for depends in layer.dependencies:
                for j, dep in cls.get_depends(context, depends, index + 1):
                    yield j, context.layers[dep.name]
        except AttributeError:
            # FileLayer won't have dependencies
            pass

def
get_depends
(
cls
,
context
:
interfaces
.
context
.
ContextInterface
,
layer_name
:
str
,
index
:
int
=
0
)
->
Iterable
[
Tuple
[
int
,
interfaces
.
layers
.
DataLayerInterface
]
]
:
layer
=
context
.
layers
[
layer_name
]
yield
index
,
layer
try
:
for
depends
in
layer
.
dependencies
:
for
j
,
dep
in
cls
.
get_depends
(
context
,
depends
,
index
+
1
)
:
yield
j
,
context
.
layers
[
dep
.
name
]
except
AttributeError
:
# FileLayer won't have dependencies
pass


def get_kernel_module(cls, context: interfaces.context.ContextInterface, layer_name: str, symbol_table: str):
        """Returns the kernel module based on the layer and symbol_table"""
        virtual_layer = context.layers[layer_name]
        if not isinstance(virtual_layer, layers.intel.Intel):
            raise TypeError("Virtual Layer is not an intel layer")

        kvo = virtual_layer.config["kernel_virtual_offset"]

        ntkrnlmp = context.module(symbol_table, layer_name = layer_name, offset = kvo)
        return ntkrnlmp

def
get_kernel_module
(
cls
,
context
:
interfaces
.
context
.
ContextInterface
,
layer_name
:
str
,
symbol_table
:
str
)
:
virtual_layer
=
context
.
layers
[
layer_name
]
if
not
isinstance
(
virtual_layer
,
layers
.
intel
.
Intel
)
:
raise
TypeError
(
"Virtual Layer is not an intel layer"
)
kvo
=
virtual_layer
.
config
[
"kernel_virtual_offset"
]
ntkrnlmp
=
context
.
module
(
symbol_table
,
layer_name
=
layer_name
,
offset
=
kvo
)
return
ntkrnlmp


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

        native_types = context.symbol_space[symbol_table].natives

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

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

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

        return kdbg

def get_kdbg_structure ( cls , context : interfaces . context . ContextInterface , config_path : str , layer_name : str , symbol_table : str ) -> interfaces . objects . ObjectInterface : ntkrnlmp = cls . get_kernel_module ( context , layer_name , symbol_table ) native_types = context . symbol_space [ symbol_table ] . natives kdbg_offset = ntkrnlmp . get_symbol ( "KdDebuggerDataBlock" ) . address kdbg_table_name = intermed . IntermediateSymbolTable . create ( context , interfaces . configuration . path_join ( config_path , 'kdbg' ) , "windows" , "kdbg" , native_types = native_types , class_types = extensions . kdbg . class_types ) kdbg = context . object ( kdbg_table_name + constants . BANG + "_KDDEBUGGER_DATA64" , offset = ntkrnlmp . offset + kdbg_offset , layer_name = layer_name ) return kdbg


def get_kuser_structure(cls, context: interfaces.context.ContextInterface, layer_name: str,
                            symbol_table: str) -> interfaces.objects.ObjectInterface:
        """Returns the _KUSER_SHARED_DATA structure for a kernel"""
        virtual_layer = context.layers[layer_name]
        if not isinstance(virtual_layer, layers.intel.Intel):
            raise TypeError("Virtual Layer is not an intel layer")

        ntkrnlmp = cls.get_kernel_module(context, layer_name, symbol_table)

        # this is a hard-coded address in the Windows OS
        if virtual_layer.bits_per_register == 32:
            kuser_addr = 0xFFDF0000
        else:
            kuser_addr = 0xFFFFF78000000000

        kuser = ntkrnlmp.object(object_type = "_KUSER_SHARED_DATA",
                                layer_name = layer_name,
                                offset = kuser_addr,
                                absolute = True)

        return kuser


def get_version_structure(cls, context: interfaces.context.ContextInterface, layer_name: str,
                              symbol_table: str) -> interfaces.objects.ObjectInterface:
        """Returns the KdVersionBlock information from a kernel"""
        ntkrnlmp = cls.get_kernel_module(context, layer_name, symbol_table)

        vers_offset = ntkrnlmp.get_symbol("KdVersionBlock").address

        vers = ntkrnlmp.object(object_type = "_DBGKD_GET_VERSION64", layer_name = layer_name, offset = vers_offset)

        return vers

def get_version_structure ( cls , context : interfaces . context . ContextInterface , layer_name : str , symbol_table : str ) -> interfaces . objects . ObjectInterface : ntkrnlmp = cls . get_kernel_module ( context , layer_name , symbol_table ) vers_offset = ntkrnlmp . get_symbol ( "KdVersionBlock" ) . address vers = ntkrnlmp . object ( object_type = "_DBGKD_GET_VERSION64" , layer_name = layer_name , offset = vers_offset ) return vers


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

        kvo = virtual_layer.config["kernel_virtual_offset"]

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

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

        nt_header = dos_header.get_nt_header()

        return nt_header

def
get_ntheader_structure
(
cls
,
context
:
interfaces
.
context
.
ContextInterface
,
config_path
:
str
,
layer_name
:
str
)
->
interfaces
.
objects
.
ObjectInterface
:
virtual_layer
=
context
.
layers
[
layer_name
]
if
not
isinstance
(
virtual_layer
,
layers
.
intel
.
Intel
)
:
raise
TypeError
(
"Virtual Layer is not an intel layer"
)
kvo
=
virtual_layer
.
config
[
"kernel_virtual_offset"
]
pe_table_name
=
intermed
.
IntermediateSymbolTable
.
create
(
context
,
interfaces
.
configuration
.
path_join
(
config_path
,
'pe'
)
,
"windows"
,
"pe"
,
class_types
=
extensions
.
pe
.
class_types
)
dos_header
=
context
.
object
(
pe_table_name
+
constants
.
BANG
+
"_IMAGE_DOS_HEADER"
,
offset
=
kvo
,
layer_name
=
layer_name
)
nt_header
=
dos_header
.
get_nt_header
(
)
return
nt_header


Scans for links using the poolscanner module and constraints .

def scan_symlinks(cls,
                      context: interfaces.context.ContextInterface,
                      layer_name: str,
                      symbol_table: str) -> \
            Iterable[interfaces.objects.ObjectInterface]:
        """Scans for links 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 symlink objects found by scanning memory for the Symlink pool signatures
        """

        constraints = poolscanner.PoolScanner.builtin_constraints(symbol_table, [b'Sym\xe2', b'Symb'])

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

            _constraint, mem_object, _header = result
            yield mem_object

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


Creates a list of Pool Tag Constraints for network objects .

def create_netscan_constraints(context: interfaces.context.ContextInterface,
                                   symbol_table: str) -> List[poolscanner.PoolConstraint]:
        """Creates a list of Pool Tag Constraints for network objects.

        Args:
            context: The context to retrieve required elements (layers, symbol tables) from
            symbol_table: The name of an existing symbol table containing the symbols / types

        Returns:
            The list containing the built constraints.
        """

        tcpl_size = context.symbol_space.get_type(symbol_table + constants.BANG + "_TCP_LISTENER").size
        tcpe_size = context.symbol_space.get_type(symbol_table + constants.BANG + "_TCP_ENDPOINT").size
        udpa_size = context.symbol_space.get_type(symbol_table + constants.BANG + "_UDP_ENDPOINT").size

        # ~ vollog.debug("Using pool size constraints: TcpL {}, TcpE {}, UdpA {}".format(tcpl_size, tcpe_size, udpa_size))

        return [
            # TCP listener
            poolscanner.PoolConstraint(b'TcpL',
                                       type_name = symbol_table + constants.BANG + "_TCP_LISTENER",
                                       size = (tcpl_size, None),
                                       page_type = poolscanner.PoolType.NONPAGED | poolscanner.PoolType.FREE),
            # TCP Endpoint
            poolscanner.PoolConstraint(b'TcpE',
                                       type_name = symbol_table + constants.BANG + "_TCP_ENDPOINT",
                                       size = (tcpe_size, None),
                                       page_type = poolscanner.PoolType.NONPAGED | poolscanner.PoolType.FREE),
            # UDP Endpoint
            poolscanner.PoolConstraint(b'UdpA',
                                       type_name = symbol_table + constants.BANG + "_UDP_ENDPOINT",
                                       size = (udpa_size, None),
                                       page_type = poolscanner.PoolType.NONPAGED | poolscanner.PoolType.FREE)
        ]


Tries to determine which symbol filename to use for the image s tcpip driver . The logic is partially taken from the info plugin .

def determine_tcpip_version(cls, context: interfaces.context.ContextInterface, layer_name: str,
                                nt_symbol_table: str) -> str:
        """Tries to determine which symbol filename to use for the image's tcpip driver. The logic is partially taken from the info plugin.

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

        Returns:
            The filename of the symbol table to use.
        """

        # while the failsafe way to determine the version of tcpip.sys would be to
        # extract the driver and parse its PE header containing the versionstring,
        # unfortunately that header is not guaranteed to persist within memory.
        # therefore we determine the version based on the kernel version as testing
        # with several windows versions has showed this to work out correctly.

        is_64bit = symbols.symbol_table_is_64bit(context, nt_symbol_table)

        if is_64bit:
            arch = "x64"
        else:
            arch = "x86"

        vers = info.Info.get_version_structure(context, layer_name, nt_symbol_table)

        kuser = info.Info.get_kuser_structure(context, layer_name, nt_symbol_table)

        try:
            vers_minor_version = int(vers.MinorVersion)
            nt_major_version = int(kuser.NtMajorVersion)
            nt_minor_version = int(kuser.NtMinorVersion)
        except ValueError:
            # vers struct exists, but is not an int anymore?
            raise NotImplementedError("Kernel Debug Structure version format not supported!")
        except:
            # unsure what to raise here. Also, it might be useful to add some kind of fallback,
            # either to a user-provided version or to another method to determine tcpip.sys's version
            raise exceptions.VolatilityException(
                "Kernel Debug Structure missing VERSION/KUSER structure, unable to determine Windows version!")

        vollog.debug("Determined OS Version: {}.{} {}.{}".format(kuser.NtMajorVersion, kuser.NtMinorVersion,
                                                                 vers.MajorVersion, vers.MinorVersion))

        if nt_major_version == 10 and arch == "x64":
            # win10 x64 has an additional class type we have to include.
            class_types = network.win10_x64_class_types
        else:
            # default to general class types
            class_types = network.class_types

        # these versions are listed explicitly because symbol files differ based on
        # version *and* architecture. this is currently the clearest way to show
        # the differences, even if it introduces a fair bit of redundancy.
        # furthermore, it is easy to append new versions.
        if arch == "x86":
            version_dict = {
                (6, 0, 6000): "netscan-vista-x86",
                (6, 0, 6001): "netscan-vista-x86",
                (6, 0, 6002): "netscan-vista-x86",
                (6, 0, 6003): "netscan-vista-x86",
                (6, 1, 7600): "netscan-win7-x86",
                (6, 1, 7601): "netscan-win7-x86",
                (6, 1, 8400): "netscan-win7-x86",
                (6, 2, 9200): "netscan-win8-x86",
                (6, 3, 9600): "netscan-win81-x86",
                (10, 0, 10240): "netscan-win10-x86",
                (10, 0, 10586): "netscan-win10-x86",
                (10, 0, 14393): "netscan-win10-14393-x86",
                (10, 0, 15063): "netscan-win10-15063-x86",
                (10, 0, 16299): "netscan-win10-15063-x86",
                (10, 0, 17134): "netscan-win10-15063-x86",
                (10, 0, 17763): "netscan-win10-15063-x86",
                (10, 0, 18362): "netscan-win10-15063-x86",
                (10, 0, 18363): "netscan-win10-15063-x86"
            }
        else:
            version_dict = {
                (6, 0, 6000): "netscan-vista-x64",
                (6, 0, 6001): "netscan-vista-sp12-x64",
                (6, 0, 6002): "netscan-vista-sp12-x64",
                (6, 0, 6003): "netscan-vista-sp12-x64",
                (6, 1, 7600): "netscan-win7-x64",
                (6, 1, 7601): "netscan-win7-x64",
                (6, 1, 8400): "netscan-win7-x64",
                (6, 2, 9200): "netscan-win8-x64",
                (6, 3, 9600): "netscan-win81-x64",
                (10, 0, 10240): "netscan-win10-x64",
                (10, 0, 10586): "netscan-win10-x64",
                (10, 0, 14393): "netscan-win10-x64",
                (10, 0, 15063): "netscan-win10-15063-x64",
                (10, 0, 16299): "netscan-win10-15063-x64",
                (10, 0, 17134): "netscan-win10-15063-x64",
                (10, 0, 17763): "netscan-win10-15063-x64",
                (10, 0, 18362): "netscan-win10-15063-x64",
                (10, 0, 18363): "netscan-win10-15063-x64"
            }

        # when determining the symbol file we have to consider the following cases:
        # the determined version's symbol file is found by intermed.create -> proceed
        # the determined version's symbol file is not found by intermed -> intermed will throw an exc and abort
        # the determined version has no mapped symbol file -> if win10 use latest, otherwise throw exc
        # windows version cannot be determined -> throw exc
        filename = version_dict.get((nt_major_version, nt_minor_version, vers_minor_version))
        if not filename:
            if nt_major_version == 10:
                # NtMajorVersion of 10 without a match means a newer version than listed
                # hence try the latest supported version. If this one throws an error,
                # support has to be added manually.
                win_10_versions = sorted([key for key in list(version_dict.keys()) if key[0] == 10])
                # as win10 MinorVersion counts upwards we can take the last entry
                latest_version = win_10_versions[-1]
                filename = version_dict.get(latest_version)
                vollog.debug("Unable to find exact matching symbol file, going with latest: {}".format(filename))
            else:
                raise NotImplementedError("This version of Windows is not supported: {}.{} {}.{}!".format(
                    nt_major_version, nt_minor_version, vers.MajorVersion, vers_minor_version))

        vollog.debug("Determined symbol filename: {}".format(filename))

        return filename, class_types


Creates a symbol table for TCP Listeners and TCP / UDP Endpoints .

def create_netscan_symbol_table(cls, context: interfaces.context.ContextInterface, layer_name: str,
                                    nt_symbol_table: str, config_path: str) -> str:
        """Creates a symbol table for TCP Listeners and TCP/UDP Endpoints.

        Args:
            context: The context to retrieve required elements (layers, symbol tables) from
            layer_name: The name of the layer on which to operate
            nt_symbol_table: The name of the table containing the kernel symbols
            config_path: The config path where to find symbol files

        Returns:
            The name of the constructed symbol table
        """
        table_mapping = {"nt_symbols": nt_symbol_table}

        symbol_filename, class_types = cls.determine_tcpip_version(
            context,
            layer_name,
            nt_symbol_table,
        )

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

def create_netscan_symbol_table ( cls , context : interfaces . context . ContextInterface , layer_name : str , nt_symbol_table : str , config_path : str ) -> str : table_mapping = { "nt_symbols" : nt_symbol_table } symbol_filename , class_types = cls . determine_tcpip_version ( context , layer_name , nt_symbol_table , ) return intermed . IntermediateSymbolTable . create ( context , config_path , "windows" , symbol_filename , class_types = class_types , table_mapping = table_mapping )


Scans for network objects using the poolscanner module and constraints .

def scan(cls,
             context: interfaces.context.ContextInterface,
             layer_name: str,
             nt_symbol_table: str,
             netscan_symbol_table: str) -> \
            Iterable[interfaces.objects.ObjectInterface]:
        """Scans for network 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
            nt_symbol_table: The name of the table containing the kernel symbols
            netscan_symbol_table: The name of the table containing the network object symbols (_TCP_LISTENER etc.)

        Returns:
            A list of network objects found by scanning the `layer_name` layer for network pool signatures
        """

        constraints = cls.create_netscan_constraints(context, netscan_symbol_table)

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

            _constraint, mem_object, _header = result
            yield mem_object

def scan ( cls , context : interfaces . context . ContextInterface , layer_name : str , nt_symbol_table : str , netscan_symbol_table : str ) -> Iterable [ interfaces . objects . ObjectInterface ] : constraints = cls . create_netscan_constraints ( context , netscan_symbol_table ) for result in poolscanner . PoolScanner . generate_pool_scan ( context , layer_name , nt_symbol_table , constraints ) : _constraint , mem_object , _header = result yield mem_object


Generates the network objects for use in rendering .

def _generator(self, show_corrupt_results: Optional[bool] = None):
        """ Generates the network objects for use in rendering. """

        netscan_symbol_table = self.create_netscan_symbol_table(self.context, self.config["primary"],
                                                                self.config["nt_symbols"], self.config_path)

        for netw_obj in self.scan(self.context, self.config['primary'], self.config['nt_symbols'],
                                  netscan_symbol_table):

            vollog.debug("Found netw obj @ 0x{:2x} of assumed type {}".format(netw_obj.vol.offset, type(netw_obj)))
            # objects passed pool header constraints. check for additional constraints if strict flag is set.
            if not show_corrupt_results and not netw_obj.is_valid():
                continue

            if isinstance(netw_obj, network._UDP_ENDPOINT):
                vollog.debug("Found UDP_ENDPOINT @ 0x{:2x}".format(netw_obj.vol.offset))

                # For UdpA, the state is always blank and the remote end is asterisks
                for ver, laddr, _ in netw_obj.dual_stack_sockets():
                    yield (0, (format_hints.Hex(netw_obj.vol.offset), "UDP" + ver, laddr, netw_obj.Port, "*", 0, "",
                               netw_obj.get_owner_pid() or renderers.UnreadableValue(), netw_obj.get_owner_procname()
                               or renderers.UnreadableValue(), netw_obj.get_create_time()
                               or renderers.UnreadableValue()))

            elif isinstance(netw_obj, network._TCP_ENDPOINT):
                vollog.debug("Found _TCP_ENDPOINT @ 0x{:2x}".format(netw_obj.vol.offset))
                if netw_obj.get_address_family() == network.AF_INET:
                    proto = "TCPv4"
                elif netw_obj.get_address_family() == network.AF_INET6:
                    proto = "TCPv6"
                else:
                    proto = "TCPv?"

                try:
                    state = netw_obj.State.description
                except ValueError:
                    state = renderers.UnreadableValue()

                yield (0, (format_hints.Hex(netw_obj.vol.offset), proto, netw_obj.get_local_address()
                           or renderers.UnreadableValue(), netw_obj.LocalPort, netw_obj.get_remote_address()
                           or renderers.UnreadableValue(), netw_obj.RemotePort, state, netw_obj.get_owner_pid()
                           or renderers.UnreadableValue(), netw_obj.get_owner_procname() or renderers.UnreadableValue(),
                           netw_obj.get_create_time() or renderers.UnreadableValue()))

            # check for isinstance of tcp listener last, because all other objects are inherited from here
            elif isinstance(netw_obj, network._TCP_LISTENER):
                vollog.debug("Found _TCP_LISTENER @ 0x{:2x}".format(netw_obj.vol.offset))

                # For TcpL, the state is always listening and the remote port is zero
                for ver, laddr, raddr in netw_obj.dual_stack_sockets():
                    yield (0, (format_hints.Hex(netw_obj.vol.offset), "TCP" + ver, laddr, netw_obj.Port, raddr, 0,
                               "LISTENING", netw_obj.get_owner_pid() or renderers.UnreadableValue(),
                               netw_obj.get_owner_procname() or renderers.UnreadableValue(), netw_obj.get_create_time()
                               or renderers.UnreadableValue()))
            else:
                # this should not happen therefore we log it.
                vollog.debug("Found network object unsure of its type: {} of type {}".format(netw_obj, type(netw_obj)))


Scans for processes using the poolscanner module and constraints .

def scan_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]:
        """Scans for processes 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 processes found by scanning the `layer_name` layer for process pool signatures
        """

        constraints = poolscanner.PoolScanner.builtin_constraints(symbol_table, [b'Pro\xe3', b'Proc'])

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

            _constraint, mem_object, _header = result
            if not filter_func(mem_object):
                yield mem_object

def scan_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 ] : constraints = poolscanner . PoolScanner . builtin_constraints ( symbol_table , [ b'Pro\xe3' , b'Proc' ] ) for result in poolscanner . PoolScanner . generate_pool_scan ( context , layer_name , symbol_table , constraints ) : _constraint , mem_object , _header = result if not filter_func ( mem_object ) : yield mem_object


def virtual_process_from_physical(cls,
                                      context: interfaces.context.ContextInterface,
                                      layer_name: str,
                                      symbol_table: str,
                                      proc: interfaces.objects.ObjectInterface) -> \
            Iterable[interfaces.objects.ObjectInterface]:
        """ Returns a virtual process from a physical addressed one

        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
            proc: the process object with phisical address

        Returns:
            A process object on virtual address layer

        """

        # We'll use the first thread to bounce back to the virtual process
        kvo = context.layers[layer_name].config['kernel_virtual_offset']
        ntkrnlmp = context.module(symbol_table, layer_name = layer_name, offset = kvo)

        tleoffset = ntkrnlmp.get_type("_ETHREAD").relative_child_offset("ThreadListEntry")
        # Start out with the member offset
        offsets = [tleoffset]

        # If (and only if) we're dealing with 64-bit Windows 7 SP1
        # then add the other commonly seen member offset to the list
        kuser = info.Info.get_kuser_structure(context, layer_name, symbol_table)
        nt_major_version = int(kuser.NtMajorVersion)
        nt_minor_version = int(kuser.NtMinorVersion)
        vers = info.Info.get_version_structure(context, layer_name, symbol_table)
        build = vers.MinorVersion
        bits = context.layers[layer_name].bits_per_register
        version = (nt_major_version, nt_minor_version, build)
        if version == (6, 1, 7601) and bits == 64:
            offsets.append(tleoffset + 8)

        # Now we can try to bounce back
        for ofs in offsets:
            ethread = ntkrnlmp.object(object_type = "_ETHREAD",
                                      offset = proc.ThreadListHead.Flink - ofs,
                                      absolute = True)

            # Ask for the thread's process to get an _EPROCESS with a virtual address layer
            virtual_process = ethread.owning_process()
            # Sanity check the bounce.
            # This compares the original offset with the new one (translated from virtual layer)
            (_, _, ph_offset, _, _) = list(context.layers[layer_name].mapping(offset = virtual_process.vol.offset,
                                                                              length = 0))[0]
            if virtual_process and \
                    proc.vol.offset == ph_offset:
                return virtual_process


def _generator(self) -> Generator[Tuple, None, None]:
        """Generates results from a strings file."""
        revmap = self.generate_mapping(self.config['primary'])

        accessor = resources.ResourceAccessor()
        strings_fp = accessor.open(self.config['strings_file'], "rb")
        strings_size = path.getsize(strings_fp.file.name)

        line = strings_fp.readline()
        last_prog = 0
        while line:
            try:
                offset, string = self._parse_line(line)
                try:
                    revmap_list = [name + ":" + hex(offset) for (name, offset) in revmap[offset >> 12]]
                except (IndexError, KeyError):
                    revmap_list = ["FREE MEMORY"]
                yield (0, (str(string, 'latin-1'), format_hints.Hex(offset), ", ".join(revmap_list)))
            except ValueError:
                vollog.error("Strings file is in the wrong format")
                return
            line = strings_fp.readline()
            prog = strings_fp.tell() / strings_size * 100
            if round(prog, 1) > last_prog:
                last_prog = round(prog, 1)
                self._progress_callback(prog, "Matching strings in memory")

def
_generator
(
self
)
->
Generator
[
Tuple
,
,
]
:
revmap
=
self
.
generate_mapping
(
self
.
config
[
'primary'
]
)
accessor
=
resources
.
ResourceAccessor
(
)
strings_fp
=
accessor
.
open
(
self
.
config
[
'strings_file'
]
,
"rb"
)
strings_size
=
path
.
getsize
(
strings_fp
.
file
.
name
)
line
=
strings_fp
.
readline
(
)
last_prog
=
0
while
line
:
try
:
offset
,
string
=
self
.
_parse_line
(
line
)
try
:
revmap_list
=
[
name
+
":"
+
hex
(
offset
)
for
(
name
,
offset
)
in
revmap
[
offset
>>
12
]
]
except
(
IndexError
,
KeyError
)
:
revmap_list
=
[
"FREE MEMORY"
]
yield
(
0
,
(
str
(
string
,
'latin-1'
)
,
format_hints
.
Hex
(
offset
)
,
", "
.
join
(
revmap_list
)
)
)
except
ValueError
:
vollog
.
error
(
"Strings file is in the wrong format"
)
return
line
=
strings_fp
.
readline
(
)
prog
=
strings_fp
.
tell
(
)
/
strings_size
*
100
if
round
(
prog
,
1
)
>
last_prog
:
last_prog
=
round
(
prog
,
1
)
self
.
_progress_callback
(
prog
,
"Matching strings in memory"
)


Parses a single line from a strings file .

def _parse_line(self, line: bytes) -> Tuple[int, bytes]:
        """Parses a single line from a strings file.

        Args:
            line: bytes of the line of a strings file (an offset and a string)

        Returns:
            Tuple of the offset and the string found at that offset
        """

        match = self.strings_pattern.search(line)
        if not match:
            raise ValueError("Strings file contains invalid strings line")
        offset, string = match.group(1, 2)
        return int(offset), string


Creates a reverse mapping between virtual addresses and physical addresses .

def generate_mapping(self, layer_name: str) -> Dict[int, Set[Tuple[str, int]]]:
        """Creates a reverse mapping between virtual addresses and physical
        addresses.

        Args:
            layer_name: the layer to map against the string lines

        Returns:
            A mapping of virtual offsets to strings and physical offsets
        """
        layer = self._context.layers[layer_name]
        reverse_map = dict()  # type: Dict[int, Set[Tuple[str, int]]]
        if isinstance(layer, intel.Intel):
            # We don't care about errors, we just wanted chunks that map correctly
            for mapval in layer.mapping(0x0, layer.maximum_address, ignore_errors = True):
                offset, _, mapped_offset, mapped_size, maplayer = mapval
                for val in range(mapped_offset, mapped_offset + mapped_size, 0x1000):
                    cur_set = reverse_map.get(mapped_offset >> 12, set())
                    cur_set.add(("kernel", offset))
                    reverse_map[mapped_offset >> 12] = cur_set
                self._progress_callback((offset * 100) / layer.maximum_address, "Creating reverse kernel map")

            # TODO: Include kernel modules

            for process in pslist.PsList.list_processes(self.context, self.config['primary'],
                                                        self.config['nt_symbols']):
                proc_id = "Unknown"
                try:
                    proc_id = process.UniqueProcessId
                    proc_layer_name = process.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

                proc_layer = self.context.layers[proc_layer_name]
                if isinstance(proc_layer, linear.LinearlyMappedLayer):
                    for mapval in proc_layer.mapping(0x0, proc_layer.maximum_address, ignore_errors = True):
                        mapped_offset, _, offset, mapped_size, maplayer = mapval
                        for val in range(mapped_offset, mapped_offset + mapped_size, 0x1000):
                            cur_set = reverse_map.get(mapped_offset >> 12, set())
                            cur_set.add(("Process {}".format(process.UniqueProcessId), offset))
                            reverse_map[mapped_offset >> 12] = cur_set
                        # FIXME: make the progress for all processes, rather than per-process
                        self._progress_callback((offset * 100) / layer.maximum_address,
                                                "Creating mapping for task {}".format(process.UniqueProcessId))

        return reverse_map


def sid_to_key(cls, sid: int) -> Tuple[bytes, bytes]:
        """Takes rid of a user and converts it to a key to be used by the DES cipher"""
        bytestr1 = [sid & 0xFF, (sid >> 8) & 0xFF, (sid >> 16) & 0xFF, (sid >> 24) & 0xFF]
        bytestr1 += bytestr1[0:3]
        bytestr2 = [bytestr1[3]] + bytestr1[0:3]
        bytestr2 += bytestr2[0:3]
        return cls.sidbytes_to_key(bytes(bytestr1)), cls.sidbytes_to_key(bytes(bytestr2))

def sid_to_key ( cls , sid : int ) -> Tuple [ bytes , bytes ] : bytestr1 = [ sid & 0xFF , ( sid >> 8 ) & 0xFF , ( sid >> 16 ) & 0xFF , ( sid >> 24 ) & 0xFF ] bytestr1 += bytestr1 [ 0 : 3 ] bytestr2 = [ bytestr1 [ 3 ] ] + bytestr1 [ 0 : 3 ] bytestr2 += bytestr2 [ 0 : 3 ] return cls . sidbytes_to_key ( bytes ( bytestr1 ) ) , cls . sidbytes_to_key ( bytes ( bytestr2 ) )


def sidbytes_to_key(cls, s: bytes) -> bytes:
        """Builds final DES key from the strings generated in sid_to_key"""
        key = []
        key.append(s[0] >> 1)
        key.append(((s[0] & 0x01) << 6) | (s[1] >> 2))
        key.append(((s[1] & 0x03) << 5) | (s[2] >> 3))
        key.append(((s[2] & 0x07) << 4) | (s[3] >> 4))
        key.append(((s[3] & 0x0F) << 3) | (s[4] >> 5))
        key.append(((s[4] & 0x1F) << 2) | (s[5] >> 6))
        key.append(((s[5] & 0x3F) << 1) | (s[6] >> 7))
        key.append(s[6] & 0x7F)
        for i in range(8):
            key[i] = (key[i] << 1)
            key[i] = cls.odd_parity[key[i]]
        return bytes(key)


Enumerate persistent & common variables .

def _get_silent_vars(self) -> List[str]:
        """Enumerate persistent & common variables.

        This function collects the global (all users) and
        user-specific environment variables from the
        registry. Any variables in a process env block that
        does not exist in the persistent list was explicitly
        set with the SetEnvironmentVariable() API.
        """

        values = []

        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):
            sys = False
            ntuser = False

            ## The global variables
            try:
                key = hive.get_key('CurrentControlSet\\Control\\Session Manager\\Environment')
                sys = True
            except KeyError:
                try:
                    key = hive.get_key('ControlSet001\\Control\\Session Manager\\Environment')
                    sys = True
                except KeyError:
                    pass
            if sys:
                try:
                    for node in key.get_values():
                        try:
                            value_node_name = node.get_name()
                            if value_node_name:
                                values.append(value_node_name)
                        except (exceptions.InvalidAddressException, registry.RegistryFormatException) as excp:
                            vollog.log(
                                constants.LOGLEVEL_VVV,
                                "Error while parsing global environment variables keys (some keys might be excluded)")
                            continue
                except KeyError:
                    pass

            ## The user-specific variables
            try:
                key = hive.get_key('Environment')
                ntuser = True
            except KeyError:
                pass
            if ntuser:
                try:
                    for node in key.get_values():
                        try:
                            value_node_name = node.get_name()
                            if value_node_name:
                                values.append(value_node_name)
                        except (exceptions.InvalidAddressException, registry.RegistryFormatException) as excp:
                            vollog.log(
                                constants.LOGLEVEL_VVV,
                                "Error while parsing user environment variables keys (some keys might be excluded)")
                            continue
                except KeyError:
                    pass

            ## The volatile user variables
            try:
                key = hive.get_key('Volatile Environment')
            except KeyError:
                continue
            try:
                for node in key.get_values():
                    try:
                        value_node_name = node.get_name()
                        if value_node_name:
                            values.append(value_node_name)
                    except (exceptions.InvalidAddressException, registry.RegistryFormatException) as excp:
                        vollog.log(
                            constants.LOGLEVEL_VVV,
                            "Error while parsing volatile environment variables keys (some keys might be excluded)")
                        continue
            except KeyError:
                continue

        ## These are variables set explicitly but are
        ## common enough to ignore safely.
        values.extend([
            "ProgramFiles",
            "CommonProgramFiles",
            "SystemDrive",
            "SystemRoot",
            "ProgramData",
            "PUBLIC",
            "ALLUSERSPROFILE",
            "COMPUTERNAME",
            "SESSIONNAME",
            "USERNAME",
            "USERPROFILE",
            "PROMPT",
            "USERDOMAIN",
            "AppData",
            "CommonFiles",
            "CommonDesktop",
            "CommonProgramGroups",
            "CommonStartMenu",
            "CommonStartUp",
            "Cookies",
            "DesktopDirectory",
            "Favorites",
            "History",
            "NetHood",
            "PersonalDocuments",
            "RecycleBin",
            "StartMenu",
            "Templates",
            "AltStartup",
            "CommonFavorites",
            "ConnectionWizard",
            "DocAndSettingRoot",
            "InternetCache",
            "windir",
            "Path",
            "HOMEDRIVE",
            "PROCESSOR_ARCHITECTURE",
            "NUMBER_OF_PROCESSORS",
            "ProgramFiles(x86)",
            "CommonProgramFiles(x86)",
            "CommonProgramW6432",
            "PSModulePath",
            "PROCESSOR_IDENTIFIER",
            "FP_NO_HOST_CHECK",
            "LOCALAPPDATA",
            "TMP",
            "ProgramW6432",
        ])

        return values


Scans for drivers using the poolscanner module and constraints .

def scan_drivers(cls,
                     context: interfaces.context.ContextInterface,
                     layer_name: str,
                     symbol_table: str) -> \
            Iterable[interfaces.objects.ObjectInterface]:
        """Scans for drivers 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'Dri\xf6', b'Driv'])

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

            _constraint, mem_object, _header = result
            yield mem_object

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


Reads the raw data of a _CM_KEY_VALUE and returns a dict of userassist fields .

def parse_userassist_data(self, reg_val):
        """Reads the raw data of a _CM_KEY_VALUE and returns a dict of
        userassist fields."""

        item = {
            "id": renderers.UnparsableValue(),
            "count": renderers.UnparsableValue(),
            "focus": renderers.UnparsableValue(),
            "time": renderers.UnparsableValue(),
            "lastupdated": renderers.UnparsableValue(),
            "rawdata": renderers.UnparsableValue(),
        }

        userassist_data = reg_val.decode_data()

        if userassist_data is None:
            return item

        item["rawdata"] = userassist_data

        if self._win7 is None:
            # if OS is still unknown at this point, return the default item which just has the rawdata
            return item

        if len(userassist_data) < self._userassist_size:
            return item

        userassist_layer_name = self.context.layers.free_layer_name("userassist_buffer")
        buffer = BufferDataLayer(self.context, self._config_path, userassist_layer_name, userassist_data)
        self.context.add_layer(buffer)
        userassist_obj = self.context.object(
            object_type = self._reg_table_name + constants.BANG + self._userassist_type_name,
            layer_name = userassist_layer_name,
            offset = 0)

        if self._win7:
            item["id"] = renderers.NotApplicableValue()
            item["count"] = int(userassist_obj.Count)

            seconds = (userassist_obj.FocusTime + 500) / 1000.0
            time = datetime.timedelta(seconds = seconds) if seconds > 0 else userassist_obj.FocusTime
            item["focus"] = int(userassist_obj.FocusCount)
            item["time"] = str(time)

        else:
            item["id"] = int(userassist_obj.ID)
            item["count"] = int(userassist_obj.CountStartingAtFive
                                if userassist_obj.CountStartingAtFive < 5 else userassist_obj.CountStartingAtFive - 5)
            item["focus"] = renderers.NotApplicableValue()
            item["time"] = renderers.NotApplicableValue()

        item["lastupdated"] = conversion.wintime_to_datetime(userassist_obj.LastUpdated.QuadPart)

        return item


Determine the userassist type and size depending on the OS version .

def _determine_userassist_type(self) -> None:
        """Determine the userassist type and size depending on the OS
        version."""

        if self._win7 is True:
            self._userassist_type_name = "_VOL_USERASSIST_TYPES_7"
        elif self._win7 is False:
            self._userassist_type_name = "_VOL_USERASSIST_TYPES_XP"

        self._userassist_size = self.context.symbol_space.get_type(self._reg_table_name + constants.BANG +
                                                                   self._userassist_type_name).size

def _determine_userassist_type ( self ) -> None : if self . _win7 is True : self . _userassist_type_name = "_VOL_USERASSIST_TYPES_7" elif self . _win7 is False : self . _userassist_type_name = "_VOL_USERASSIST_TYPES_XP" self . _userassist_size = self . context . symbol_space . get_type ( self . _reg_table_name + constants . BANG + self . _userassist_type_name ) . size


Generate userassist data for a registry hive .

def list_userassist(self, hive: RegistryHive) -> Generator[Tuple[int, Tuple], None, None]:
        """Generate userassist data for a registry hive."""

        hive_name = hive.hive.cast(self.config["nt_symbols"] + constants.BANG + "_CMHIVE").get_name()

        if self._win7 is None:
            try:
                self._win7 = self._win7_or_later()
            except exceptions.SymbolError:
                # self._win7 will be None and only registry value rawdata will be output
                pass

        self._determine_userassist_type()

        userassist_node_path = hive.get_key("software\\microsoft\\windows\\currentversion\\explorer\\userassist",
                                            return_list = True)

        if not userassist_node_path:
            vollog.warning("list_userassist did not find a valid node_path (or None)")
            return

        if not isinstance(userassist_node_path, list):
            vollog.warning("userassist_node_path did not return a list as expected")
            return
        userassist_node = userassist_node_path[-1]
        # iterate through the GUIDs under the userassist key
        for guidkey in userassist_node.get_subkeys():
            # each guid key should have a Count key in it
            for countkey in guidkey.get_subkeys():
                countkey_path = countkey.get_key_path()
                countkey_last_write_time = conversion.wintime_to_datetime(countkey.LastWriteTime.QuadPart)

                # output the parent Count key
                result = (
                    0, (renderers.format_hints.Hex(hive.hive_offset), hive_name, countkey_path,
                        countkey_last_write_time, "Key", renderers.NotApplicableValue(), renderers.NotApplicableValue(),
                        renderers.NotApplicableValue(), renderers.NotApplicableValue(), renderers.NotApplicableValue(),
                        renderers.NotApplicableValue(), renderers.NotApplicableValue())
                )  # type: Tuple[int, Tuple[format_hints.Hex, Any, Any, Any, Any, Any, Any, Any, Any, Any, Any, Any]]
                yield result

                # output any subkeys under Count
                for subkey in countkey.get_subkeys():

                    subkey_name = subkey.get_name()
                    result = (1, (
                        renderers.format_hints.Hex(hive.hive_offset),
                        hive_name,
                        countkey_path,
                        countkey_last_write_time,
                        "Subkey",
                        subkey_name,
                        renderers.NotApplicableValue(),
                        renderers.NotApplicableValue(),
                        renderers.NotApplicableValue(),
                        renderers.NotApplicableValue(),
                        renderers.NotApplicableValue(),
                        renderers.NotApplicableValue(),
                    ))
                    yield result

                # output any values under Count
                for value in countkey.get_values():

                    value_name = value.get_name()
                    try:
                        value_name = codecs.encode(value_name, "rot_13")
                    except UnicodeDecodeError:
                        pass

                    if self._win7:
                        guid = value_name.split("\\")[0]
                        if guid in self._folder_guids:
                            value_name = value_name.replace(guid, self._folder_guids[guid])

                    userassist_data_dict = self.parse_userassist_data(value)
                    result = (1, (
                        renderers.format_hints.Hex(hive.hive_offset),
                        hive_name,
                        countkey_path,
                        countkey_last_write_time,
                        "Value",
                        value_name,
                        userassist_data_dict["id"],
                        userassist_data_dict["count"],
                        userassist_data_dict["focus"],
                        userassist_data_dict["time"],
                        userassist_data_dict["lastupdated"],
                        format_hints.HexBytes(userassist_data_dict["rawdata"]),
                    ))
                    yield result


Walks through a set of nodes from a given node ( last one in node_path ) . Avoids loops by not traversing into nodes already present in the node_path .

def key_iterator(
            cls,
            hive: RegistryHive,
            node_path: Sequence[objects.StructType] = None,
            recurse: bool = False
    ) -> Iterable[Tuple[int, bool, datetime.datetime, str, bool, interfaces.objects.ObjectInterface]]:
        """Walks through a set of nodes from a given node (last one in
        node_path). Avoids loops by not traversing into nodes already present
        in the node_path.

        Args:
            hive: The registry hive to walk
            node_path: The list of nodes that make up the
            recurse: Traverse down the node tree or stay only on the same level

        Yields:
            A tuple of results (depth, is_key, last write time, path, volatile, and the node).
        """
        if not node_path:
            node_path = [hive.get_node(hive.root_cell_offset)]
        if not isinstance(node_path, list) or len(node_path) < 1:
            vollog.warning("Hive walker was not passed a valid node_path (or None)")
            return
        node = node_path[-1]
        key_path_items = [hive] + node_path[1:]
        key_path = '\\'.join([k.get_name() for k in key_path_items])
        if node.vol.type_name.endswith(constants.BANG + '_CELL_DATA'):
            raise RegistryFormatException(hive.name, "Encountered _CELL_DATA instead of _CM_KEY_NODE")
        last_write_time = conversion.wintime_to_datetime(node.LastWriteTime.QuadPart)

        for key_node in node.get_subkeys():
            result = (len(node_path), True, last_write_time, key_path, key_node.get_volatile(), key_node)
            yield result

            if recurse:
                if key_node.vol.offset not in [x.vol.offset for x in node_path]:
                    try:
                        key_node.get_name()
                    except exceptions.InvalidAddressException as excp:
                        vollog.debug(excp)
                        continue

                    yield from cls.key_iterator(hive, node_path + [key_node], recurse = recurse)

        for value_node in node.get_values():
            result = (len(node_path), False, last_write_time, key_path, node.get_volatile(), value_node)
            yield result


Method that wraps the more generic key_iterator to provide output for printkey specifically .

def _printkey_iterator(self,
                           hive: RegistryHive,
                           node_path: Sequence[objects.StructType] = None,
                           recurse: bool = False):
        """Method that wraps the more generic key_iterator, to provide output
        for printkey specifically.

        Args:
            hive: The registry hive to walk
            node_path: The list of nodes that make up the
            recurse: Traverse down the node tree or stay only on the same level

        Yields:
            The depth, and a tuple of results (last write time, hive offset, type, path, name, data and volatile)
        """
        for depth, is_key, last_write_time, key_path, volatile, node in self.key_iterator(hive, node_path, recurse):
            if is_key:
                try:
                    key_node_name = node.get_name()
                except (exceptions.InvalidAddressException, RegistryFormatException) as excp:
                    vollog.debug(excp)
                    key_node_name = renderers.UnreadableValue()

                yield (depth, (last_write_time, renderers.format_hints.Hex(hive.hive_offset), "Key", key_path,
                               key_node_name, renderers.NotApplicableValue(), volatile))
            else:
                try:
                    value_node_name = node.get_name() or "(Default)"
                except (exceptions.InvalidAddressException, RegistryFormatException) as excp:
                    vollog.debug(excp)
                    value_node_name = renderers.UnreadableValue()

                try:
                    value_type = RegValueTypes.get(node.Type).name
                except (exceptions.InvalidAddressException, RegistryFormatException) as excp:
                    vollog.debug(excp)
                    value_type = renderers.UnreadableValue()

                if isinstance(value_type, renderers.UnreadableValue):
                    vollog.debug("Couldn't read registry value type, so data is unreadable")
                    value_data = renderers.UnreadableValue()  # type: Union[interfaces.renderers.BaseAbsentValue, bytes]
                else:
                    try:
                        value_data = node.decode_data()

                        if isinstance(value_data, int):
                            value_data = format_hints.MultiTypeData(value_data, encoding = 'utf-8')
                        elif RegValueTypes.get(node.Type) == RegValueTypes.REG_BINARY:
                            value_data = format_hints.MultiTypeData(value_data, show_hex = True)
                        elif RegValueTypes.get(node.Type) == 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')
                    except (ValueError, exceptions.InvalidAddressException, RegistryFormatException) as excp:
                        vollog.debug(excp)
                        value_data = renderers.UnreadableValue()

                result = (depth, (last_write_time, renderers.format_hints.Hex(hive.hive_offset), value_type, key_path,
                                  value_node_name, value_data, volatile))
                yield result


Scans for hives using the poolscanner module and constraints or bigpools module with tag .

def scan_hives(cls,
                   context: interfaces.context.ContextInterface,
                   layer_name: str,
                   symbol_table: str) -> \
            Iterable[interfaces.objects.ObjectInterface]:
        """Scans for hives using the poolscanner module and constraints or bigpools module with 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

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

        is_64bit = symbols.symbol_table_is_64bit(context, symbol_table)
        is_windows_8_1_or_later = versions.is_windows_8_1_or_later(context = context, symbol_table = symbol_table)

        if is_windows_8_1_or_later and is_64bit:
            kvo = context.layers[layer_name].config['kernel_virtual_offset']
            ntkrnlmp = context.module(symbol_table, layer_name = layer_name, offset = kvo)

            for pool in bigpools.BigPools.list_big_pools(context,
                                                         layer_name = layer_name,
                                                         symbol_table = symbol_table,
                                                         tags = ["CM10"]):
                cmhive = ntkrnlmp.object(object_type = "_CMHIVE", offset = pool.Va, absolute = True)
                yield cmhive

        else:
            constraints = poolscanner.PoolScanner.builtin_constraints(symbol_table, [b'CM10'])

            for result in poolscanner.PoolScanner.generate_pool_scan(context, layer_name, symbol_table, constraints):
                _constraint, mem_object, _header = result
                yield mem_object

def scan_hives ( cls , context : interfaces . context . ContextInterface , layer_name : str , symbol_table : str ) -> Iterable [ interfaces . objects . ObjectInterface ] : is_64bit = symbols . symbol_table_is_64bit ( context , symbol_table ) is_windows_8_1_or_later = versions . is_windows_8_1_or_later ( context = context , symbol_table = symbol_table ) if is_windows_8_1_or_later and is_64bit : kvo = context . layers [ layer_name ] . config [ 'kernel_virtual_offset' ] ntkrnlmp = context . module ( symbol_table , layer_name = layer_name , offset = kvo ) for pool in bigpools . BigPools . list_big_pools ( context , layer_name = layer_name , symbol_table = symbol_table , tags = [ "CM10" ] ) : cmhive = ntkrnlmp . object ( object_type = "_CMHIVE" , offset = pool . Va , absolute = True ) yield cmhive else : constraints = poolscanner . PoolScanner . builtin_constraints ( symbol_table , [ b'CM10' ] ) for result in poolscanner . PoolScanner . generate_pool_scan ( context , layer_name , symbol_table , constraints ) : _constraint , mem_object , _header = result yield mem_object


Walks through a registry hive by hive returning the constructed registry layer name .

def list_hives(cls,
                   context: interfaces.context.ContextInterface,
                   base_config_path: str,
                   layer_name: str,
                   symbol_table: str,
                   filter_string: Optional[str] = None,
                   hive_offsets: List[int] = None) -> Iterable[registry.RegistryHive]:
        """Walks through a registry, hive by hive returning the constructed
        registry layer name.

        Args:
            context: The context to retrieve required elements (layers, symbol tables) from
            base_config_path: The configuration path for any settings required by the new table
            layer_name: The name of the layer on which to operate
            symbol_table: The name of the table containing the kernel symbols
            filter_string: An optional string which must be present in the hive name if specified
            offset: An optional offset to specify a specific hive to iterate over (takes precedence over filter_string)

        Yields:
            A registry hive layer name
        """
        if hive_offsets is None:
            try:
                hive_offsets = [
                    hive.vol.offset for hive in cls.list_hive_objects(context, layer_name, symbol_table, filter_string)
                ]
            except ImportError:
                vollog.warning("Unable to import windows.hivelist plugin, please provide a hive offset")
                raise ValueError("Unable to import windows.hivelist plugin, please provide a hive offset")

        for hive_offset in hive_offsets:
            # Construct the hive
            reg_config_path = cls.make_subconfig(context = context,
                                                 base_config_path = base_config_path,
                                                 hive_offset = hive_offset,
                                                 base_layer = layer_name,
                                                 nt_symbols = symbol_table)

            try:
                hive = registry.RegistryHive(context, reg_config_path, name = 'hive' + hex(hive_offset))
            except exceptions.InvalidAddressException:
                vollog.warning("Couldn't create RegistryHive layer at offset {}, skipping".format(hex(hive_offset)))
                continue
            context.layers.add_layer(hive)
            yield hive


Lists all the hives in the primary layer .

def list_hive_objects(cls,
                          context: interfaces.context.ContextInterface,
                          layer_name: str,
                          symbol_table: str,
                          filter_string: str = None) -> Iterator[interfaces.objects.ObjectInterface]:
        """Lists all the hives 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
            filter_string: A string which must be present in the hive name if specified

        Returns:
            The list of registry hives from the `layer_name` layer as filtered against using the `filter_string`
        """

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

        list_head = ntkrnlmp.get_symbol("CmpHiveListHead").address
        list_entry = ntkrnlmp.object(object_type = "_LIST_ENTRY", offset = list_head)
        reloff = ntkrnlmp.get_type("_CMHIVE").relative_child_offset("HiveList")
        cmhive = ntkrnlmp.object(object_type = "_CMHIVE", offset = list_entry.vol.offset - reloff, absolute = True)

        # Run through the list forwards
        seen = set()

        hg = HiveGenerator(cmhive, forward = True)
        for hive in hg:
            if hive.vol.offset in seen:
                vollog.debug("Hivelist found an already seen offset {} while " \
                             "traversing forwards, this should not occur".format(hex(hive.vol.offset)))
                break
            seen.add(hive.vol.offset)
            if filter_string is None or filter_string.lower() in str(hive.get_name() or "").lower():
                if context.layers[layer_name].is_valid(hive.vol.offset):
                    yield hive

        forward_invalid = hg.invalid
        if forward_invalid:
            vollog.debug("Hivelist failed traversing the list forwards at {}, traversing backwards".format(
                hex(forward_invalid)))
            hg = HiveGenerator(cmhive, forward = False)
            for hive in hg:
                if hive.vol.offset in seen:
                    vollog.debug("Hivelist found an already seen offset {} while " \
                                 "traversing backwards, list walking met in the middle".format(hex(hive.vol.offset)))
                    break
                seen.add(hive.vol.offset)
                if filter_string is None or filter_string.lower() in str(hive.get_name() or "").lower():
                    if context.layers[layer_name].is_valid(hive.vol.offset):
                        yield hive

            backward_invalid = hg.invalid

            if backward_invalid and forward_invalid != backward_invalid:
                # walking forward and backward did not stop at the same offset. they should if:
                #  1) there are no invalid hives, walking forwards would reach the end and backwards is not necessary
                #  2) there is one invalid hive, walking backwards would stop at the same place as forwards
                # therefore, there must be more 2 or more invalid hives, so the middle of the list is not reachable
                # by walking the list, so revert to scanning, and walk the list forwards and backwards from each
                # found hive
                vollog.debug("Hivelist failed traversing backwards at {}, a different " \
                             "location from forwards, revert to scanning".format(hex(backward_invalid)))
                for hive in hivescan.HiveScan.scan_hives(context, layer_name, symbol_table):
                    try:
                        if hive.HiveList.Flink:
                            start_hive_offset = hive.HiveList.Flink - reloff

                            ## Now instantiate the first hive in virtual address space as normal
                            start_hive = ntkrnlmp.object(object_type = "_CMHIVE",
                                                         offset = start_hive_offset,
                                                         absolute = True)
                            for forward in (True, False):
                                for linked_hive in start_hive.HiveList.to_list(hive.vol.type_name, "HiveList", forward):
                                    if not linked_hive.is_valid() or linked_hive.vol.offset in seen:
                                        continue
                                    seen.add(linked_hive.vol.offset)
                                    if filter_string is None or filter_string.lower() in str(linked_hive.get_name()
                                                                                or "").lower():
                                        if context.layers[layer_name].is_valid(linked_hive.vol.offset):
                                            yield linked_hive
                    except exceptions.InvalidAddressException:
                        vollog.debug("InvalidAddressException when traversing hive {} found from scan, skipping".format(
                            hex(hive.vol.offset)))


def list_sockets(cls,
                     context: interfaces.context.ContextInterface,
                     layer_name: str,
                     darwin_symbols: str,
                     filter_func: Callable[[int], bool] = lambda _: False) -> \
            Iterable[Tuple[interfaces.objects.ObjectInterface,
                           interfaces.objects.ObjectInterface,
                           interfaces.objects.ObjectInterface]]:
        """
        Returns the open socket descriptors of a process

        Return values:
            A tuple of 3 elements:
                1) The name of the process that opened the socket
                2) The process ID of the processed that opened the socket
                3) The address of the associated socket structure
        """
        # This is hardcoded, since a change in the default method would change the expected results
        list_tasks = pslist.PsList.get_list_tasks(pslist.PsList.pslist_methods[0])
        for task in list_tasks(context, layer_name, darwin_symbols, filter_func):

            task_name = utility.array_to_string(task.p_comm)
            pid = task.p_pid

            for filp, _, _ in mac.MacUtilities.files_descriptors_for_process(context, darwin_symbols, task):
                try:
                    ftype = filp.f_fglob.get_fg_type()
                except exceptions.InvalidAddressException:
                    continue

                if ftype != 'SOCKET':
                    continue

                try:
                    socket = filp.f_fglob.fg_data.dereference().cast("socket")
                except exceptions.InvalidAddressException:
                    continue

                yield task_name, pid, socket


Enumerates the registered kauth scopes and yields each object Uses smear - safe enumeration API

def list_kauth_scopes(cls,
                          context: interfaces.context.ContextInterface,
                          layer_name: str,
                          darwin_symbols: str,
                          filter_func: Callable[[int], bool] = lambda _: False) -> \
            Iterable[Tuple[interfaces.objects.ObjectInterface,
                           interfaces.objects.ObjectInterface,
                           interfaces.objects.ObjectInterface]]:
        """
        Enumerates the registered kauth scopes and yields each object
        Uses smear-safe enumeration API
        """

        kernel = contexts.Module(context, darwin_symbols, layer_name, 0)

        scopes = kernel.object_from_symbol("kauth_scopes")

        for scope in mac.MacUtilities.walk_tailq(scopes, "ks_link"):
            yield scope

def list_kauth_scopes ( cls , context : interfaces . context . ContextInterface , layer_name : str , darwin_symbols : str , filter_func : Callable [ [ int ] , bool ] = lambda _ : False ) -> Iterable [ Tuple [ interfaces . objects . ObjectInterface , interfaces . objects . ObjectInterface , interfaces . objects . ObjectInterface ] ] : kernel = contexts . Module ( context , darwin_symbols , layer_name , 0 ) scopes = kernel . object_from_symbol ( "kauth_scopes" ) for scope in mac . MacUtilities . walk_tailq ( scopes , "ks_link" ) : yield scope


def _walk_klist_array(cls, kernel, fdp, array_pointer_member, array_size_member):
        """
        Convience wrapper for walking an array of lists of kernel events
        Handles invalid address references
        """
        try:
            klist_array_pointer = getattr(fdp, array_pointer_member)
            array_size = getattr(fdp, array_size_member)

            klist_array = kernel.object(object_type = "array",
                                        offset = klist_array_pointer,
                                        count = array_size + 1,
                                        subtype = kernel.get_type("klist"))

        except exceptions.InvalidAddressException:
            return

        for klist in klist_array:
            for kn in mac.MacUtilities.walk_slist(klist, "kn_link"):
                yield kn

def _walk_klist_array ( cls , kernel , fdp , array_pointer_member , array_size_member ) : try : klist_array_pointer = getattr ( fdp , array_pointer_member ) array_size = getattr ( fdp , array_size_member ) klist_array = kernel . object ( object_type = "array" , offset = klist_array_pointer , count = array_size + 1 , subtype = kernel . get_type ( "klist" ) ) except exceptions . InvalidAddressException : return for klist in klist_array : for kn in mac . MacUtilities . walk_slist ( klist , "kn_link" ) : yield kn


Enumerates event filters per task . Uses smear - safe APIs throughout as these data structures see a signifcant amount of smear

def _get_task_kevents(cls, kernel, task):
        """
        Enumerates event filters per task.
        Uses smear-safe APIs throughout as these data structures
        see a signifcant amount of smear
        """
        fdp = task.p_fd

        for kn in cls._walk_klist_array(kernel, fdp, "fd_knlist", "fd_knlistsize"):
            yield kn

        for kn in cls._walk_klist_array(kernel, fdp, "fd_knhash", "fd_knhashmask"):
            yield kn

        try:
            p_klist = task.p_klist
        except exceptions.InvalidAddressException:
            return

        for kn in mac.MacUtilities.walk_slist(p_klist, "kn_link"):
            yield kn

def _get_task_kevents ( cls , kernel , task ) : fdp = task . p_fd for kn in cls . _walk_klist_array ( kernel , fdp , "fd_knlist" , "fd_knlistsize" ) : yield kn for kn in cls . _walk_klist_array ( kernel , fdp , "fd_knhash" , "fd_knhashmask" ) : yield kn try : p_klist = task . p_klist except exceptions . InvalidAddressException : return for kn in mac . MacUtilities . walk_slist ( p_klist , "kn_link" ) : yield kn


def list_kernel_events(cls,
                           context: interfaces.context.ContextInterface,
                           layer_name: str,
                           darwin_symbols: str,
                           filter_func: Callable[[int], bool] = lambda _: False) -> \
            Iterable[Tuple[interfaces.objects.ObjectInterface,
                           interfaces.objects.ObjectInterface,
                           interfaces.objects.ObjectInterface]]:
        """
        Returns the kernel event filters registered

        Return values:
            A tuple of 3 elements:
                1) The name of the process that registered the filter
                2) The process ID of the process that registered the filter
                3) The object of the associated kernel event filter
        """
        kernel = contexts.Module(context, darwin_symbols, layer_name, 0)

        list_tasks = pslist.PsList.get_list_tasks(pslist.PsList.pslist_methods[0])

        for task in list_tasks(context, layer_name, darwin_symbols, filter_func):
            task_name = utility.array_to_string(task.p_comm)
            pid = task.p_pid

            for kn in cls._get_task_kevents(kernel, task):
                yield task_name, pid, kn

def list_kernel_events ( cls , context : interfaces . context . ContextInterface , layer_name : str , darwin_symbols : str , filter_func : Callable [ [ int ] , bool ] = lambda _ : False ) -> Iterable [ Tuple [ interfaces . objects . ObjectInterface , interfaces . objects . ObjectInterface , interfaces . objects . ObjectInterface ] ] : kernel = contexts . Module ( context , darwin_symbols , layer_name , 0 ) list_tasks = pslist . PsList . get_list_tasks ( pslist . PsList . pslist_methods [ 0 ] ) for task in list_tasks ( context , layer_name , darwin_symbols , filter_func ) : task_name = utility . array_to_string ( task . p_comm ) pid = task . p_pid for kn in cls . _get_task_kevents ( kernel , task ) : yield task_name , pid , kn


Finds how deep the pid is in the processes list .

def _find_level(self, pid):
        """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.vol.offset != 0 and proc.p_ppid != 0 and proc.p_ppid not in seen:
            ppid = int(proc.p_ppid)
            child_list = self._children.get(ppid, set([]))
            child_list.add(proc.p_pid)
            self._children[ppid] = child_list
            proc = self._processes.get(ppid, None)
            level += 1
        self._levels[pid] = level

def _find_level ( self , pid ) : seen = set ( [ ] ) seen . add ( pid ) level = 0 proc = self . _processes . get ( pid , None ) while proc is not None and proc . vol . offset != 0 and proc . p_ppid != 0 and proc . p_ppid not in seen : ppid = int ( proc . p_ppid ) child_list = self . _children . get ( ppid , set ( [ ] ) ) child_list . add ( proc . p_pid ) self . _children [ ppid ] = child_list proc = self . _processes . get ( ppid , None ) level += 1 self . _levels [ pid ] = level


def _generator(self):
        """Generates the tree list of processes"""
        list_tasks = pslist.PsList.get_list_tasks(self.config.get('pslist_method', pslist.PsList.pslist_methods[0]))

        for proc in list_tasks(self.context, self.config['primary'], self.config['darwin']):
            self._processes[proc.p_pid] = 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.p_pid, proc.p_ppid, utility.array_to_string(proc.p_comm))

            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
)
:
list_tasks
=
pslist
.
PsList
.
get_list_tasks
(
self
.
config
.
get
(
'pslist_method'
,
pslist
.
PsList
.
pslist_methods
[
0
]
)
)
for
proc
in
list_tasks
(
self
.
context
,
self
.
config
[
'primary'
]
,
self
.
config
[
'darwin'
]
)
:
self
.
_processes
[
proc
.
p_pid
]
=
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
.
p_pid
,
proc
.
p_ppid
,
utility
.
array_to_string
(
proc
.
p_comm
)
)
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):
        """
        Enumerates the listeners for each kauth scope
        """
        kernel = contexts.Module(self.context, self.config['darwin'], self.config['primary'], 0)

        mods = lsmod.Lsmod.list_modules(self.context, self.config['primary'], self.config['darwin'])

        handlers = mac.MacUtilities.generate_kernel_handler_info(self.context, self.config['primary'], kernel, mods)

        for scope in kauth_scopes.Kauth_scopes.list_kauth_scopes(self.context, self.config['primary'],
                                                                 self.config['darwin']):

            scope_name = utility.pointer_to_string(scope.ks_identifier, 128)

            for listener in scope.get_listeners():
                callback = listener.kll_callback
                if callback == 0:
                    continue

                module_name, symbol_name = mac.MacUtilities.lookup_module_address(self.context, handlers, callback)

                yield (0, (scope_name, format_hints.Hex(listener.kll_idata), format_hints.Hex(callback), module_name,
                           symbol_name))

def _generator ( self ) : kernel = contexts . Module ( self . context , self . config [ 'darwin' ] , self . config [ 'primary' ] , 0 ) mods = lsmod . Lsmod . list_modules ( self . context , self . config [ 'primary' ] , self . config [ 'darwin' ] ) handlers = mac . MacUtilities . generate_kernel_handler_info ( self . context , self . config [ 'primary' ] , kernel , mods ) for scope in kauth_scopes . Kauth_scopes . list_kauth_scopes ( self . context , self . config [ 'primary' ] , self . config [ 'darwin' ] ) : scope_name = utility . pointer_to_string ( scope . ks_identifier , 128 ) for listener in scope . get_listeners ( ) : callback = listener . kll_callback if callback == 0 : continue module_name , symbol_name = mac . MacUtilities . lookup_module_address ( self . context , handlers , callback ) yield ( 0 , ( scope_name , format_hints . Hex ( listener . kll_idata ) , format_hints . Hex ( callback ) , module_name , symbol_name ) )


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

def _list_injections(self, task):
        """Generate memory regions for a process that may contain injected
        code."""

        proc_layer_name = task.add_process_layer()
        if proc_layer_name is None:
            return

        proc_layer = self.context.layers[proc_layer_name]

        for vma in task.get_map_iter():
            if not vma.is_suspicious(self.context, self.config['darwin']):
                data = proc_layer.read(vma.links.start, 64, pad = True)
                yield vma, data

def _list_injections ( self , task ) : proc_layer_name = task . add_process_layer ( ) if proc_layer_name is None : return proc_layer = self . context . layers [ proc_layer_name ] for vma in task . get_map_iter ( ) : if not vma . is_suspicious ( self . context , self . config [ 'darwin' ] ) : data = proc_layer . read ( vma . links . start , 64 , pad = True ) yield vma , data


def _add_vnode(cls, vnode, loop_vnodes):
        """
        Adds the given vnode to loop_vnodes.

        loop_vnodes is key off the address of a vnode
        and holds its name, parent address, and object
        """

        key = vnode
        added = False

        if not key in loop_vnodes:
            # We can't do anything with a no-name vnode
            v_name = cls._vnode_name(vnode)
            if v_name is None:
                return added

            parent = cls._get_parent(vnode)
            if parent:
                parent_val = parent
            else:
                parent_val = None

            loop_vnodes[key] = (v_name, parent_val, vnode)

            added = True

        return added


Iterates over the list of vnodes associated with the given one . Also traverses the parent chain for the vnode and adds each one .

def _walk_vnode(cls, vnode, loop_vnodes):
        """
        Iterates over the list of vnodes associated with the given one.
        Also traverses the parent chain for the vnode and adds each one.
        """
        while vnode:
            if not cls._add_vnode(vnode, loop_vnodes):
                break

            parent = cls._get_parent(vnode)
            while parent:
                cls._walk_vnode(parent, loop_vnodes)
                parent = cls._get_parent(parent)

            try:
                vnode = vnode.v_mntvnodes.tqe_next
            except exceptions.InvalidAddressException:
                break

def _walk_vnode ( cls , vnode , loop_vnodes ) : while vnode : if not cls . _add_vnode ( vnode , loop_vnodes ) : break parent = cls . _get_parent ( vnode ) while parent : cls . _walk_vnode ( parent , loop_vnodes ) parent = cls . _get_parent ( parent ) try : vnode = vnode . v_mntvnodes . tqe_next except exceptions . InvalidAddressException : break


def get_list_tasks(
        cls, method: str
    ) -> Callable[[interfaces.context.ContextInterface, str, str, Callable[[int], bool]],
                  Iterable[interfaces.objects.ObjectInterface]]:
        """Returns the list_tasks method based on the selector

        Args:
            method: Must be one fo the available methods in get_task_choices

        Returns:
            list_tasks method for listing tasks
            """
        # Ensure method is one of the suitable choices
        if method not in cls.pslist_methods:
            method = cls.pslist_methods[0]

        if method == 'allproc':
            list_tasks = cls.list_tasks_allproc
        elif method == 'tasks':
            list_tasks = cls.list_tasks_tasks
        elif method == 'process_group':
            list_tasks = cls.list_tasks_process_group
        elif method == 'sessions':
            list_tasks = cls.list_tasks_sessions
        elif method == 'pid_hash_table':
            list_tasks = cls.list_tasks_pid_hash_table
        else:
            raise ValueError("Impossible method choice chosen")
        vollog.debug("Using method {}".format(method))

        return list_tasks


def list_tasks_allproc(cls,
                           context: interfaces.context.ContextInterface,
                           layer_name: str,
                           darwin_symbols: str,
                           filter_func: Callable[[int], bool] = lambda _: False) -> \
            Iterable[interfaces.objects.ObjectInterface]:
        """Lists all the processes in the primary layer based on the allproc method

        Args:
            context: The context to retrieve required elements (layers, symbol tables) from
            layer_name: The name of the layer on which to operate
            darwin_symbols: The name of the table containing the kernel symbols
            filter_func: A function which takes a process object and returns True if the process should be ignored/filtered

        Returns:
            The list of process objects from the processes linked list after filtering
        """

        kernel = contexts.Module(context, darwin_symbols, layer_name, 0)

        kernel_layer = context.layers[layer_name]

        proc = kernel.object_from_symbol(symbol_name = "allproc").lh_first

        seen = {}  # type: Dict[int, int]
        while proc is not None and proc.vol.offset != 0:
            if proc.vol.offset in seen:
                vollog.log(logging.INFO, "Recursive process list detected (a result of non-atomic acquisition).")
                break
            else:
                seen[proc.vol.offset] = 1

            if kernel_layer.is_valid(proc.vol.offset, proc.vol.size) and not filter_func(proc):
                yield proc

            try:
                proc = proc.p_list.le_next.dereference()
            except exceptions.InvalidAddressException:
                break


def list_tasks_tasks(cls,
                         context: interfaces.context.ContextInterface,
                         layer_name: str,
                         darwin_symbols: str,
                         filter_func: Callable[[int], bool] = lambda _: False) -> \
            Iterable[interfaces.objects.ObjectInterface]:
        """Lists all the tasks in the primary layer based on the tasks queue

        Args:
            context: The context to retrieve required elements (layers, symbol tables) from
            layer_name: The name of the layer on which to operate
            darwin_symbols: The name of the table containing the kernel symbols
            filter_func: A function which takes a task object and returns True if the task should be ignored/filtered

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

        kernel = contexts.Module(context, darwin_symbols, layer_name, 0)

        kernel_layer = context.layers[layer_name]

        queue_entry = kernel.object_from_symbol(symbol_name = "tasks")

        seen = {}  # type: Dict[int, int]
        for task in queue_entry.walk_list(queue_entry, "tasks", "task"):
            if task.vol.offset in seen:
                vollog.log(logging.INFO, "Recursive process list detected (a result of non-atomic acquisition).")
                break
            else:
                seen[task.vol.offset] = 1

            try:
                proc = task.bsd_info.dereference().cast("proc")
            except exceptions.InvalidAddressException:
                continue

            if kernel_layer.is_valid(proc.vol.offset, proc.vol.size) and not filter_func(proc):
                yield proc


def list_tasks_sessions(cls,
                            context: interfaces.context.ContextInterface,
                            layer_name: str,
                            darwin_symbols: str,
                            filter_func: Callable[[int], bool] = lambda _: False) -> \
            Iterable[interfaces.objects.ObjectInterface]:
        """Lists all the tasks in the primary layer using sessions

        Args:
            context: The context to retrieve required elements (layers, symbol tables) from
            layer_name: The name of the layer on which to operate
            darwin_symbols: The name of the table containing the kernel symbols
            filter_func: A function which takes a task object and returns True if the task should be ignored/filtered

        Returns:
            The list of task objects from the `layer_name` layer's `tasks` list after filtering
        """
        kernel = contexts.Module(context, darwin_symbols, layer_name, 0)

        table_size = kernel.object_from_symbol(symbol_name = "sesshash")

        sesshashtbl = kernel.object_from_symbol(symbol_name = "sesshashtbl")

        proc_array = kernel.object(object_type = "array",
                                   offset = sesshashtbl,
                                   count = table_size + 1,
                                   subtype = kernel.get_type("sesshashhead"))

        for proc_list in proc_array:
            for proc in mac.MacUtilities.walk_list_head(proc_list, "s_hash"):
                if proc.s_leader.is_readable() and not filter_func(proc.s_leader):
                    yield proc.s_leader

def list_tasks_sessions ( cls , context : interfaces . context . ContextInterface , layer_name : str , darwin_symbols : str , filter_func : Callable [ [ int ] , bool ] = lambda _ : False ) -> Iterable [ interfaces . objects . ObjectInterface ] : kernel = contexts . Module ( context , darwin_symbols , layer_name , 0 ) table_size = kernel . object_from_symbol ( symbol_name = "sesshash" ) sesshashtbl = kernel . object_from_symbol ( symbol_name = "sesshashtbl" ) proc_array = kernel . object ( object_type = "array" , offset = sesshashtbl , count = table_size + 1 , subtype = kernel . get_type ( "sesshashhead" ) ) for proc_list in proc_array : for proc in mac . MacUtilities . walk_list_head ( proc_list , "s_hash" ) : if proc . s_leader . is_readable ( ) and not filter_func ( proc . s_leader ) : yield proc . s_leader