Property to prevent the initializer storing an unserializable open file ( for context cloning )

def _file(self) -> IO[Any]:
        """Property to prevent the initializer storing an unserializable open
        file (for context cloning)"""
        # FIXME: Add "+" to the mode once we've determined whether write mode is enabled
        mode = "rb"
        self._file_ = self._file_ or self._accessor.open(self._location, mode)
        return self._file_


Returns the largest available address in the space .

def maximum_address(self) -> int:
        """Returns the largest available address in the space."""
        # Zero based, so we return the size of the file minus 1
        if self._size:
            return self._size
        with self._lock:
            orig = self._file.tell()
            self._file.seek(0, 2)
            self._size = self._file.tell()
            self._file.seek(orig)
        return self._size


Returns the smallest available address in the space .

def minimum_address(self) -> int:
        """Returns the smallest available address in the space."""
        return 0

def minimum_address ( self ) -> int : return 0


Returns whether the offset is valid or not .

def is_valid(self, offset: int, length: int = 1) -> bool:
        """Returns whether the offset is valid or not."""
        if length <= 0:
            raise ValueError("Length must be positive")
        return bool(self.minimum_address <= offset <= self.maximum_address
                    and self.minimum_address <= offset + length - 1 <= self.maximum_address)

def
is_valid
(
self
,
offset
:
int
,
length
:
int
=
1
)
->
bool
:
if
length
<=
0
:
raise
ValueError
(
"Length must be positive"
)
return
bool
(
self
.
minimum_address
<=
offset
<=
self
.
maximum_address
and
self
.
minimum_address
<=
offset
+
length
1
<=
self
.
maximum_address
)


Reads from the file at offset for length .

def read(self, offset: int, length: int, pad: bool = False) -> bytes:
        """Reads from the file at offset for length."""
        if not self.is_valid(offset, length):
            invalid_address = offset
            if self.minimum_address < offset <= self.maximum_address:
                invalid_address = self.maximum_address + 1
            raise exceptions.InvalidAddressException(self.name, invalid_address,
                                                     "Offset outside of the buffer boundaries")

        # TODO: implement locking for multi-threading
        with self._lock:
            self._file.seek(offset)
            data = self._file.read(length)

        if len(data) < length:
            if pad:
                data += (b"\x00" * (length - len(data)))
            else:
                raise exceptions.InvalidAddressException(
                    self.name, offset + len(data), "Could not read sufficient bytes from the " + self.name + " file")
        return data


def write(self, offset: int, data: bytes) -> None:
        """Writes to the file.

        This will technically allow writes beyond the extent of the file
        """
        if not self.is_valid(offset, len(data)):
            invalid_address = offset
            if self.minimum_address < offset <= self.maximum_address:
                invalid_address = self.maximum_address + 1
            raise exceptions.InvalidAddressException(self.name, invalid_address,
                                                     "Data segment outside of the " + self.name + " file boundaries")
        with self._lock:
            self._file.seek(offset)
            self._file.write(data)

def
write
(
self
,
offset
:
int
,
data
:
bytes
)
->
:
if
not
self
.
is_valid
(
offset
,
len
(
data
)
)
:
invalid_address
=
offset
if
self
.
minimum_address
<
offset
<=
self
.
maximum_address
:
invalid_address
=
self
.
maximum_address
+
1
raise
exceptions
.
InvalidAddressException
(
self
.
name
,
invalid_address
,
"Data segment outside of the "
+
self
.
name
+
" file boundaries"
)
with
self
.
_lock
:
self
.
_file
.
seek
(
offset
)
self
.
_file
.
write
(
data
)


Do not store the open _file_ attribute our property will ensure the file is open when needed .

def __getstate__(self) -> Dict[str, Any]:
        """Do not store the open _file_ attribute, our property will ensure the
        file is open when needed.

        This is necessary for multi-processing
        """
        self._file_ = None
        return self.__dict__

def __getstate__ ( self ) -> Dict [ str , Any ] : self . _file_ = None return self . __dict__


def destroy(self) -> None:
        """Closes the file handle."""
        self._file.close()

def destroy ( self ) -> None : self . _file . close ( )


Loads up the segments from the meta_layer .

def _load_segments(self) -> None:
        """Loads up the segments from the meta_layer."""
        self._read_header()

def _load_segments ( self ) -> None : self . _read_header ( )


Checks the vmware header to make sure it s valid .

def _read_header(self) -> None:
        """Checks the vmware header to make sure it's valid."""
        if "vmware" not in self._context.symbol_space:
            self._context.symbol_space.append(native.NativeTable("vmware", native.std_ctypes))

        meta_layer = self.context.layers.get(self._meta_layer, None)
        header_size = struct.calcsize(self.header_structure)
        data = meta_layer.read(0, header_size)
        magic, unknown, groupCount = struct.unpack(self.header_structure, data)
        if magic not in [b"\xD2\xBE\xD2\xBE"]:
            raise VmwareFormatException(self.name, "Wrong magic bytes for Vmware layer: {}".format(repr(magic)))

        # TODO: Change certain structure sizes based on the version
        # version = magic[1] & 0xf

        group_size = struct.calcsize(self.group_structure)

        groups = {}
        for group in range(groupCount):
            name, tag_location, _unknown = struct.unpack(
                self.group_structure, meta_layer.read(header_size + (group * group_size), group_size))
            name = name.rstrip(b"\x00")
            groups[name] = tag_location
        memory = groups[b"memory"]

        tags_read = False
        offset = memory
        tags = {}
        index_len = self._context.symbol_space.get_type("vmware!unsigned int").size
        while not tags_read:
            flags = ord(meta_layer.read(offset, 1))
            name_len = ord(meta_layer.read(offset + 1, 1))
            tags_read = (flags == 0) and (name_len == 0)
            if not tags_read:
                name = self._context.object("vmware!string",
                                            layer_name = self._meta_layer,
                                            offset = offset + 2,
                                            max_length = name_len)
                indicies_len = (flags >> 6) & 3
                indicies = []
                for index in range(indicies_len):
                    indicies.append(
                        self._context.object("vmware!unsigned int",
                                             offset = offset + name_len + 2 + (index * index_len),
                                             layer_name = self._meta_layer))
                data = self._context.object("vmware!unsigned int",
                                            layer_name = self._meta_layer,
                                            offset = offset + 2 + name_len + (indicies_len * index_len))
                tags[(name, tuple(indicies))] = (flags, data)
                offset += 2 + name_len + (indicies_len *
                                          index_len) + self._context.symbol_space.get_type("vmware!unsigned int").size

        if tags[("regionsCount", ())][1] == 0:
            raise VmwareFormatException(self.name, "VMware VMEM is not split into regions")
        for region in range(tags[("regionsCount", ())][1]):
            offset = tags[("regionPPN", (region,))][1] * self._page_size
            mapped_offset = tags[("regionPageNum", (region,))][1] * self._page_size
            length = tags[("regionSize", (region,))][1] * self._page_size
            self._segments.append((offset, mapped_offset, length, length))


This vmware translation layer always requires a separate metadata layer .

def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]:
        """This vmware translation layer always requires a separate metadata
        layer."""
        return [
            requirements.TranslationLayerRequirement(name = 'base_layer', optional = False),
            requirements.TranslationLayerRequirement(name = 'meta_layer', optional = False)
        ]

def get_requirements ( cls ) -> List [ interfaces . configuration . RequirementInterface ] : return [ requirements . TranslationLayerRequirement ( name = 'base_layer' , optional = False ) , requirements . TranslationLayerRequirement ( name = 'meta_layer' , optional = False ) ]


Attempt to stack this based on the starting information .

def stack(cls,
              context: interfaces.context.ContextInterface,
              layer_name: str,
              progress_callback: constants.ProgressCallback = None) -> Optional[interfaces.layers.DataLayerInterface]:
        """Attempt to stack this based on the starting information."""
        memlayer = context.layers[layer_name]
        if not isinstance(memlayer, physical.FileLayer):
            return None
        location = memlayer.location
        if location.endswith(".vmem"):
            vmss = location[:-5] + ".vmss"
            vmsn = location[:-5] + ".vmsn"
            current_layer_name = context.layers.free_layer_name("VmwareMetaLayer")
            current_config_path = interfaces.configuration.path_join("automagic", "layer_stacker", "stack",
                                                                     current_layer_name)

            try:
                _ = resources.ResourceAccessor().open(vmss).read(10)
                context.config[interfaces.configuration.path_join(current_config_path, "location")] = vmss
                context.layers.add_layer(physical.FileLayer(context, current_config_path, current_layer_name))
                vmss_success = True
            except IOError:
                vmss_success = False

            if not vmss_success:
                try:
                    _ = resources.ResourceAccessor().open(vmsn).read(10)
                    context.config[interfaces.configuration.path_join(current_config_path, "location")] = vmsn
                    context.layers.add_layer(physical.FileLayer(context, current_config_path, current_layer_name))
                    vmsn_success = True
                except IOError:
                    vmsn_success = False

            if not vmss_success and not vmsn_success:
                return None
            new_layer_name = context.layers.free_layer_name("VmwareLayer")
            context.config[interfaces.configuration.path_join(current_config_path, "base_layer")] = layer_name
            context.config[interfaces.configuration.path_join(current_config_path, "meta_layer")] = current_layer_name
            new_layer = VmwareLayer(context, current_config_path, new_layer_name)
            return new_layer
        return None

