mirror of
https://github.com/volatilityfoundation/volatility3.git
synced 2026-09-02 14:28:58 +02:00
Add in MSF and Stream layer support.
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import math
|
||||
from typing import Optional, Dict, Any, List, Iterable, Tuple
|
||||
|
||||
from volatility.framework import interfaces, constants
|
||||
@@ -25,6 +26,62 @@ class PdbMSF(interfaces.layers.TranslationLayerInterface):
|
||||
if response is None:
|
||||
raise ValueError("Could not find a suitable header")
|
||||
self._version, self._header = response
|
||||
self._streams = {} # type: Dict[int, Optional[PdbMSFStream]]
|
||||
|
||||
def read_streams(self):
|
||||
# Recover the root table, by recovering the root table index table...
|
||||
module = self.context.module(self._pdb_table_name, self._base_layer, offset = 0)
|
||||
entry_size = module.get_type("unsigned long").size
|
||||
|
||||
root_table_num_pages = math.ceil(self._header.StreamInfo.StreamInfoSize / self._header.PageSize)
|
||||
root_index_size = math.ceil((root_table_num_pages * entry_size) / self._header.PageSize)
|
||||
root_index = module.object(
|
||||
type_name = "array",
|
||||
layer_name = self._base_layer,
|
||||
offset = self._header.vol.size,
|
||||
count = root_index_size,
|
||||
subtype = module.get_type("unsigned long"))
|
||||
root_index_layer_name = self.create_stream_from_pages("root_index", [x for x in root_index])
|
||||
|
||||
module = self.context.module(self._pdb_table_name, root_index_layer_name, offset = 0)
|
||||
root_pages = self.context.object(
|
||||
symbol = self._pdb_table_name + constants.BANG + "array",
|
||||
layer_name = root_index_layer_name,
|
||||
offset = 0,
|
||||
count = root_table_num_pages,
|
||||
subtype = module.get_type("unsigned long"))
|
||||
root_layer_name = self.create_stream_from_pages("root", [x for x in root_pages])
|
||||
|
||||
module = self.context.module(self._pdb_table_name, root_layer_name, offset = 0)
|
||||
num_streams = module.object(type_name = "unsigned long", offset = 0)
|
||||
stream_sizes = module.object(
|
||||
type_name = "array", offset = entry_size, count = num_streams, subtype = module.get_type("unsigned long"))
|
||||
|
||||
current_offset = (num_streams + 1) * entry_size
|
||||
|
||||
for stream in range(num_streams):
|
||||
list_size = math.ceil(stream_sizes[stream] / self.page_size)
|
||||
if list_size:
|
||||
stream_page_list = module.object(
|
||||
type_name = "array",
|
||||
offset = current_offset,
|
||||
count = list_size,
|
||||
subtype = module.get_type("unsigned long"))
|
||||
current_offset += (list_size * entry_size)
|
||||
self._streams[stream] = self.create_stream_from_pages("stream", [x for x in stream_page_list])
|
||||
else:
|
||||
self._streams[stream] = None
|
||||
|
||||
def create_stream_from_pages(self, stream_name: str, pages: List[int]) -> str:
|
||||
# Construct a root layer based on a number of pages
|
||||
layer_name = self.context.memory.free_layer_name(self.name + "_" + stream_name)
|
||||
path_join = interfaces.configuration.path_join
|
||||
config_path = path_join(self.config_path, stream_name)
|
||||
self.context.config[path_join(config_path, 'base_layer')] = self.name
|
||||
self.context.config[path_join(config_path, 'pages')] = pages
|
||||
layer = PdbMSFStream(self.context, config_path, layer_name)
|
||||
self.context.memory.add_layer(layer)
|
||||
return layer_name
|
||||
|
||||
def _check_header(self) -> Optional[Tuple[str, interfaces.objects.ObjectInterface]]:
|
||||
"""Verifies the header of the PDB file and returns the version of the file"""
|
||||
@@ -32,9 +89,14 @@ class PdbMSF(interfaces.layers.TranslationLayerInterface):
|
||||
header_type = self._pdb_table_name + constants.BANG + header
|
||||
current_header = self.context.object(header_type, self._base_layer, 0)
|
||||
if utility.array_to_string(current_header.Magic) == self.headers[header]:
|
||||
return header, current_header
|
||||
if not (current_header.PageSize < 0x100 or current_header.PageSize > (128 * 0x10000)):
|
||||
return header, current_header
|
||||
return None
|
||||
|
||||
@property
|
||||
def page_size(self):
|
||||
return self._header.PageSize
|
||||
|
||||
@property
|
||||
def dependencies(self) -> List[str]:
|
||||
"""Returns a list of the lower layers that this layer is dependent upon"""
|
||||
@@ -60,4 +122,49 @@ class PdbMSF(interfaces.layers.TranslationLayerInterface):
|
||||
|
||||
|
||||
class PdbMSFStream(interfaces.layers.TranslationLayerInterface):
|
||||
pass
|
||||
|
||||
def __init__(self,
|
||||
context: 'interfaces.context.ContextInterface',
|
||||
config_path: str,
|
||||
name: str,
|
||||
metadata: Optional[Dict[str, Any]] = None) -> None:
|
||||
super().__init__(context, config_path, name, metadata)
|
||||
self._base_layer = self.config["base_layer"]
|
||||
self._pages = self.config.get("pages", None)
|
||||
if not self._pages:
|
||||
raise ValueError("Invalid/no pages specified")
|
||||
if not isinstance(self._pdb_layer, PdbMSF):
|
||||
raise TypeError("Base Layer must be a PdbMSF layer")
|
||||
|
||||
def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]:
|
||||
return [requirements.ListRequirement(name = 'pages', element_type = int, min_elements = 1)]
|
||||
|
||||
def mapping(self, offset: int, length: int, ignore_errors: bool = False) -> Iterable[Tuple[int, int, int, str]]:
|
||||
returned = 0
|
||||
page_size = self._pdb_layer.page_size
|
||||
while length > 0:
|
||||
page = math.floor((offset + returned) / page_size)
|
||||
page_position = ((offset + returned) % page_size)
|
||||
chunk_size = min(page_size - page_position, length)
|
||||
yield (offset + returned, (self._pages[page] * page_size) + page_position, chunk_size, self._base_layer)
|
||||
returned += chunk_size
|
||||
length -= chunk_size
|
||||
|
||||
@property
|
||||
def dependencies(self) -> List[str]:
|
||||
return [self._base_layer]
|
||||
|
||||
def is_valid(self, offset: int, length: int = 1) -> bool:
|
||||
return self.minimum_address <= offset and offset + length < self.maximum_address
|
||||
|
||||
@property
|
||||
def minimum_address(self) -> int:
|
||||
return 0
|
||||
|
||||
@property
|
||||
def maximum_address(self) -> int:
|
||||
return len(self._pages) * self._pdb_layer.page_size
|
||||
|
||||
@property
|
||||
def _pdb_layer(self) -> PdbMSF:
|
||||
return self._context.memory.get(self._base_layer, None)
|
||||
|
||||
@@ -39,6 +39,8 @@ class PdbReader:
|
||||
msf_layer = msf.PdbMSF(new_context, msf_config_path, msf_layer_name)
|
||||
new_context.add_layer(msf_layer)
|
||||
|
||||
msf_layer.read_streams()
|
||||
|
||||
return msf_layer_name, new_context
|
||||
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
"name": "unsigned short"
|
||||
}
|
||||
},
|
||||
"StreamTableStreamInfo": {
|
||||
"StreamInfo": {
|
||||
"offset": 52,
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
@@ -101,7 +101,7 @@
|
||||
"name": "unsigned long"
|
||||
}
|
||||
},
|
||||
"StreamTableStreamInfo": {
|
||||
"StreamInfo": {
|
||||
"offset": 44,
|
||||
"type": {
|
||||
"kind": "struct",
|
||||
@@ -110,7 +110,7 @@
|
||||
}
|
||||
},
|
||||
"kind": "struct",
|
||||
"size": 60
|
||||
"size": 52
|
||||
}
|
||||
},
|
||||
"enums": {
|
||||
|
||||
Reference in New Issue
Block a user