diff --git a/volatility/framework/layers/msf.py b/volatility/framework/layers/msf.py index 946c45ce7..216159b9b 100644 --- a/volatility/framework/layers/msf.py +++ b/volatility/framework/layers/msf.py @@ -21,20 +21,24 @@ class PdbMSF(interfaces.layers.TranslationLayerInterface): super().__init__(context, config_path, name, metadata) self._base_layer = self.config["base_layer"] - self._pdb_table_name = intermed.IntermediateSymbolTable.create(context, self._config_path, 'windows', 'pdb') + self._pdb_symbol_table = intermed.IntermediateSymbolTable.create(context, self._config_path, 'windows', 'pdb') response = self._check_header() if response is None: raise ValueError("Could not find a suitable header") self._version, self._header = response self._streams = {} # type: Dict[int, str] + @property + def pdb_symbol_table(self) -> str: + return self._pdb_symbol_table + def read_streams(self): # Shortcut in case they've already been read if self._streams: return # Recover the root table, by recovering the root table index table... - module = self.context.module(self._pdb_table_name, self._base_layer, offset = 0) + module = self.context.module(self.pdb_symbol_table, 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) @@ -48,17 +52,13 @@ class PdbMSF(interfaces.layers.TranslationLayerInterface): root_index_layer_name = self.create_stream_from_pages("root_index", self._header.StreamInfo.StreamInfoSize, [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")) + module = self.context.module(self.pdb_symbol_table, root_index_layer_name, offset = 0) + root_pages = module.object( + type_name = "array", offset = 0, count = root_table_num_pages, subtype = module.get_type("unsigned long")) root_layer_name = self.create_stream_from_pages("root", self._header.StreamInfo.StreamInfoSize, [x for x in root_pages]) - module = self.context.module(self._pdb_table_name, root_layer_name, offset = 0) + module = self.context.module(self.pdb_symbol_table, 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")) @@ -94,7 +94,7 @@ class PdbMSF(interfaces.layers.TranslationLayerInterface): def _check_header(self) -> Optional[Tuple[str, interfaces.objects.ObjectInterface]]: """Verifies the header of the PDB file and returns the version of the file""" for header in self.headers: - header_type = self._pdb_table_name + constants.BANG + header + header_type = self.pdb_symbol_table + 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]: if not (current_header.PageSize < 0x100 or current_header.PageSize > (128 * 0x10000)): @@ -153,6 +153,10 @@ class PdbMSFStream(interfaces.layers.TranslationLayerInterface): if not isinstance(self._pdb_layer, PdbMSF): raise TypeError("Base Layer must be a PdbMSF layer") + @property + def pdb_symbol_table(self) -> str: + return self._context.layers[self._base_layer].pdb_symbol_table + def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]: return [ requirements.ListRequirement(name = 'pages', element_type = int, min_elements = 1), diff --git a/volatility/framework/symbols/windows/mspdb.py b/volatility/framework/symbols/windows/mspdb.py index 38c015c81..d65fde3ea 100644 --- a/volatility/framework/symbols/windows/mspdb.py +++ b/volatility/framework/symbols/windows/mspdb.py @@ -1,6 +1,6 @@ import argparse import os -from typing import Tuple +from typing import Tuple, Dict from urllib import request from volatility.framework import contexts, interfaces @@ -10,9 +10,12 @@ from volatility.framework.layers import physical, msf class PdbReader: """Class to read Microsoft PDB files""" - def __init__(self, context: interfaces.context.ContextInterface, layer_name: str): - self._context = context - self._layer_name = layer_name + def __init__(self, context: interfaces.context.ContextInterface, location: str): + self._layer_name, self._context = self.load_pdb_layer(context, location) + + @property + def pdb_layer_name(self): + return self._layer_name @classmethod def load_pdb_layer(cls, context: interfaces.context.ContextInterface, @@ -43,6 +46,56 @@ class PdbReader: return msf_layer_name, new_context + def read_tpi_stream(self): + tpi_layer = self._context.layers.get(self._layer_name + "_stream2", None) + if not tpi_layer: + raise ValueError("No TPI stream available") + module = self._context.module(module_name = tpi_layer.pdb_symbol_table, layer_name = tpi_layer.name, offset = 0) + header = module.object(type_name = "TPI_HEADER", offset = 0) + + # Check the header + if not (56 <= header.header_size < 1024): + raise ValueError("TPI Stream Header size outside normal bounds") + if header.index_min < 4096: + raise ValueError("Minimum TPI index is 4096, found: {}".format(header.index_min)) + if header.index_max < header.index_min: + raise ValueError("Maximum TPI index is smaller than minimum TPI index, found: {} < {} ".format( + header.index_max, header.index_min)) + + types = {} + + offset = header.header_size + # Ensure we use the same type everywhere + length_type = "unsigned short" + length_len = module.get_type(length_type).size + while tpi_layer.maximum_address - offset > 0: + length = module.object(type_name = length_type, offset = offset) + offset += length_len + types.update(self.process_type(module, offset)) + offset += length + # Since types can only refer to earlier types, assigning the name at this point is fine + + if tpi_layer.maximum_address - offset != 0: + raise ValueError("Type values did not fill the TPI stream correctly") + + return header + + def process_type(self, module: interfaces.context.ModuleInterface, offset: int) -> Dict[str, Dict]: + leaf_type = module.object(type_name = "unsigned short", offset = offset) + LeafType = module.get_enumeration("LEAF_TYPE") + + if leaf_type in [ + LeafType.LF_CLASS, LeafType.LF_CLASS_ST, LeafType.LF_STRUCTURE, LeafType.LF_STRUCTURE_ST, + LeafType.LF_INTERFACE + ]: + pass + elif leaf_type in [LeafType.LF_MEMBER, LeafType.LF_MEMBER_ST]: + pass + else: + raise ValueError("Unhandled leaf_type: {}".format(leaf_type)) + + return {} + if __name__ == '__main__': @@ -55,12 +108,12 @@ if __name__ == '__main__': parser.error("File {} does not exists".format(args.filename)) location = "file:" + request.pathname2url(args.filename) - layer_name, ctx = PdbReader.load_pdb_layer(ctx, location) - - reader = PdbReader(ctx, layer_name) + reader = PdbReader(ctx, location) ### TESTING - x = ctx.object('pdb1!BIG_MSF_HDR', layer_name, 0) + # x = ctx.object('pdb1!BIG_MSF_HDR', reader.pdb_layer_name, 0) + header = reader.read_tpi_stream() + import pdb pdb.set_trace() diff --git a/volatility/framework/symbols/windows/pdb.json b/volatility/framework/symbols/windows/pdb.json index e8a0b26f4..2a98326bf 100644 --- a/volatility/framework/symbols/windows/pdb.json +++ b/volatility/framework/symbols/windows/pdb.json @@ -111,9 +111,297 @@ }, "kind": "struct", "size": 52 + }, + "TPI_HEADER": { + "fields": { + "version": { + "offset": 0, + "type": { + "kind": "base", + "name": "unsigned long" + } + }, + "header_size": { + "offset": 4, + "type": { + "kind": "base", + "name": "unsigned long" + } + }, + "index_min": { + "offset": 8, + "type": { + "kind": "base", + "name": "unsigned long" + } + }, + "index_max": { + "offset": 12, + "type": { + "kind": "base", + "name": "unsigned long" + } + }, + "gprec_size": { + "offset": 16, + "type": { + "kind": "base", + "name": "unsigned long" + } + }, + "tpi_hash_stream": { + "offset": 20, + "type": { + "kind": "base", + "name": "unsigned short" + } + }, + "tpi_hash_pad_stream": { + "offset": 22, + "type": { + "kind": "base", + "name": "unsigned short" + } + }, + "hash_key_size": { + "offset": 24, + "type": { + "kind": "base", + "name": "unsigned long" + } + }, + "hash_bucket_size": { + "offset": 28, + "type": { + "kind": "base", + "name": "unsigned long" + } + }, + "hash_values_offset": { + "offset": 32, + "type": { + "kind": "base", + "name": "unsigned long" + } + }, + "hash_values_size": { + "offset": 36, + "type": { + "kind": "base", + "name": "unsigned long" + } + }, + "ti_off_offset": { + "offset": 40, + "type": { + "kind": "base", + "name": "unsigned long" + } + }, + "ti_off_size": { + "offset": 44, + "type": { + "kind": "base", + "name": "unsigned long" + } + }, + "hash_adj_offset": { + "offset": 48, + "type": { + "kind": "base", + "name": "unsigned long" + } + }, + "hash_adj_size": { + "offset": 52, + "type": { + "kind": "base", + "name": "unsigned long" + } + } + }, + "kind": "struct", + "size": 56 } }, "enums": { + "LEAF_TYPE": { + "base": "unsigned short", + "constants": { + "LF_MODIFIER_16t": 1, + "LF_POINTER_16t": 2, + "LF_ARRAY_16t": 3, + "LF_CLASS_16t": 4, + "LF_STRUCTURE_16t": 5, + "LF_UNION_16t": 6, + "LF_ENUM_16t": 7, + "LF_PROCEDURE_16t": 8, + "LF_MFUNCTION_16t": 9, + "LF_VTSHAPE": 10, + "LF_COBOL0_16t": 11, + "LF_COBOL1": 12, + "LF_BARRAY_16t": 13, + "LF_LABEL": 14, + "LF_NULL": 15, + "LF_NOTTRAN": 16, + "LF_DIMARRAY_16t": 17, + "LF_VFTPATH_16t": 18, + "LF_PRECOMP_16t": 19, + "LF_ENDPRECOMP": 20, + "LF_OEM_16t": 21, + "LF_TYPESERVER_ST": 22, + "LF_SKIP_16t": 512, + "LF_ARGLIST_16t": 513, + "LF_DEFARG_16t": 514, + "LF_LIST": 515, + "LF_FIELDLIST_16t": 516, + "LF_DERIVED_16t": 517, + "LF_BITFIELD_16t": 518, + "LF_METHODLIST_16t": 519, + "LF_DIMCONU_16t": 520, + "LF_DIMCONLU_16t": 521, + "LF_DIMVARU_16t": 522, + "LF_DIMVARLU_16t": 523, + "LF_REFSYM": 524, + "LF_BCLASS_16t": 1024, + "LF_VBCLASS_16t": 1025, + "LF_IVBCLASS_16t": 1026, + "LF_ENUMERATE_ST": 1027, + "LF_FRIENDFCN_16t": 1028, + "LF_INDEX_16t": 1029, + "LF_MEMBER_16t": 1030, + "LF_STMEMBER_16t": 1031, + "LF_METHOD_16t": 1032, + "LF_NESTTYPE_16t": 1033, + "LF_VFUNCTAB_16t": 1034, + "LF_FRIENDCLS_16t": 1035, + "LF_ONEMETHOD_16t": 1036, + "LF_VFUNCOFF_16t": 1037, + "LF_TI16_MAX": 4096, + "LF_MODIFIER": 4097, + "LF_POINTER": 4098, + "LF_ARRAY_ST": 4099, + "LF_CLASS_ST": 4100, + "LF_STRUCTURE_ST": 4101, + "LF_UNION_ST": 4102, + "LF_ENUM_ST": 4103, + "LF_PROCEDURE": 4104, + "LF_MFUNCTION": 4105, + "LF_COBOL0": 4106, + "LF_BARRAY": 4107, + "LF_DIMARRAY_ST": 4108, + "LF_VFTPATH": 4109, + "LF_PRECOMP_ST": 4110, + "LF_OEM": 4111, + "LF_ALIAS_ST": 4112, + "LF_OEM2": 4113, + "LF_SKIP": 4608, + "LF_ARGLIST": 4609, + "LF_DEFARG_ST": 4610, + "LF_FIELDLIST": 4611, + "LF_DERIVED": 4612, + "LF_BITFIELD": 4613, + "LF_METHODLIST": 4614, + "LF_DIMCONU": 4615, + "LF_DIMCONLU": 4616, + "LF_DIMVARU": 4617, + "LF_DIMVARLU": 4618, + "LF_BCLASS": 5120, + "LF_VBCLASS": 5121, + "LF_IVBCLASS": 5122, + "LF_FRIENDFCN_ST": 5123, + "LF_INDEX": 5124, + "LF_MEMBER_ST": 5125, + "LF_STMEMBER_ST": 5126, + "LF_METHOD_ST": 5127, + "LF_NESTTYPE_ST": 5128, + "LF_VFUNCTAB": 5129, + "LF_FRIENDCLS": 5130, + "LF_ONEMETHOD_ST": 5131, + "LF_VFUNCOFF": 5132, + "LF_NESTTYPEEX_ST": 5133, + "LF_MEMBERMODIFY_ST": 5134, + "LF_MANAGED_ST": 5135, + "LF_ST_MAX": 5376, + "LF_TYPESERVER": 5377, + "LF_ENUMERATE": 5378, + "LF_ARRAY": 5379, + "LF_CLASS": 5380, + "LF_STRUCTURE": 5381, + "LF_UNION": 5382, + "LF_ENUM": 5383, + "LF_DIMARRAY": 5384, + "LF_PRECOMP": 5385, + "LF_ALIAS": 5386, + "LF_DEFARG": 5387, + "LF_FRIENDFCN": 5388, + "LF_MEMBER": 5389, + "LF_STMEMBER": 5390, + "LF_METHOD": 5391, + "LF_NESTTYPE": 5392, + "LF_ONEMETHOD": 5393, + "LF_NESTTYPEEX": 5394, + "LF_MEMBERMODIFY": 5395, + "LF_MANAGED": 5396, + "LF_TYPESERVER2": 5397, + "LF_STRIDED_ARRAY": 5398, + "LF_HLSL": 5399, + "LF_MODIFIER_EX": 5400, + "LF_INTERFACE": 5401, + "LF_BINTERFACE": 5402, + "LF_VECTOR": 5403, + "LF_MATRIX": 5404, + "LF_VFTABLE": 5405, + "LF_FUNC_ID": 5633, + "LF_MFUNC_ID": 5634, + "LF_BUILDINFO": 5635, + "LF_SUBSTR_LIST": 5636, + "LF_STRING_ID": 5637, + "LF_UDT_SRC_LINE": 5638, + "LF_UDT_MOD_SRC_LINE": 5639, + "LF_NUMERIC": 32768, + "LF_CHAR": 32768, + "LF_SHORT": 32769, + "LF_USHORT": 32770, + "LF_LONG": 32771, + "LF_ULONG": 32772, + "LF_REAL32": 32773, + "LF_REAL64": 32774, + "LF_REAL80": 32775, + "LF_REAL128": 32776, + "LF_QUADWORD": 32777, + "LF_UQUADWORD": 32778, + "LF_REAL48": 32779, + "LF_COMPLEX32": 32780, + "LF_COMPLEX64": 32781, + "LF_COMPLEX80": 32782, + "LF_COMPLEX128": 32783, + "LF_VARSTRING": 32784, + "LF_OCTWORD": 32791, + "LF_UOCTWORD": 32792, + "LF_DECIMAL": 32793, + "LF_DATE": 32794, + "LF_UTF8STRING": 32795, + "LF_REAL16": 32796, + "LF_PAD0": 240, + "LF_PAD1": 241, + "LF_PAD2": 242, + "LF_PAD3": 243, + "LF_PAD4": 244, + "LF_PAD5": 245, + "LF_PAD6": 246, + "LF_PAD7": 247, + "LF_PAD8": 248, + "LF_PAD9": 249, + "LF_PAD10": 250, + "LF_PAD11": 251, + "LF_PAD12": 252, + "LF_PAD13": 253, + "LF_PAD14": 254, + "LF_PAD15": 255 + }, + "size": 2 + } }, "base_types": { "unsigned char": {