def stack ( cls , context : interfaces . context . ContextInterface , layer_name : str , progress_callback : constants . ProgressCallback = None ) -> Optional [ interfaces . layers . DataLayerInterface ] : memlayer = context . layers [ layer_name ] if not isinstance ( memlayer , physical . FileLayer ) : return None location = memlayer . location if location . endswith ( ".vmem" ) : vmss = location [ : - 5 ] + ".vmss" vmsn = location [ : - 5 ] + ".vmsn" current_layer_name = context . layers . free_layer_name ( "VmwareMetaLayer" ) current_config_path = interfaces . configuration . path_join ( "automagic" , "layer_stacker" , "stack" , current_layer_name ) try : _ = resources . ResourceAccessor ( ) . open ( vmss ) . read ( 10 ) context . config [ interfaces . configuration . path_join ( current_config_path , "location" ) ] = vmss context . layers . add_layer ( physical . FileLayer ( context , current_config_path , current_layer_name ) ) vmss_success = True except IOError : vmss_success = False if not vmss_success : try : _ = resources . ResourceAccessor ( ) . open ( vmsn ) . read ( 10 ) context . config [ interfaces . configuration . path_join ( current_config_path , "location" ) ] = vmsn context . layers . add_layer ( physical . FileLayer ( context , current_config_path , current_layer_name ) ) vmsn_success = True except IOError : vmsn_success = False if not vmss_success and not vmsn_success : return None new_layer_name = context . layers . free_layer_name ( "VmwareLayer" ) context . config [ interfaces . configuration . path_join ( current_config_path , "base_layer" ) ] = layer_name context . config [ interfaces . configuration . path_join ( current_config_path , "meta_layer" ) ] = current_layer_name new_layer = VmwareLayer ( context , current_config_path , new_layer_name ) return new_layer return None


Runs through the data looking for the needle and yields all offsets where the needle is found .

def __call__(self, data: bytes, data_offset: int) -> Generator[int, None, None]:
        """Runs through the data looking for the needle, and yields all offsets
        where the needle is found."""
        find_pos = data.find(self.needle)
        while find_pos >= 0:
            if find_pos < self.chunk_size:
                yield find_pos + data_offset
            find_pos = data.find(self.needle, find_pos + 1)

def __call__ ( self , data : bytes , data_offset : int ) -> Generator [ int , None , None ] : find_pos = data . find ( self . needle ) while find_pos >= 0 : if find_pos < self . chunk_size : yield find_pos + data_offset find_pos = data . find ( self . needle , find_pos + 1 )


def __call__(self, data: bytes, data_offset: int) -> Generator[int, None, None]:
        """Runs through the data looking for the needle, and yields all offsets
        where the needle is found."""
        find_pos = self.regex.finditer(data)
        for match in find_pos:
            offset = match.start()
            if offset < self.chunk_size:
                yield offset + data_offset

def __call__ ( self , data : bytes , data_offset : int ) -> Generator [ int , None , None ] : find_pos = self . regex . finditer ( data ) for match in find_pos : offset = match . start ( ) if offset < self . chunk_size : yield offset + data_offset


Runs through the data looking for the needles .

def __call__(self, data: bytes, data_offset: int) -> Generator[Tuple[int, bytes], None, None]:
        """Runs through the data looking for the needles."""
        for offset, pattern in self._patterns.search(data):
            if offset < self.chunk_size:
                yield offset + data_offset, pattern

def __call__ ( self , data : bytes , data_offset : int ) -> Generator [ Tuple [ int , bytes ] , None , None ] : for offset , pattern in self . _patterns . search ( data ) : if offset < self . chunk_size : yield offset + data_offset , pattern


Converts a series of bytes to a particular type of value .

def convert_data_to_value(data: bytes, struct_type: Type[TUnion[int, float, bytes, str, bool]],
                          data_format: DataFormatInfo) -> TUnion[int, float, bytes, str, bool]:
    """Converts a series of bytes to a particular type of value."""
    if struct_type == int:
        return int.from_bytes(data, byteorder = data_format.byteorder, signed = data_format.signed)
    if struct_type == bool:
        struct_format = "?"
    elif struct_type == float:
        float_vals = "zzezfzzzd"
        if data_format.length > len(float_vals) or float_vals[data_format.length] not in "efd":
            raise ValueError("Invalid float size")
        struct_format = ("<" if data_format.byteorder == 'little' else ">") + float_vals[data_format.length]
    elif struct_type in [bytes, str]:
        struct_format = str(data_format.length) + "s"
    else:
        raise TypeError("Cannot construct struct format for type {}".format(type(struct_type)))

    return struct.unpack(struct_format, data)[0]


Converts a particular value to a series of bytes .

def convert_value_to_data(value: TUnion[int, float, bytes, str, bool], struct_type: Type[TUnion[int, float, bytes, str,
                                                                                bool]],
                          data_format: DataFormatInfo) -> bytes:
    """Converts a particular value to a series of bytes."""
    if not isinstance(value, struct_type):
        raise TypeError("Written value is not of the correct type for {}".format(struct_type.__class__.__name__))

    if struct_type == int and isinstance(value, int):
        # Doubling up on the isinstance is for mypy
        return int.to_bytes(value,
                            length = data_format.length,
                            byteorder = data_format.byteorder,
                            signed = data_format.signed)
    if struct_type == bool:
        struct_format = "?"
    elif struct_type == float:
        float_vals = "zzezfzzzd"
        if data_format.length > len(float_vals) or float_vals[data_format.length] not in "efd":
            raise ValueError("Invalid float size")
        struct_format = ("<" if data_format.byteorder == 'little' else ">") + float_vals[data_format.length]
    elif struct_type in [bytes, str]:
        struct_format = str(data_format.length) + "s"
    else:
        raise TypeError("Cannot construct struct format for type {}".format(type(struct_type)))

    return struct.pack(struct_format, value)


Dummy method that does nothing for Void objects .

def write(self, value: Any) -> None:
        """Dummy method that does nothing for Void objects."""
        raise TypeError("Cannot write data to a void, recast as another object")


Creates the appropriate class and returns it so that the native type is inherited .

def __new__(cls: Type,
                context: interfaces.context.ContextInterface,
                type_name: str,
                object_info: interfaces.objects.ObjectInformation,
                data_format: DataFormatInfo,
                new_value: TUnion[int, float, bool, bytes, str] = None,
                **kwargs) -> 'PrimitiveObject':
        """Creates the appropriate class and returns it so that the native type
        is inherited.

        The only reason the kwargs is added, is so that the inherriting types can override __init__
        without needing to override __new__

        We also sneak in new_value, so that we don't have to do expensive (read: impossible) context reads
        when unpickling.
        """
        if new_value is None:
            value = cls._unmarshall(context, data_format, object_info)
        else:
            value = new_value
        result = cls._struct_type.__new__(cls, value)
        # This prevents us having to go read a context layer when recreating after unpickling
        # Mypy complains that result doesn't have a __new_value, but using setattr causes pycharm to complain further down
        result.__new_value = value  # type: ignore
        return result


Make sure that when pickling all appropiate parameters for new are provided .

def __getnewargs_ex__(self):
        """Make sure that when pickling, all appropiate parameters for new are
        provided."""
        kwargs = {}
        for k, v in self._vol.maps[-1].items():
            if k not in ["context", "data_format", "object_info", "type_name"]:
                kwargs[k] = v
        kwargs['new_value'] = self.__new_value
        return (self._context, self._vol.maps[-2]['type_name'], self._vol.maps[-3], self._data_format), kwargs

def __getnewargs_ex__ ( self ) : kwargs = { } for k , v in self . _vol . maps [ - 1 ] . items ( ) : if k not in [ "context" , "data_format" , "object_info" , "type_name" ] : kwargs [ k ] = v kwargs [ 'new_value' ] = self . __new_value return ( self . _context , self . _vol . maps [ - 2 ] [ 'type_name' ] , self . _vol . maps [ - 3 ] , self . _data_format ) , kwargs


Writes the object into the layer of the context at the current offset .

def write(self, value: TUnion[int, float, bool, bytes, str]) -> None:
        """Writes the object into the layer of the context at the current
        offset."""
        data = convert_value_to_data(value, self._struct_type, self._data_format)
        return self._context.layers.write(self.vol.layer_name, self.vol.offset, data)

def write ( self , value : TUnion [ int , float , bool , bytes , str ] ) -> None : data = convert_value_to_data ( value , self . _struct_type , self . _data_format ) return self . _context . layers . write ( self . vol . layer_name , self . vol . offset , data )


Creates the appropriate class and returns it so that the native type is inherritted .

def __new__(cls: Type,
                context: interfaces.context.ContextInterface,
                type_name: str,
                object_info: interfaces.objects.ObjectInformation,
                length: int = 1,
                **kwargs) -> 'Bytes':
        """Creates the appropriate class and returns it so that the native type
        is inherritted.

        The only reason the kwargs is added, is so that the
        inherriting types can override __init__ without needing to
        override __new__
        """
        return cls._struct_type.__new__(
            cls, cls._unmarshall(context, data_format = DataFormatInfo(length, "big", False),
                                 object_info = object_info))

def __new__ ( cls : Type , context : interfaces . context . ContextInterface , type_name : str , object_info : interfaces . objects . ObjectInformation , length : int = 1 , * * kwargs ) -> 'Bytes' : return cls . _struct_type . __new__ ( cls , cls . _unmarshall ( context , data_format = DataFormatInfo ( length , "big" , False ) , object_info = object_info ) )


def __new__(cls: Type,
                context: interfaces.context.ContextInterface,
                type_name: str,
                object_info: interfaces.objects.ObjectInformation,
                max_length: int = 1,
                encoding: str = "utf-8",
                errors: str = "strict",
                **kwargs) -> 'String':
        """Creates the appropriate class and returns it so that the native type
        is inherited.

        The only reason the kwargs is added, is so that the
        inherriting types can override __init__ without needing to
        override __new__
        """
        params = {}
        if encoding:
            params['encoding'] = encoding
        if errors:
            params['errors'] = errors
        # Pass the encoding and error parameters to the string constructor to appropriately encode the string
        value = cls._struct_type.__new__(
            cls,
            cls._unmarshall(context, data_format = DataFormatInfo(max_length, "big", False), object_info = object_info),
            **params)
        if value.find('\x00') >= 0:
            value = value[:value.find('\x00')]
        return value


Ensure that pointer values always fall within the domain of the layer they re constructed on .

def _unmarshall(cls, context: interfaces.context.ContextInterface, data_format: DataFormatInfo,
                    object_info: interfaces.objects.ObjectInformation) -> Any:
        """Ensure that pointer values always fall within the domain of the
        layer they're constructed on.

        If there's a need for all the data within the address, the
        pointer should be recast.  The "pointer" must always live within
        the space (even if the data provided is invalid).
        """
        length, endian, signed = data_format
        if signed:
            raise ValueError("Pointers cannot have signed values")
        mask = context.layers[object_info.native_layer_name].address_mask
        data = context.layers.read(object_info.layer_name, object_info.offset, length)
        value = int.from_bytes(data, byteorder = endian, signed = signed)
        return value & mask

