mirror of
https://github.com/volatilityfoundation/volatility3.git
synced 2026-09-28 12:34:53 +02:00
Add in initial code for PDB reading.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user