Further work on the MSF/PDB code.

This commit is contained in:
Mike Auty
2019-07-30 22:14:19 +01:00
committed by ikelos
parent ff5b71672c
commit ecfbe46c7a
3 changed files with 364 additions and 19 deletions
+15 -11
View File
@@ -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),
+61 -8
View File
@@ -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": {