def
_unmarshall
(
cls
,
context
:
interfaces
.
context
.
ContextInterface
,
data_format
:
DataFormatInfo
,
object_info
:
interfaces
.
objects
.
ObjectInformation
)
->
Any
:
length
,
endian
,
signed
=
data_format
if
signed
:
raise
ValueError
(
"Pointers cannot have signed values"
)
mask
=
context
.
layers
[
object_info
.
native_layer_name
]
.
address_mask
data
=
context
.
layers
.
read
(
object_info
.
layer_name
,
object_info
.
offset
,
length
)
value
=
int
.
from_bytes
(
data
,
byteorder
=
endian
,
signed
=
signed
)
return
value
&
mask


def dereference(self, layer_name: Optional[str] = None) -> interfaces.objects.ObjectInterface:
        """Dereferences the pointer.

        Layer_name is identifies the appropriate layer within the
        context that the pointer points to. If layer_name is None, it
        defaults to the same layer that the pointer is currently
        instantiated in.
        """
        layer_name = layer_name or self.vol.native_layer_name
        mask = self._context.layers[layer_name].address_mask
        offset = self & mask
        return self.vol.subtype(context = self._context,
                                object_info = interfaces.objects.ObjectInformation(layer_name = layer_name,
                                                                                offset = offset,
                                                                                parent = self,
                                                                                size = self.vol.subtype.size))

def dereference ( self , layer_name : Optional [ str ] = None ) -> interfaces . objects . ObjectInterface : layer_name = layer_name or self . vol . native_layer_name mask = self . _context . layers [ layer_name ] . address_mask offset = self & mask return self . vol . subtype ( context = self . _context , object_info = interfaces . objects . ObjectInformation ( layer_name = layer_name , offset = offset , parent = self , size = self . vol . subtype . size ) )


Determines whether the address of this pointer can be read from memory .

def is_readable(self, layer_name: Optional[str] = None) -> bool:
        """Determines whether the address of this pointer can be read from
        memory."""
        layer_name = layer_name or self.vol.layer_name
        return self._context.layers[layer_name].is_valid(self, self.vol.subtype.size)

def is_readable ( self , layer_name : Optional [ str ] = None ) -> bool : layer_name = layer_name or self . vol . layer_name return self . _context . layers [ layer_name ] . is_valid ( self , self . vol . subtype . size )


Convenience function to access unknown attributes by getting them from the subtype object .

def __getattr__(self, attr: str) -> Any:
        """Convenience function to access unknown attributes by getting them
        from the subtype object."""
        if attr in ['vol', '_vol']:
            raise AttributeError("Pointer not initialized before use")
        return getattr(self.dereference(), attr)

def
__getattr__
(
self
,
attr
:
str
)
->
Any
:
if
attr
in
[
'vol'
,
'_vol'
]
:
raise
AttributeError
(
"Pointer not initialized before use"
)
return
getattr
(
self
.
dereference
(
)
,
attr
)


Returns whether the dereferenced type has this member .

def has_member(self, member_name: str) -> bool:
        """Returns whether the dereferenced type has this member."""
        return self._vol['subtype'].has_member(member_name)

def has_member ( self , member_name : str ) -> bool : return self . _vol [ 'subtype' ] . has_member ( member_name )


An enumeration must be equivalent to its value even if the other value is not an enumeration

def __eq__(self, other):
        """An enumeration must be equivalent to its value, even if the other value is not an enumeration"""
        return int(self) == other

def __eq__ ( self , other ) : return int ( self ) == other


def __hash__(self):
        """Enumerations must be hashed as equivalent to their integer counterparts"""
        return super().__hash__()

def __hash__ ( self ) : return super ( ) . __hash__ ( )


Generates the inverse choices for the object .

def _generate_inverse_choices(cls, choices: Dict[str, int]) -> Dict[int, str]:
        """Generates the inverse choices for the object."""
        inverse_choices = {}  # type: Dict[int, str]
        for k, v in choices.items():
            if v in inverse_choices:
                # Technically this shouldn't be a problem, but since we inverse cache
                # and can't map one value to two possibilities we throw an exception during build
                # We can remove/work around this if it proves a common issue
                raise ValueError("Enumeration value {} duplicated as {} and {}".format(v, k, inverse_choices[v]))
            inverse_choices[v] = k
        return inverse_choices


Looks up an individual value and returns the associated name .

def lookup(self, value: int = None) -> str:
        """Looks up an individual value and returns the associated name."""
        if value is None:
            return self.lookup(self)
        if value in self._inverse_choices:
            return self._inverse_choices[value]
        raise ValueError("The value of the enumeration is outside the possible choices")


Returns the chosen name for the value this object contains .

def description(self) -> str:
        """Returns the chosen name for the value this object contains."""
        return self.lookup(self)

def description ( self ) -> str : return self . lookup ( self )


def is_valid_choice(self) -> bool:
        """Returns whether the value for the object is a valid choice"""
        return self in self.choices.values()

def is_valid_choice ( self ) -> bool : return self in self . choices . values ( )


def __getattr__(self, attr: str) -> str:
        """Returns the value for a specific name."""
        if attr in self._vol['choices']:
            return self._vol['choices'][attr]
        raise AttributeError("Unknown attribute {} for Enumeration {}".format(attr, self._vol['type_name']))


def count(self) -> int:
        """Returns the count dynamically."""
        return self.vol.count

def count ( self ) -> int : return self . vol . count


def count(self, value: int) -> None:
        """Sets the count to a specific value."""
        self._vol['count'] = value
        self._vol['size'] = value * self._vol['subtype'].size

def count ( self , value : int ) -> None : self . _vol [ 'count' ] = value self . _vol [ 'size' ] = value * self . _vol [ 'subtype' ] . size


Returns the i - th item from the array .

def __getitem__(self, i):
        """Returns the i-th item from the array."""
        result = []  # type: List[interfaces.objects.Template]
        mask = self._context.layers[self.vol.layer_name].address_mask
        # We use the range function to deal with slices for us
        series = range(self.vol.count)[i]
        return_list = True
        if isinstance(series, int):
            return_list = False
            series = [series]
        for index in series:
            object_info = interfaces.objects.ObjectInformation(
                layer_name = self.vol.layer_name,
                offset = mask & (self.vol.offset + (self.vol.subtype.size * index)),
                parent = self,
                native_layer_name = self.vol.native_layer_name,
                size = self.vol.subtype.size)
            result += [self.vol.subtype(context = self._context, object_info = object_info)]
        if not return_list:
            return result[0]
        return result


def __len__(self) -> int:
        """Returns the length of the array."""
        return self.vol.count

def __len__ ( self ) -> int : return self . vol . count


Returns whether the object would contain a member called member_name .

def has_member(self, member_name: str) -> bool:
        """Returns whether the object would contain a member called
        member_name."""
        return member_name in self.vol.members

def has_member ( self , member_name : str ) -> bool : return member_name in self . vol . members


Specifically named method for retrieving members .

def member(self, attr: str = 'member') -> object:
        """Specifically named method for retrieving members."""
        return self.__getattr__(attr)

def member ( self , attr : str = 'member' ) -> object : return self . __getattr__ ( attr )


Method for accessing members of the type .

def __getattr__(self, attr: str) -> Any:
        """Method for accessing members of the type."""
        if attr in ['_concrete_members', 'vol']:
            raise AttributeError("Object has not been properly initialized")
        if attr in self._concrete_members:
            return self._concrete_members[attr]
        elif attr in self.vol.members:
            mask = self._context.layers[self.vol.layer_name].address_mask
            relative_offset, template = self.vol.members[attr]
            if isinstance(template, templates.ReferenceTemplate):
                template = self._context.symbol_space.get_type(template.vol.type_name)
            object_info = interfaces.objects.ObjectInformation(layer_name = self.vol.layer_name,
                                                               offset = mask & (self.vol.offset + relative_offset),
                                                               member_name = attr,
                                                               parent = self,
                                                               native_layer_name = self.vol.native_layer_name,
                                                               size = template.size)
            member = template(context = self._context, object_info = object_info)
            self._concrete_members[attr] = member
            return member
        # We duplicate this code to avoid polluting the methodspace
        agg_name = 'AggregateType'
        for agg_type in AggregateTypes:
            if isinstance(self, agg_type):
                agg_name = agg_type.__name__
        raise AttributeError("{} has no attribute: {}.{}".format(agg_name, self.vol.type_name, attr))


Returns a complete list of members when dir is called .

def __dir__(self) -> Iterable[str]:
        """Returns a complete list of members when dir is called."""
        return list(super().__dir__()) + list(self.vol.members)

def __dir__ ( self ) -> Iterable [ str ] : return list ( super ( ) . __dir__ ( ) ) + list ( self . vol . members )


Takes a volatility Array of characters and returns a string .

def array_to_string(array: 'objects.Array',
                    count: Optional[int] = None,
                    errors: str = 'replace') -> interfaces.objects.ObjectInterface:
    """Takes a volatility Array of characters and returns a string."""
    # TODO: Consider checking the Array's target is a native char
    if count is None:
        count = array.vol.count
    if not isinstance(array, objects.Array):
        raise TypeError("Array_to_string takes an Array of char")

    return array.cast("string", max_length = count, errors = errors)


Takes a volatility Pointer to characters and returns a string .

def pointer_to_string(pointer: 'objects.Pointer', count: int, errors: str = 'replace'):
    """Takes a volatility Pointer to characters and returns a string."""
    if not isinstance(pointer, objects.Pointer):
        raise TypeError("pointer_to_string takes a Pointer")
    if count < 1:
        raise ValueError("pointer_to_string requires a positive count")
    char = pointer.dereference()
    return char.cast("string", max_length = count, errors = errors)


Takes an object and recasts it as an array of pointers to subtype .

