mirror of
https://github.com/volatilityfoundation/volatility3.git
synced 2026-08-22 06:22:23 +02:00
Layers now accept metadata dictionaries (and chain/stack them on top of those from lower layers). Metadata can only be set at construction time, and the metadata dictionary is readonly. The hope is this will make enumerating metadata keys across the codebase simpler. The current metadata items that layers hold is: architecture (Unknown | Intel32 | Intel64) os (Unknown | Windows | Linux) pae (bool) page_map_offset (int) This patchset may develop further to help enumerate all of these (through a registration/reporting system).
139 lines
6.8 KiB
Python
139 lines
6.8 KiB
Python
import os
|
|
import struct
|
|
import typing
|
|
|
|
from volatility.framework import interfaces, validity
|
|
from volatility.framework.configuration import requirements
|
|
from volatility.framework.layers import physical, segmented
|
|
from volatility.framework.symbols import native
|
|
|
|
|
|
class VmwareLayer(segmented.SegmentedLayer):
|
|
priority = 22
|
|
|
|
header_structure = "<4sII"
|
|
group_structure = "64sQQ"
|
|
|
|
def __init__(self,
|
|
context: interfaces.context.ContextInterface,
|
|
config_path: str,
|
|
name: str,
|
|
metadata: typing.Optional[typing.Dict[str, typing.Any]] = None) -> None:
|
|
# Construct these so we can use self.config
|
|
self._context = context
|
|
self._config_path = config_path
|
|
self._page_size = 0x1000
|
|
self._base_layer, self._meta_layer = self.config["base_layer"], self.config["meta_layer"]
|
|
# Then call the super, which will call load_segments (which needs the base_layer before it'll work)
|
|
super().__init__(context, config_path = config_path, name = name, metadata = metadata)
|
|
|
|
def _load_segments(self) -> None:
|
|
"""Loads up the segments from the meta_layer"""
|
|
self._read_header()
|
|
|
|
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.memory.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 ValueError("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 ValueError("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))
|
|
|
|
@property
|
|
def dependencies(self) -> typing.List[str]:
|
|
return [self._base_layer, self._meta_layer]
|
|
|
|
@classmethod
|
|
def get_requirements(cls) -> typing.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)
|
|
]
|
|
|
|
|
|
class VmwareStacker(interfaces.automagic.StackerLayerInterface):
|
|
@classmethod
|
|
def stack(cls,
|
|
context: interfaces.context.ContextInterface,
|
|
layer_name: str,
|
|
progress_callback: validity.ProgressCallback = None) \
|
|
-> typing.Optional[interfaces.layers.DataLayerInterface]:
|
|
"""Attempt to stack this based on the starting information"""
|
|
memlayer = context.memory[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.memory.free_layer_name("VmwareMetaLayer")
|
|
current_config_path = interfaces.configuration.path_join("automagic", "layer_stacker", "stack",
|
|
current_layer_name)
|
|
if os.path.exists(vmss):
|
|
context.config[interfaces.configuration.path_join(current_config_path, "location")] = vmss
|
|
context.memory.add_layer(physical.FileLayer(context, current_config_path, current_layer_name))
|
|
elif os.path.exists(vmsn):
|
|
context.config[interfaces.configuration.path_join(current_config_path, "location")] = vmss
|
|
context.memory.add_layer(physical.FileLayer(context, current_config_path, current_layer_name))
|
|
else:
|
|
return None
|
|
new_layer_name = context.memory.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
|