mirror of
https://github.com/volatilityfoundation/volatility3.git
synced 2026-08-30 11:49:42 +02:00
Further work on the MSF/PDB code.
This commit is contained in:
@@ -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),
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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": {
|
||||
|
||||
Reference in New Issue
Block a user