def array_of_pointers(array: interfaces.objects.ObjectInterface, count: int,
                      subtype: Union[str, interfaces.objects.Template],
                      context: interfaces.context.ContextInterface) -> interfaces.objects.ObjectInterface:
    """Takes an object, and recasts it as an array of pointers to subtype."""
    symbol_table = array.vol.type_name.split(constants.BANG)[0]
    if isinstance(subtype, str) and context is not None:
        subtype = context.symbol_space.get_type(subtype)
    if not isinstance(subtype, interfaces.objects.Template) or subtype is None:
        raise TypeError("Subtype must be a valid template (or string name of an object template)")
    subtype_pointer = context.symbol_space.get_type(symbol_table + constants.BANG + "pointer")
    subtype_pointer.update_vol(subtype = subtype)
    return array.cast("array", count = count, subtype = subtype_pointer)


Returns the children of the templated object ( see : class : ~volatilit y . framework . interfaces . objects . ObjectInterface . VolTemplateProxy )

def size(self) -> int:
        """Returns the children of the templated object (see :class:`~volatilit
        y.framework.interfaces.objects.ObjectInterface.VolTemplateProxy`)"""
        return self.vol.object_class.VolTemplateProxy.size(self)

def size ( self ) -> int : return self . vol . object_class . VolTemplateProxy . size ( self )


def children(self) -> List[interfaces.objects.Template]:
        """Returns the children of the templated object (see :class:`~volatilit
        y.framework.interfaces.objects.ObjectInterface.VolTemplateProxy`)"""
        return self.vol.object_class.VolTemplateProxy.children(self)

def children ( self ) -> List [ interfaces . objects . Template ] : return self . vol . object_class . VolTemplateProxy . children ( self )


Returns the relative offset of a child of the templated object ( see : class : ~volatility . framework . interfaces . objects . ObjectInterface . VolTem plateProxy )

def relative_child_offset(self, child: str) -> int:
        """Returns the relative offset of a child of the templated object (see
        :class:`~volatility.framework.interfaces.objects.ObjectInterface.VolTem
        plateProxy`)"""
        return self.vol.object_class.VolTemplateProxy.relative_child_offset(self, child)

def relative_child_offset ( self , child : str ) -> int : return self . vol . object_class . VolTemplateProxy . relative_child_offset ( self , child )


Replaces old_child for new_child in the templated object s child list ( see : class : ~volatility . framework . interfaces . objects . ObjectInterf ace . VolTemplateProxy )

def replace_child(self, old_child: interfaces.objects.Template, new_child: interfaces.objects.Template) -> None:
        """Replaces `old_child` for `new_child` in the templated object's child
        list (see :class:`~volatility.framework.interfaces.objects.ObjectInterf
        ace.VolTemplateProxy`)"""
        return self.vol.object_class.VolTemplateProxy.replace_child(self, old_child, new_child)

def replace_child ( self , old_child : interfaces . objects . Template , new_child : interfaces . objects . Template ) -> None : return self . vol . object_class . VolTemplateProxy . replace_child ( self , old_child , new_child )


def has_member(self, member_name: str) -> bool:
        """Returns whether the object would contain a member called
        member_name."""
        return self.vol.object_class.VolTemplateProxy.has_member(self, member_name)

def has_member ( self , member_name : str ) -> bool : return self . vol . object_class . VolTemplateProxy . has_member ( self , member_name )


def __call__(self, context: interfaces.context.ContextInterface,
                 object_info: interfaces.objects.ObjectInformation) -> interfaces.objects.ObjectInterface:
        """Constructs the object.

        Returns: an object adhereing to the :class:`~volatility.framework.interfaces.objects.ObjectInterface`
        """
        arguments = {}  # type: Dict[str, Any]
        for arg in self.vol:
            if arg != 'object_class':
                arguments[arg] = self.vol[arg]
        return self.vol.object_class(context = context, object_info = object_info, **arguments)

def
__call__
(
self
,
context
:
interfaces
.
context
.
ContextInterface
,
object_info
:
interfaces
.
objects
.
ObjectInformation
)
->
interfaces
.
objects
.
ObjectInterface
:
arguments
=
{
}
# type: Dict[str, Any]
for
arg
in
self
.
vol
:
if
arg
!=
'object_class'
:
arguments
[
arg
]
=
self
.
vol
[
arg
]
return
self
.
vol
.
object_class
(
context
=
context
,
object_info
=
object_info
,
*
*
arguments
)


Referenced symbols must be appropriately resolved before they can provide information such as size This is because the size request has no context within which to determine the actual symbol structure .

def _unresolved(self, *args, **kwargs) -> Any:
        """Referenced symbols must be appropriately resolved before they can
        provide information such as size This is because the size request has
        no context within which to determine the actual symbol structure."""
        type_name = self.vol.type_name.split(constants.BANG)
        table_name = None
        if len(type_name) == 2:
            table_name = type_name[0]
        symbol_name = type_name[-1]
        raise exceptions.SymbolError(
            symbol_name, table_name,
            "Template contains no information about its structure: {}".format(self.vol.type_name))


Returns an ordered list of all subclasses of : class : ~volatility . framework . interfaces . automagic . AutomagicInterface .

def available(context: interfaces.context.ContextInterface) -> List[interfaces.automagic.AutomagicInterface]:
    """Returns an ordered list of all subclasses of
    :class:`~volatility.framework.interfaces.automagic.AutomagicInterface`.

    The order is based on the priority attributes of the subclasses, in order to ensure the automagics are listed in
    an appropriate order.

    Args:
        context: The context that will contain any automagic configuration values.
    """
    import_files(sys.modules[__name__])
    config_path = constants.AUTOMAGIC_CONFIG_PATH
    return sorted([
        clazz(context, interfaces.configuration.path_join(config_path, clazz.__name__))
        for clazz in class_subclasses(interfaces.automagic.AutomagicInterface)
    ],
                  key = lambda x: x.priority)

def available ( context : interfaces . context . ContextInterface ) -> List [ interfaces . automagic . AutomagicInterface ] : import_files ( sys . modules [ __name__ ] ) config_path = constants . AUTOMAGIC_CONFIG_PATH return sorted ( [ clazz ( context , interfaces . configuration . path_join ( config_path , clazz . __name__ ) ) for clazz in class_subclasses ( interfaces . automagic . AutomagicInterface ) ] , key = lambda x : x . priority )


Chooses which automagics to run maintaining the order they were handed in .

def choose_automagic(
        automagics: List[interfaces.automagic.AutomagicInterface],
        plugin: Type[interfaces.plugins.PluginInterface]) -> List[Type[interfaces.automagic.AutomagicInterface]]:
    """Chooses which automagics to run, maintaining the order they were handed
    in."""

    plugin_category = "None"
    plugin_categories = plugin.__module__.split('.')
    lowest_index = len(plugin_categories)

    automagic_categories = {'windows': windows_automagic, 'linux': linux_automagic, 'mac': mac_automagic}

    for os in automagic_categories:
        try:
            if plugin_categories.index(os) < lowest_index:
                lowest_index = plugin_categories.index(os)
                plugin_category = os
        except ValueError:
            # The value wasn't found, try the next one
            pass

    if plugin_category not in automagic_categories:
        vollog.info("No plugin category detected")
        return automagics

    vollog.info("Detected a {} category plugin".format(plugin_category))
    output = []
    for amagic in automagics:
        if amagic.__class__.__name__ in automagic_categories[plugin_category]:
            output += [amagic]
    return output


Runs through the list of automagics in order allowing them to make changes to the context .

def run(automagics: List[interfaces.automagic.AutomagicInterface],
        context: interfaces.context.ContextInterface,
        configurable: Union[interfaces.configuration.ConfigurableInterface,
                            Type[interfaces.configuration.ConfigurableInterface]],
        config_path: str,
        progress_callback: constants.ProgressCallback = None) -> List[traceback.TracebackException]:
    """Runs through the list of `automagics` in order, allowing them to make
    changes to the context.

    Args:
        automagics: A list of :class:`~volatility.framework.interfaces.automagic.AutomagicInterface` objects
        context: The context (that inherits from :class:`~volatility.framework.interfaces.context.ContextInterface`) for modification
        configurable: An object that inherits from :class:`~volatility.framework.interfaces.configuration.ConfigurableInterface`
        config_path: The path within the `context.config` for options required by the `configurable`
        progress_callback: A function that takes a percentage (and an optional description) that will be called periodically

    This is where any automagic is allowed to run, and alter the context in order to satisfy/improve all requirements

    Returns a list of traceback objects that occurred during the autorun procedure

    Note:
        The order of the `automagics` list is important.  An `automagic` that populates configurations may be necessary
        for an `automagic` that populates the context based on the configuration information.
    """
    for automagic in automagics:
        if not isinstance(automagic, interfaces.automagic.AutomagicInterface):
            raise TypeError("Automagics must only contain AutomagicInterface subclasses")

    if (not isinstance(configurable, interfaces.configuration.ConfigurableInterface)
            and not issubclass(configurable, interfaces.configuration.ConfigurableInterface)):
        raise TypeError("Automagic operates on configurables only")

    # TODO: Fix need for top level config element just because we're using a MultiRequirement to group the
    # configurable's config requirements
    # configurable_class: Type[interfaces.configuration.ConfigurableInterface]
    if isinstance(configurable, interfaces.configuration.ConfigurableInterface):
        configurable_class = configurable.__class__
    else:
        configurable_class = configurable
    requirement = requirements.MultiRequirement(name = configurable_class.__name__)
    for req in configurable.get_requirements():
        requirement.add_requirement(req)

    exceptions = []

    for automagic in automagics:
        try:
            vollog.info("Running automagic: {}".format(automagic.__class__.__name__))
            automagic(context, config_path, requirement, progress_callback)
        except Exception as excp:
            exceptions.append(traceback.TracebackException.from_exception(excp))
    return exceptions


Traverses the requirement tree rooted at requirement looking for virtual layers that might contain a windows PDB .

