Add in initial code for PDB reading.

This commit is contained in:
Mike Auty
2019-07-30 22:14:19 +01:00
committed by ikelos
parent 164079c203
commit 230d32f569
4 changed files with 295 additions and 1 deletions
+1 -1
View File
@@ -18,4 +18,4 @@
# specific language governing rights and limitations under the License.
#
from volatility.framework.layers import resources, intel, lime, physical, segmented, vmware, crash
from volatility.framework.layers import resources, intel, lime, physical, segmented, vmware, crash, msf
+60
View File
@@ -0,0 +1,60 @@
from typing import Optional, Dict, Any, List, Iterable, Tuple
from volatility.framework import interfaces, constants
from volatility.framework.configuration import requirements
from volatility.framework.objects import utility
from volatility.framework.symbols import intermed
class PdbMSF(interfaces.layers.TranslationLayerInterface):
headers = {
"MSF_HDR": "Microsoft C/C++ program database 2.00\r\n\x1a\x4a\x47",
"BIG_MSF_HDR": "Microsoft C/C++ MSF 7.00\r\n\x1a\x44\x53",
}
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._pdb_table_name = intermed.IntermediateSymbolTable.create(context, self._config_path, 'windows', 'pdb')
self._version = self._check_header()
def _check_header(self) -> Optional[str]:
"""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
current_header = self.context.object(header_type, self._base_layer, 0)
if utility.array_to_string(current_header.Magic) == self.headers[header]:
return header
return None
@property
def dependencies(self) -> List[str]:
"""Returns a list of the lower layers that this layer is dependent upon"""
return [self._base_layer]
@classmethod
def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]:
return [requirements.TranslationLayerRequirement(name = 'base_layer', optional = False)]
@property
def maximum_address(self) -> int:
return self.context.memory[self._base_layer].maximum_address
@property
def minimum_address(self) -> int:
return self.context.memory[self._base_layer].minimum_address
def is_valid(self, offset: int, length: int = 1) -> bool:
return self.context.memory[self._base_layer].is_valid(offset, length)
def mapping(self, offset: int, length: int, ignore_errors: bool = False) -> Iterable[Tuple[int, int, int, str]]:
yield (offset, offset, length, self._base_layer)
class PdbMSFStream(interfaces.layers.TranslationLayerInterface):
pass
@@ -0,0 +1,64 @@
import argparse
import os
from typing import Tuple
from urllib import request
from volatility.framework import contexts, interfaces
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
@classmethod
def load_pdb_layer(cls, context: interfaces.context.ContextInterface,
location: str) -> Tuple[str, interfaces.context.ContextInterface]:
"""Loads a PDB file into a layer within the context and returns the name of the new layer
Note: the context may be changed by this method
"""
physical_layer_name = context.memory.free_layer_name("FileLayer")
physical_config_path = interfaces.configuration.path_join("pdbreader", physical_layer_name)
# Create the file layer
# This must be specific to get us started, setup the config and run
new_context = context.clone()
new_context.config[interfaces.configuration.path_join(physical_config_path, "location")] = location
physical_layer = physical.FileLayer(new_context, physical_config_path, physical_layer_name)
new_context.add_layer(physical_layer)
# Add on the MSF format layer
msf_layer_name = context.memory.free_layer_name("MSFLayer")
msf_config_path = interfaces.configuration.path_join("pdbreader", msf_layer_name)
new_context.config[interfaces.configuration.path_join(msf_config_path, "base_layer")] = physical_layer_name
msf_layer = msf.PdbMSF(new_context, msf_config_path, msf_layer_name)
new_context.add_layer(msf_layer)
return msf_layer_name, new_context
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument("-f", "--filename", help = "Provide the name of a pdb file to read", required = True)
args = parser.parse_args()
ctx = contexts.Context()
if not os.path.exists(args.filename):
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)
### TESTING
x = ctx.object('pdb1!BIG_MSF_HDR', layer_name, 0)
import pdb
pdb.set_trace()
@@ -0,0 +1,170 @@
{
"symbols": {
},
"user_types": {
"SI_PERSIST": {
"fields": {
"cb": {
"offset": 0,
"type": {
"kind": "base",
"name": "long"
}
},
"mpspnpn": {
"offset": 4,
"type": {
"kind": "base",
"name": "unsigned long"
}
}
},
"kind": "struct",
"size": 8
},
"MSF_HDR": {
"fields": {
"Magic": {
"offset": 0,
"type": {
"count": 44,
"kind": "array",
"subtype": {
"kind": "base",
"name": "unsigned char"
}
}
},
"PageSize": {
"offset": 44,
"type": {
"kind": "base",
"name": "long"
}
},
"FPM": {
"offset": 48,
"type": {
"kind": "base",
"name": "unsigned short"
}
},
"Mac": {
"offset": 50,
"type": {
"kind": "base",
"name": "unsigned short"
}
},
"siSt": {
"offset": 52,
"type": {
"kind": "struct",
"name": "SI_PERSIST"
}
}
},
"kind": "struct",
"size": 60
},
"BIG_MSF_HDR": {
"fields": {
"Magic": {
"offset": 0,
"type": {
"count": 30,
"kind": "array",
"subtype": {
"kind": "base",
"name": "unsigned char"
}
}
},
"PageSize": {
"offset": 30,
"type": {
"kind": "base",
"name": "long"
}
},
"FPM": {
"offset": 34,
"type": {
"kind": "base",
"name": "unsigned long"
}
},
"Mac": {
"offset": 38,
"type": {
"kind": "base",
"name": "unsigned long"
}
},
"siSt": {
"offset": 42,
"type": {
"kind": "struct",
"name": "SI_PERSIST"
}
}
},
"kind": "struct",
"size": 60
}
},
"enums": {
},
"base_types": {
"unsigned char": {
"endian": "little",
"kind": "char",
"signed": false,
"size": 1
},
"unsigned short": {
"endian": "little",
"kind": "int",
"signed": false,
"size": 2
},
"long": {
"endian": "little",
"kind": "int",
"signed": true,
"size": 4
},
"char": {
"endian": "little",
"kind": "char",
"signed": true,
"size": 1
},
"unsigned long": {
"endian": "little",
"kind": "int",
"signed": false,
"size": 4
},
"long long": {
"endian": "little",
"kind": "int",
"signed": true,
"size": 8
},
"unsigned long long": {
"endian": "little",
"kind": "int",
"signed": false,
"size": 8
}
},
"metadata": {
"producer": {
"version": "0.0.1",
"name": "ikelos-by-hand",
"datetime": "2019-05-22T15:51:03"
},
"format": "4.0.0"
}
}