def find_virtual_layers_from_req(self, context: interfaces.context.ContextInterface, config_path: str,
                                     requirement: interfaces.configuration.RequirementInterface) -> List[str]:
        """Traverses the requirement tree, rooted at `requirement` looking for
        virtual layers that might contain a windows PDB.

        Returns a list of possible layers

        Args:
            context: The context in which the `requirement` lives
            config_path: The path within the `context` for the `requirement`'s configuration variables
            requirement: The root of the requirement tree to search for :class:~`volatility.framework.interfaces.layers.TranslationLayerRequirement` objects to scan
            progress_callback: Means of providing the user with feedback during long processes

        Returns:
            A list of (layer_name, scan_results)
        """
        sub_config_path = interfaces.configuration.path_join(config_path, requirement.name)
        results = []  # type: List[str]
        if isinstance(requirement, requirements.TranslationLayerRequirement):
            # Check for symbols in this layer
            # FIXME: optionally allow a full (slow) scan
            # FIXME: Determine the physical layer no matter the virtual layer
            virtual_layer_name = context.config.get(sub_config_path, None)
            layer_name = context.config.get(interfaces.configuration.path_join(sub_config_path, "memory_layer"), None)
            if layer_name and virtual_layer_name:
                memlayer = context.layers[virtual_layer_name]
                if isinstance(memlayer, intel.Intel):
                    results = [virtual_layer_name]
        else:
            for subreq in requirement.requirements.values():
                results += self.find_virtual_layers_from_req(context, sub_config_path, subreq)
        return results


Fulfills the SymbolTableRequirements in self . _symbol_requirements found by the recurse_symbol_requirements .

def recurse_symbol_fulfiller(self,
                                 context: interfaces.context.ContextInterface,
                                 valid_kernel: ValidKernelType,
                                 progress_callback: constants.ProgressCallback = None) -> None:
        """Fulfills the SymbolTableRequirements in `self._symbol_requirements`
        found by the `recurse_symbol_requirements`.

        This pass will construct any requirements that may need it in the context it was passed

        Args:
            context: Context on which to operate
            valid_kernel: A list of offsets where valid kernels have been found
        """
        for sub_config_path, requirement in self._symbol_requirements:
            # TODO: Potentially think about multiple symbol requirements in both the same and different levels of the requirement tree
            # TODO: Consider whether a single found kernel can fulfill multiple requirements
            if valid_kernel:
                # TODO: Check that the symbols for this kernel will fulfill the requirement
                virtual_layer, _kvo, kernel = valid_kernel
                if not isinstance(kernel['pdb_name'], str) or not isinstance(kernel['GUID'], str):
                    raise TypeError("PDB name or GUID not a string value")

                PDBUtility.load_windows_symbol_table(
                    context = context,
                    guid = kernel['GUID'],
                    age = kernel['age'],
                    pdb_name = kernel['pdb_name'],
                    symbol_table_class = "volatility.framework.symbols.windows.WindowsKernelIntermedSymbols",
                    config_path = sub_config_path,
                    progress_callback = progress_callback)
            else:
                vollog.debug("No suitable kernel pdb signature found")


Traverses the requirement tree looking for kernel_virtual_offset values that may need setting and sets it based on the previously identified valid_kernel .

def set_kernel_virtual_offset(self, context: interfaces.context.ContextInterface,
                                  valid_kernel: ValidKernelType) -> None:
        """Traverses the requirement tree, looking for kernel_virtual_offset
        values that may need setting and sets it based on the previously
        identified `valid_kernel`.

        Args:
            context: Context on which to operate and provide the kernel virtual offset
            valid_kernel: List of valid kernels and offsets
        """
        if valid_kernel:
            # Set the virtual offset under the TranslationLayer it applies to
            virtual_layer, kvo, kernel = valid_kernel
            kvo_path = interfaces.configuration.path_join(context.layers[virtual_layer].config_path,
                                                          'kernel_virtual_offset')
            context.config[kvo_path] = kvo
            vollog.debug("Setting kernel_virtual_offset to {}".format(hex(kvo)))


Method for finding a suitable kernel offset based on a module table .

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

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

            if valid_kernel:
                break
        return valid_kernel


def check_kernel_offset(self,
                            context: interfaces.context.ContextInterface,
                            vlayer: layers.intel.Intel,
                            address: int,
                            progress_callback: constants.ProgressCallback = None) -> Optional[ValidKernelType]:
        """Scans a virtual address."""
        # Scan a few megs of the virtual space at the location to see if they're potential kernels

        valid_kernel = None  # type: Optional[ValidKernelType]
        kernel_pdb_names = [bytes(name + ".pdb", "utf-8") for name in constants.windows.KERNEL_MODULE_NAMES]

        virtual_layer_name = vlayer.name
        try:
            if vlayer.read(address, 0x2) == b'MZ':
                res = list(
                    PDBUtility.pdbname_scan(ctx = context,
                                            layer_name = vlayer.name,
                                            page_size = vlayer.page_size,
                                            pdb_names = kernel_pdb_names,
                                            progress_callback = progress_callback,
                                            start = address,
                                            end = address + self.max_pdb_size))
                if res:
                    valid_kernel = (virtual_layer_name, address, res[0])
        except exceptions.InvalidAddressException:
            pass
        return valid_kernel


Runs through the identified potential kernels and verifies their suitability .

def determine_valid_kernel(self,
                               context: interfaces.context.ContextInterface,
                               potential_layers: List[str],
                               progress_callback: constants.ProgressCallback = None) -> Optional[ValidKernelType]:
        """Runs through the identified potential kernels and verifies their
        suitability.

        This carries out a scan using the pdb_signature scanner on a physical layer.  It uses the
        results of the scan to determine the virtual offset of the kernel.  On early windows implementations
        there is a fixed mapping between the physical and virtual addresses of the kernel.  On more recent versions
        a search is conducted for a structure that will identify the kernel's virtual offset.

        Args:
            context: Context on which to operate
            potential_kernels: Dictionary containing `GUID`, `age`, `pdb_name` and `mz_offset` keys
            progress_callback: Function taking a percentage and optional description to be called during expensive computations to indicate progress

        Returns:
            A dictionary of valid kernels
        """
        valid_kernel = None  # type: Optional[ValidKernelType]
        for virtual_layer_name in potential_layers:
            vlayer = context.layers.get(virtual_layer_name, None)
            if isinstance(vlayer, layers.intel.Intel):
                for method in self.methods:
                    valid_kernel = method(self, context, vlayer, progress_callback)
                    if valid_kernel:
                        break
        if not valid_kernel:
            vollog.info("No suitable kernels found during pdbscan")
        return valid_kernel


Tests a specific page in a chunk of data to see if it contains a self - referential pointer .

def __call__(self, data: bytes, data_offset: int, page_offset: int) -> Optional[Tuple[int, Any]]:
        """Tests a specific page in a chunk of data to see if it contains a
        self-referential pointer.

        Args:
            data: The chunk of data that contains the page to be scanned
            data_offset: Where, within the layer, the chunk of data lives
            page_offset: Where, within the data, the page to be scanned starts

        Returns:
            A valid DTB within this page (and an additional parameter for data)
        """
        value = data[page_offset + (self.ptr_reference * self.ptr_size):page_offset +
                     ((self.ptr_reference + 1) * self.ptr_size)]
        try:
            ptr = self._unpack(value)
        except struct.error:
            return None
        # The value *must* be present (bit 0) since it's a mapped page
        # It's almost always writable (bit 1)
        # It's occasionally Super, but not reliably so, haven't checked when/why not
        # The top 3-bits are usually ignore (which in practice means 0
        # Need to find out why the middle 3-bits are usually 6 (0110)
        if ptr != 0 and (ptr & self.mask == data_offset + page_offset) & (ptr & 0xFF1 == 0x61):
            dtb = (ptr & self.mask)
            return self.second_pass(dtb, data, data_offset)
        return None


Re - reads over the whole page to validate other records based on the number of pages marked user vs super .

def second_pass(self, dtb: int, data: bytes, data_offset: int) -> Optional[Tuple[int, Any]]:
        """Re-reads over the whole page to validate other records based on the
        number of pages marked user vs super.

        Args:
            dtb: The identified dtb that needs validating
            data: The chunk of data that contains the dtb to be validated
            data_offset: Where, within the layer, the chunk of data lives

        Returns:
            A valid DTB within this page
        """
        page = data[dtb - data_offset:dtb - data_offset + self.page_size]
        usr_count, sup_count = 0, 0
        for i in range(0, self.page_size, self.ptr_size):
            val = self._unpack(page[i:i + self.ptr_size])
            if val & 0x1:
                sup_count += 0 if (val & 0x4) else 1
                usr_count += 1 if (val & 0x4) else 0
        # print(hex(dtb), usr_count, sup_count, usr_count + sup_count)
        # We sometimes find bogus DTBs at 0x16000 with a very low sup_count and 0 usr_count
        # I have a winxpsp2-x64 image with identical usr/sup counts at 0x16000 and 0x24c00 as well as the actual 0x3c3000
        if usr_count or sup_count > 5:
            return dtb, None
        return None


PAE top level directory tables contains four entries and the self - referential pointer occurs in the second level of tables ( so as not to use up a full quarter of the space ) . This is very high in the space and occurs in the fourht ( last quarter ) second - level table . The second - level tables appear always to come sequentially directly after the real dtb . The value for the real DTB is therefore four page earlier ( and the fourth entry should point back to the dtb parameter this function was originally passed .

def second_pass(self, dtb: int, data: bytes, data_offset: int) -> Optional[Tuple[int, Any]]:
        """PAE top level directory tables contains four entries and the self-
        referential pointer occurs in the second level of tables (so as not to
        use up a full quarter of the space).  This is very high in the space,
        and occurs in the fourht (last quarter) second-level table.  The
        second-level tables appear always to come sequentially directly after
        the real dtb.  The value for the real DTB is therefore four page
        earlier (and the fourth entry should point back to the `dtb` parameter
        this function was originally passed.

        Args:
            dtb: The identified self-referential pointer that needs validating
            data: The chunk of data that contains the dtb to be validated
            data_offset: Where, within the layer, the chunk of data lives

        Returns:
            Returns the actual DTB of the PAE space
        """
        dtb -= 0x4000
        # If we're not in something that the overlap would pick up
        if dtb - data_offset >= 0:
            pointers = data[dtb - data_offset + (3 * self.ptr_size):dtb - data_offset + (4 * self.ptr_size)]
            val = self._unpack(pointers)
            if (val & self.mask == dtb + 0x4000) and (val & 0xFFF == 0x001):
                return dtb, None
        return None


Attempts to determine and stack an intel layer on a physical layer where possible .

def stack(cls,
              context: interfaces.context.ContextInterface,
              layer_name: str,
              progress_callback: constants.ProgressCallback = None) -> Optional[interfaces.layers.DataLayerInterface]:
        """Attempts to determine and stack an intel layer on a physical layer
        where possible.

        Where the DTB scan fails, it attempts a heuristic of checking
        for the DTB within a specific range. New versions of windows,
        with randomized self-referential pointers, appear to always load
        their dtb within a small specific range (`0x1a0000` and
        `0x1b0000`), so instead we scan for all self-referential
        pointers in that range, and ignore any that contain multiple
        self-references (since the DTB is very unlikely to point to
        itself more than once).
        """
        base_layer = context.layers[layer_name]
        if isinstance(base_layer, intel.Intel):
            return None
        if base_layer.metadata.get('os', None) not in ['Windows', 'Unknown']:
            return None
        layer = config_path = None

        # Check the metadata
        if (base_layer.metadata.get('os', None) == 'Windows' and base_layer.metadata.get('page_map_offset')):
            arch = base_layer.metadata.get('architecture', None)
            if arch not in ['Intel32', 'Intel64']:
                return None
            # Set the layer type
            layer_type = intel.WindowsIntel  # type: Type
            if arch == 'Intel64':
                layer_type = intel.WindowsIntel32e
            elif base_layer.metadata.get('pae', False):
                layer_type = intel.WindowsIntelPAE
            # Construct the layer
            new_layer_name = context.layers.free_layer_name("IntelLayer")
            config_path = interfaces.configuration.path_join("IntelHelper", new_layer_name)
            context.config[interfaces.configuration.path_join(config_path, "memory_layer")] = layer_name
            context.config[interfaces.configuration.path_join(
                config_path, "page_map_offset")] = base_layer.metadata['page_map_offset']
            layer = layer_type(context, config_path = config_path, name = new_layer_name, metadata = {'os': 'Windows'})

        # Check for the self-referential pointer
        if layer is None:
            hits = base_layer.scan(context, PageMapScanner(WintelHelper.tests))
            layer = None
            config_path = None
            for test, dtb in hits:
                new_layer_name = context.layers.free_layer_name("IntelLayer")
                config_path = interfaces.configuration.path_join("IntelHelper", new_layer_name)
                context.config[interfaces.configuration.path_join(config_path, "memory_layer")] = layer_name
                context.config[interfaces.configuration.path_join(config_path, "page_map_offset")] = dtb
                layer = test.layer_type(context,
                                        config_path = config_path,
                                        name = new_layer_name,
                                        metadata = {'os': 'Windows'})
                break

        # Fall back to a heuristic for finding the Windows DTB
        if layer is None:
            vollog.debug("Self-referential pointer not in well-known location, moving to recent windows heuristic")
            # There is a very high chance that the DTB will live in this narrow segment, assuming we couldn't find it previously
            hits = context.layers[layer_name].scan(context,
                                                   PageMapScanner([DtbSelfRef64bit()]),
                                                   sections = [(0x1a0000, 0x50000)],
                                                   progress_callback = progress_callback)
            # Flatten the generator
            hits = list(hits)
            if hits:
                # TODO: Decide which to use if there are multiple options
                test, page_map_offset = hits[0]
                new_layer_name = context.layers.free_layer_name("IntelLayer")
                config_path = interfaces.configuration.path_join("IntelHelper", new_layer_name)
                context.config[interfaces.configuration.path_join(config_path, "memory_layer")] = layer_name
                context.config[interfaces.configuration.path_join(config_path, "page_map_offset")] = page_map_offset
                # TODO: Need to determine the layer type (chances are high it's x64, hence this default)
                layer = layers.intel.WindowsIntel32e(context,
                                                     config_path = config_path,
                                                     name = new_layer_name,
                                                     metadata = {'os': 'Windows'})
        if layer is not None and config_path:
            vollog.debug("DTB was found at: 0x{:0x}".format(context.config[interfaces.configuration.path_join(
                config_path, "page_map_offset")]))
        return layer


Finds translation layers that can have swap layers added .

def __call__(self,
                 context: interfaces.context.ContextInterface,
                 config_path: str,
                 requirement: interfaces.configuration.RequirementInterface,
                 progress_callback: constants.ProgressCallback = None) -> None:
        """Finds translation layers that can have swap layers added."""
        path_join = interfaces.configuration.path_join
        self._translation_requirement = self.find_requirements(context,
                                                               config_path,
                                                               requirement,
                                                               requirements.TranslationLayerRequirement,
                                                               shortcut = False)
        for trans_sub_config, trans_req in self._translation_requirement:
            if not isinstance(trans_req, requirements.TranslationLayerRequirement):
                # We need this so the type-checker knows we're a TranslationLayerRequirement
                continue
            swap_sub_config, swap_req = self.find_swap_requirement(trans_sub_config, trans_req)
            counter = 0
            swap_config = interfaces.configuration.parent_path(swap_sub_config)

            if swap_req and swap_req.unsatisfied(context, swap_config):
                # See if any of them need constructing
                for swap_location in self.config.get('single_swap_locations', []):
                    # Setup config locations/paths
                    current_layer_name = swap_req.name + str(counter)
                    current_layer_path = path_join(swap_sub_config, current_layer_name)
                    layer_loc_path = path_join(current_layer_path, "location")
                    layer_class_path = path_join(current_layer_path, "class")
                    counter += 1

                    # Fill in the config
                    if swap_location:
                        context.config[current_layer_path] = current_layer_name
                        context.config[layer_loc_path] = swap_location
                        context.config[layer_class_path] = 'volatility.framework.layers.physical.FileLayer'

                    # Add the requirement
                    new_req = requirements.TranslationLayerRequirement(name = current_layer_name,
                                                                       description = "Swap Layer",
                                                                       optional = False)
                    swap_req.add_requirement(new_req)

                context.config[path_join(swap_sub_config, 'number_of_elements')] = counter
                context.config[swap_sub_config] = True

                swap_req.construct(context, swap_config)


Takes a Translation layer and returns its swap_layer requirement .

def find_swap_requirement(config: str,
                              requirement: requirements.TranslationLayerRequirement) \
            -> Tuple[str, Optional[requirements.LayerListRequirement]]:
        """Takes a Translation layer and returns its swap_layer requirement."""
        swap_req = None
        for req_name in requirement.requirements:
            req = requirement.requirements[req_name]
            if isinstance(req, requirements.LayerListRequirement) and req.name == 'swap_layers':
                swap_req = req
                continue

        swap_config = interfaces.configuration.path_join(config, 'swap_layers')
        return swap_config, swap_req

def find_swap_requirement ( config : str , requirement : requirements . TranslationLayerRequirement ) -> Tuple [ str , Optional [ requirements . LayerListRequirement ] ] : swap_req = None for req_name in requirement . requirements : req = requirement . requirements [ req_name ] if isinstance ( req , requirements . LayerListRequirement ) and req . name == 'swap_layers' : swap_req = req continue swap_config = interfaces . configuration . path_join ( config , 'swap_layers' ) return swap_config , swap_req


Returns the requirements of this plugin .

def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]:
        """Returns the requirements of this plugin."""
        return [
            requirements.ListRequirement(
                name = "single_swap_locations",
                element_type = str,
                min_elements = 0,
                max_elements = 16,
                description = "Specifies a list of swap layer URIs for use with single-location",
                optional = True)
        ]


Attempts to identify linux within this layer .

def stack(cls,
              context: interfaces.context.ContextInterface,
              layer_name: str,
              progress_callback: constants.ProgressCallback = None) -> Optional[interfaces.layers.DataLayerInterface]:
        """Attempts to identify linux within this layer."""
        # Bail out by default unless we can stack properly
        layer = context.layers[layer_name]
        join = interfaces.configuration.path_join

        # Never stack on top of an intel layer
        # FIXME: Find a way to improve this check
        if isinstance(layer, intel.Intel):
            return None

        linux_banners = LinuxBannerCache.load_banners()
        # If we have no banners, don't bother scanning
        if not linux_banners:
            vollog.info("No Linux banners found - if this is a linux plugin, please check your symbol files location")
            return None

        mss = scanners.MultiStringScanner([x for x in linux_banners if x is not None])
        for _, banner in layer.scan(context = context, scanner = mss, progress_callback = progress_callback):
            dtb = None
            vollog.debug("Identified banner: {}".format(repr(banner)))

            symbol_files = linux_banners.get(banner, None)
            if symbol_files:
                isf_path = symbol_files[0]
                table_name = context.symbol_space.free_table_name('LintelStacker')
                table = linux.LinuxKernelIntermedSymbols(context,
                                                         'temporary.' + table_name,
                                                         name = table_name,
                                                         isf_url = isf_path)
                context.symbol_space.append(table)
                kaslr_shift, aslr_shift = cls.find_aslr(context,
                                                        table_name,
                                                        layer_name,
                                                        progress_callback = progress_callback)

                layer_class = intel.Intel  # type: Type
                if 'init_top_pgt' in table.symbols:
                    layer_class = intel.Intel32e
                    dtb_symbol_name = 'init_top_pgt'
                elif 'init_level4_pgt' in table.symbols:
                    layer_class = intel.Intel32e
                    dtb_symbol_name = 'init_level4_pgt'
                else:
                    dtb_symbol_name = 'swapper_pg_dir'

                dtb = cls.virtual_to_physical_address(table.get_symbol(dtb_symbol_name).address + kaslr_shift)

                # Build the new layer
                new_layer_name = context.layers.free_layer_name("IntelLayer")
                config_path = join("IntelHelper", new_layer_name)
                context.config[join(config_path, "memory_layer")] = layer_name
                context.config[join(config_path, "page_map_offset")] = dtb
                context.config[join(config_path, LinuxSymbolFinder.banner_config_key)] = str(banner, 'latin-1')

                layer = layer_class(context,
                                    config_path = config_path,
                                    name = new_layer_name,
                                    metadata = {'kaslr_value': aslr_shift})

            if layer and dtb:
                vollog.debug("DTB was found at: 0x{:0x}".format(dtb))
                return layer
        return None


Determines the offset of the actual DTB in physical space and its symbol offset .

def find_aslr(cls,
                  context: interfaces.context.ContextInterface,
                  symbol_table: str,
                  layer_name: str,
                  progress_callback: constants.ProgressCallback = None) \
            -> Tuple[int, int]:
        """Determines the offset of the actual DTB in physical space and its
        symbol offset."""
        init_task_symbol = symbol_table + constants.BANG + 'init_task'
        init_task_json_address = context.symbol_space.get_symbol(init_task_symbol).address
        swapper_signature = rb"swapper(\/0|\x00\x00)\x00\x00\x00\x00\x00\x00"
        module = context.module(symbol_table, layer_name, 0)
        address_mask = context.symbol_space[symbol_table].config.get('symbol_mask', None)

        task_symbol = module.get_type('task_struct')
        comm_child_offset = task_symbol.relative_child_offset('comm')

        for offset in context.layers[layer_name].scan(scanner = scanners.RegExScanner(swapper_signature),
                                                      context = context,
                                                      progress_callback = progress_callback):
            init_task_address = offset - comm_child_offset
            init_task = module.object(object_type = 'task_struct', offset = init_task_address, absolute = True)
            if init_task.pid != 0:
                continue
            elif init_task.has_member('state') and init_task.state.cast('unsigned int') != 0:
                continue

            # This we get for free
            aslr_shift = init_task.files.cast('long unsigned int') - module.get_symbol('init_files').address
            kaslr_shift = init_task_address - cls.virtual_to_physical_address(init_task_json_address)
            if address_mask:
                aslr_shift = aslr_shift & address_mask

            if aslr_shift & 0xfff != 0 or kaslr_shift & 0xfff != 0:
                continue
            vollog.debug("Linux ASLR shift values determined: physical {:0x} virtual {:0x}".format(
                kaslr_shift, aslr_shift))
            return kaslr_shift, aslr_shift

        # We don't throw an exception, because we may legitimately not have an ASLR shift, but we report it
        vollog.debug("Scanners could not determine any ASLR shifts, using 0 for both")
        return 0, 0


Converts a virtual linux address to a physical one ( does not account of ASLR )

def virtual_to_physical_address(cls, addr: int) -> int:
        """Converts a virtual linux address to a physical one (does not account
        of ASLR)"""
        if addr > 0xffffffff80000000:
            return addr - 0xffffffff80000000
        return addr - 0xc0000000

def virtual_to_physical_address ( cls , addr : int ) -> int : if addr > 0xffffffff80000000 : return addr - 0xffffffff80000000 return addr - 0xc0000000


Runs the automagic over the configurable .

def __call__(self, context, config_path, configurable, progress_callback = None):
        """Runs the automagic over the configurable."""

        # Bomb out if we're just the generic interface
        if self.os is None:
            return

        # We only need to be called once, so no recursion necessary
        banners = self.load_banners()

        cacheables = list(intermed.IntermediateSymbolTable.file_symbol_url(self.os))

        for banner in banners:
            for json_file in banners[banner]:
                if json_file in cacheables:
                    cacheables.remove(json_file)

        total = len(cacheables)
        if total > 0:
            vollog.info("Building {} caches...".format(self.os))
        for current in range(total):
            if progress_callback is not None:
                progress_callback(current * 100 / total, "Building {} caches".format(self.os))
            isf_url = cacheables[current]

            isf = None
            try:
                # Loading the symbol table will be very slow until it's been validated
                isf = intermed.IntermediateSymbolTable(context, config_path, "temp", isf_url, validate = False)

                # We should store the banner against the filename
                # We don't bother with the hash (it'll likely take too long to validate)
                # but we should check at least that the banner matches on load.
                banner = isf.get_symbol(self.symbol_name).constant_data
                vollog.log(constants.LOGLEVEL_VV, "Caching banner {} for file {}".format(banner, isf_url))

                bannerlist = banners.get(banner, [])
                bannerlist.append(isf_url)
                banners[banner] = bannerlist
            except exceptions.SymbolError:
                pass
            except json.JSONDecodeError:
                vollog.log(constants.LOGLEVEL_VV, "Caching file {} failed due to JSON error".format(isf_url))
            finally:
                # Get rid of the loaded file, in case it sits in memory
                if isf:
                    del isf
                    gc.collect()

        # Rewrite the cached banners each run, since writing is faster than the banner_cache validation portion
        self.save_banners(banners)

        if progress_callback is not None:
            progress_callback(100, "Built {} caches".format(self.os))


Attempts to identify mac within this layer .

def stack(cls,
              context: interfaces.context.ContextInterface,
              layer_name: str,
              progress_callback: constants.ProgressCallback = None) -> Optional[interfaces.layers.DataLayerInterface]:
        """Attempts to identify mac within this layer."""
        # Bail out by default unless we can stack properly
        layer = context.layers[layer_name]
        new_layer = None
        join = interfaces.configuration.path_join

        # Never stack on top of an intel layer
        # FIXME: Find a way to improve this check
        if isinstance(layer, intel.Intel):
            return None

        mac_banners = MacBannerCache.load_banners()
        # If we have no banners, don't bother scanning
        if not mac_banners:
            vollog.info("No Mac banners found - if this is a mac plugin, please check your symbol files location")
            return None

        mss = scanners.MultiStringScanner([x for x in mac_banners if x])
        for banner_offset, banner in layer.scan(context = context, scanner = mss,
                                                progress_callback = progress_callback):
            dtb = None

            symbol_files = mac_banners.get(banner, None)
            if symbol_files:
                isf_path = symbol_files[0]
                table_name = context.symbol_space.free_table_name('MacintelStacker')
                table = mac.MacKernelIntermedSymbols(context = context,
                                                     config_path = join('temporary', table_name),
                                                     name = table_name,
                                                     isf_url = isf_path)
                context.symbol_space.append(table)
                kaslr_shift = cls.find_aslr(context = context,
                                            symbol_table = table_name,
                                            layer_name = layer_name,
                                            compare_banner = banner,
                                            compare_banner_offset = banner_offset,
                                            progress_callback = progress_callback)

                if kaslr_shift == 0:
                    vollog.log(constants.LOGLEVEL_VVV, "Invalid kalsr_shift found at offset: {}".format(banner_offset))
                    continue

                bootpml4_addr = cls.virtual_to_physical_address(table.get_symbol("BootPML4").address + kaslr_shift)

                new_layer_name = context.layers.free_layer_name("MacDTBTempLayer")
                config_path = join("automagic", "MacIntelHelper", new_layer_name)
                context.config[join(config_path, "memory_layer")] = layer_name
                context.config[join(config_path, "page_map_offset")] = bootpml4_addr

                layer = layers.intel.Intel32e(context,
                                              config_path = config_path,
                                              name = new_layer_name,
                                              metadata = {'os': 'Mac'})

                idlepml4_ptr = table.get_symbol("IdlePML4").address + kaslr_shift
                idlepml4_str = layer.read(idlepml4_ptr, 4)
                idlepml4_addr = struct.unpack("<I", idlepml4_str)[0]

                tmp_dtb = idlepml4_addr

                if tmp_dtb % 4096:
                    vollog.log(constants.LOGLEVEL_VVV, "Skipping non-page aligned DTB: 0x{:0x}".format(tmp_dtb))
                    continue

                dtb = tmp_dtb

                # Build the new layer
                new_layer_name = context.layers.free_layer_name("IntelLayer")
                config_path = join("automagic", "MacIntelHelper", new_layer_name)
                context.config[join(config_path, "memory_layer")] = layer_name
                context.config[join(config_path, "page_map_offset")] = dtb
                context.config[join(config_path, MacSymbolFinder.banner_config_key)] = str(banner, 'latin-1')

                new_layer = intel.Intel32e(context,
                                           config_path = config_path,
                                           name = new_layer_name,
                                           metadata = {'kaslr_value': kaslr_shift})

            if new_layer and dtb:
                vollog.debug("Identified banner: {}".format(repr(banner)))
                vollog.debug("DTB was found at: 0x{:0x}".format(dtb))
                return new_layer
        return None


def find_aslr(cls,
                  context: interfaces.context.ContextInterface,
                  symbol_table: str,
                  layer_name: str,
                  compare_banner: str = "",
                  compare_banner_offset: int = 0,
                  progress_callback: constants.ProgressCallback = None) -> int:
        """Determines the offset of the actual DTB in physical space and its
        symbol offset."""
        version_symbol = symbol_table + constants.BANG + 'version'
        version_json_address = context.symbol_space.get_symbol(version_symbol).address

        version_major_symbol = symbol_table + constants.BANG + 'version_major'
        version_major_json_address = context.symbol_space.get_symbol(version_major_symbol).address
        version_major_phys_offset = cls.virtual_to_physical_address(version_major_json_address)

        version_minor_symbol = symbol_table + constants.BANG + 'version_minor'
        version_minor_json_address = context.symbol_space.get_symbol(version_minor_symbol).address
        version_minor_phys_offset = cls.virtual_to_physical_address(version_minor_json_address)

        if not compare_banner_offset or not compare_banner:
            offset_generator = cls._scan_generator(context, layer_name, progress_callback)
        else:
            offset_generator = [(compare_banner_offset, compare_banner)]

        aslr_shift = 0

        for offset, banner in offset_generator:
            banner_major, banner_minor = [int(x) for x in banner[22:].split(b".")[0:2]]

            tmp_aslr_shift = offset - cls.virtual_to_physical_address(version_json_address)

            major_string = context.layers[layer_name].read(version_major_phys_offset + tmp_aslr_shift, 4)
            major = struct.unpack("<I", major_string)[0]

            if major != banner_major:
                continue

            minor_string = context.layers[layer_name].read(version_minor_phys_offset + tmp_aslr_shift, 4)
            minor = struct.unpack("<I", minor_string)[0]

            if minor != banner_minor:
                continue

            if tmp_aslr_shift & 0xfff != 0:
                continue

            aslr_shift = tmp_aslr_shift & 0xffffffff
            break

        vollog.log(constants.LOGLEVEL_VVVV, "Mac find_aslr returned: {:0x}".format(aslr_shift))

        return aslr_shift

def
find_aslr
(
cls
,
context
:
interfaces
.
context
.
ContextInterface
,
symbol_table
:
str
,
layer_name
:
str
,
compare_banner
:
str
=
""
,
compare_banner_offset
:
int
=
0
,
progress_callback
:
constants
.
ProgressCallback
=
)
->
int
:
version_symbol
=
symbol_table
+
constants
.
BANG
+
'version'
version_json_address
=
context
.
symbol_space
.
get_symbol
(
version_symbol
)
.
address
version_major_symbol
=
symbol_table
+
constants
.
BANG
+
'version_major'
version_major_json_address
=
context
.
symbol_space
.
get_symbol
(
version_major_symbol
)
.
address
version_major_phys_offset
=
cls
.
virtual_to_physical_address
(
version_major_json_address
)
version_minor_symbol
=
symbol_table
+
constants
.
BANG
+
'version_minor'
version_minor_json_address
=
context
.
symbol_space
.
get_symbol
(
version_minor_symbol
)
.
address
version_minor_phys_offset
=
cls
.
virtual_to_physical_address
(
version_minor_json_address
)
if
not
compare_banner_offset
or
not
compare_banner
:
offset_generator
=
cls
.
_scan_generator
(
context
,
layer_name
,
progress_callback
)
else
:
offset_generator
=
[
(
compare_banner_offset
,
compare_banner
)
]
aslr_shift
=
0
for
offset
,
banner
in
offset_generator
:
banner_major
,
banner_minor
=
[
int
(
x
)
for
x
in
banner
[
22
:
]
.
split
(
b"."
)
[
0
:
2
]
]
tmp_aslr_shift
=
offset
cls
.
virtual_to_physical_address
(
version_json_address
)
major_string
=
context
.
layers
[
layer_name
]
.
read
(
version_major_phys_offset
+
tmp_aslr_shift
,
4
)
major
=
struct
.
unpack
(
"<I"
,
major_string
)
[
0
]
if
major
!=
banner_major
:
continue
minor_string
=
context
.
layers
[
layer_name
]
.
read
(
version_minor_phys_offset
+
tmp_aslr_shift
,
4
)
minor
=
struct
.
unpack
(
"<I"
,
minor_string
)
[
0
]
if
minor
!=
banner_minor
:
continue
if
tmp_aslr_shift
&
0xfff
!=
0
:
continue
aslr_shift
=
tmp_aslr_shift
&
0xffffffff
break
vollog
.
log
(
constants
.
LOGLEVEL_VVVV
,
"Mac find_aslr returned: {:0x}"
.
format
(
aslr_shift
)
)
return
aslr_shift


Converts a virtual mac address to a physical one ( does not account of ASLR )

def virtual_to_physical_address(cls, addr: int) -> int:
        """Converts a virtual mac address to a physical one (does not account
        of ASLR)"""
        if addr > 0xffffff8000000000:
            addr = addr - 0xffffff8000000000
        else:
            addr = addr - 0xff8000000000

        return addr

def virtual_to_physical_address ( cls , addr : int ) -> int : if addr > 0xffffff8000000000 : addr = addr - 0xffffff8000000000 else : addr = addr - 0xff8000000000 return addr


Creates a cached copy of the results but only it s been requested .

def banners(self) -> symbol_cache.BannersType:
        """Creates a cached copy of the results, but only it's been
        requested."""
        if not self._banners:
            if not self.banner_cache:
                raise RuntimeError("Cache has not been properly defined for {}".format(self.__class__.__name__))
            self._banners = self.banner_cache.load_banners()
        return self._banners


Searches for SymbolTableRequirements and attempt to populate them .

def __call__(self,
                 context: interfaces.context.ContextInterface,
                 config_path: str,
                 requirement: interfaces.configuration.RequirementInterface,
                 progress_callback: constants.ProgressCallback = None) -> None:
        """Searches for SymbolTableRequirements and attempt to populate
        them."""

        # Bomb out early if our details haven't been configured
        if self.symbol_class is None:
            return

        self._requirements = self.find_requirements(
            context,
            config_path,
            requirement, (requirements.TranslationLayerRequirement, requirements.SymbolTableRequirement),
            shortcut = False)

        for (sub_path, requirement) in self._requirements:
            parent_path = interfaces.configuration.parent_path(sub_path)

            if (isinstance(requirement, requirements.SymbolTableRequirement)
                    and requirement.unsatisfied(context, parent_path)):
                for (tl_sub_path, tl_requirement) in self._requirements:
                    tl_parent_path = interfaces.configuration.parent_path(tl_sub_path)
                    # Find the TranslationLayer sibling to the SymbolTableRequirement
                    if (isinstance(tl_requirement, requirements.TranslationLayerRequirement)
                            and tl_parent_path == parent_path):
                        if context.config.get(tl_sub_path, None):
                            self._banner_scan(context, parent_path, requirement, context.config[tl_sub_path],
                                              progress_callback)
                            break


Accepts a context config_path and SymbolTableRequirement with a constructed layer_name and scans the layer for banners .

def _banner_scan(self,
                     context: interfaces.context.ContextInterface,
                     config_path: str,
                     requirement: interfaces.configuration.ConstructableRequirementInterface,
                     layer_name: str,
                     progress_callback: constants.ProgressCallback = None) -> None:
        """Accepts a context, config_path and SymbolTableRequirement, with a
        constructed layer_name and scans the layer for banners."""

        # Bomb out early if there's no banners
        if not self.banners:
            return

        mss = scanners.MultiStringScanner([x for x in self.banners if x is not None])

        layer = context.layers[layer_name]

        # Check if the Stacker has already found what we're looking for
        if layer.config.get(self.banner_config_key, None):
            banner_list = [(0, bytes(layer.config[self.banner_config_key],
                                     'raw_unicode_escape'))]  # type: Iterable[Any]
        else:
            # Swap to the physical layer for scanning
            # TODO: Fix this so it works for layers other than just Intel
            layer = context.layers[layer.config['memory_layer']]
            banner_list = layer.scan(context = context, scanner = mss, progress_callback = progress_callback)

        for _, banner in banner_list:
            vollog.debug("Identified banner: {}".format(repr(banner)))
            symbol_files = self.banners.get(banner, None)
            if symbol_files:
                isf_path = symbol_files[0]
                vollog.debug("Using symbol library: {}".format(symbol_files[0]))
                clazz = self.symbol_class
                # Set the discovered options
                path_join = interfaces.configuration.path_join
                context.config[path_join(config_path, requirement.name, "class")] = clazz
                context.config[path_join(config_path, requirement.name, "isf_url")] = isf_path
                context.config[path_join(config_path, requirement.name, "symbol_mask")] = layer.address_mask

                # Set a default symbol_shift when attempt to determine it,
                # so we can create the symbols which are used in finding the aslr_shift anyway
                if not context.config.get(path_join(config_path, requirement.name, "symbol_shift"), None):
                    # Don't overwrite it if it's already been set, it will be manually refound if not present
                    prefound_kaslr_value = context.layers[layer_name].metadata.get('kaslr_value', 0)
                    context.config[path_join(config_path, requirement.name, "symbol_shift")] = prefound_kaslr_value
                # Construct the appropriate symbol table
                requirement.construct(context, config_path)

                # Apply the ASLR masking (only if we're not already shifted)
                if self.find_aslr and not context.config.get(path_join(config_path, requirement.name, "symbol_shift"),
                                                             None):
                    unmasked_symbol_table_name = context.config.get(path_join(config_path, requirement.name), None)
                    if not unmasked_symbol_table_name:
                        raise exceptions.SymbolSpaceError("Symbol table could not be constructed")
                    if not isinstance(layer, layers.intel.Intel):
                        raise TypeError("Layer name {} is not an intel space")
                    aslr_shift = self.find_aslr(context, unmasked_symbol_table_name, layer.config['memory_layer'])
                    context.config[path_join(config_path, requirement.name, "symbol_shift")] = aslr_shift
                    context.symbol_space.clear_symbol_cache(unmasked_symbol_table_name)

                break
            else:
                if symbol_files:
                    vollog.debug("Symbol library path not found: {}".format(symbol_files[0]))
                    # print("Kernel", banner, hex(banner_offset))
        else:
            vollog.debug("No existing banners found")


Identifies the stackers that should be run based on the plugin ( and thus os ) provided

def choose_os_stackers(plugin):
    """Identifies the stackers that should be run, based on the plugin (and thus os) provided"""
    plugin_first_level = plugin.__module__.split('.')[2]

    # Ensure all stackers are loaded
    framework.import_files(sys.modules['volatility.framework.layers'])

    result = []
    for stacker in sorted(framework.class_subclasses(interfaces.automagic.StackerLayerInterface),
                          key = lambda x: x.stack_order):
        if plugin_first_level in stacker.exclusion_list:
            continue
        result.append(stacker.__name__)
    return result

def
choose_os_stackers
(
plugin
)
:
plugin_first_level
=
plugin
.
__module__
.
split
(
'.'
)
[
2
]
# Ensure all stackers are loaded
framework
.
import_files
(
sys
.
modules
[
'volatility.framework.layers'
]
)
result
=
[
]
for
stacker
in
sorted
(
framework
.
class_subclasses
(
interfaces
.
automagic
.
StackerLayerInterface
)
,
key
=
lambda
x
:
x
.
stack_order
)
:
if
plugin_first_level
in
stacker
.
exclusion_list
:
continue
result
.
append
(
stacker
.
__name__
)
return
result


def __call__(self,
                 context: interfaces.context.ContextInterface,
                 config_path: str,
                 requirement: interfaces.configuration.RequirementInterface,
                 progress_callback: constants.ProgressCallback = None) -> Optional[List[str]]:
        """Runs the automagic over the configurable."""

        framework.import_files(sys.modules['volatility.framework.layers'])

        # Quick exit if we're not needed
        if not requirement.unsatisfied(context, config_path):
            return None

        # Bow out quickly if the UI hasn't provided a single_location
        unsatisfied = self.unsatisfied(self.context, self.config_path)
        if unsatisfied:
            vollog.info("Unable to run LayerStacker, unsatisfied requirement: {}".format(unsatisfied))
            return list(unsatisfied)
        if not self.config or not self.config.get('single_location', None):
            raise ValueError("Unable to run LayerStacker, single_location parameter not provided")

        # Search for suitable requirements
        self.stack(context, config_path, requirement, progress_callback)

        if progress_callback is not None:
            progress_callback(100, "Stacking attempts finished")
        return None