mirror of
https://github.com/volatilityfoundation/volatility3.git
synced 2026-09-07 18:27:39 +02:00
Add in support for format versioning.
This commit is contained in:
@@ -3,22 +3,74 @@ import json
|
||||
import logging
|
||||
import urllib.parse
|
||||
|
||||
from volatility.framework import constants, exceptions, interfaces, objects
|
||||
from volatility.framework import constants, exceptions, interfaces, objects, class_subclasses
|
||||
|
||||
vollog = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class IntermediateSymbolTable(interfaces.symbols.SymbolTableInterface):
|
||||
"""Class for storing intermediate debugging data as objects and classes"""
|
||||
|
||||
def __init__(self, name, idd_filepath, native_types = None):
|
||||
super().__init__(name, native_types)
|
||||
# Check there are no obvious errors
|
||||
url = urllib.parse.urlparse(idd_filepath)
|
||||
if url.scheme != 'file':
|
||||
raise NotImplementedError(
|
||||
"This scheme is not yet implement for the Intermediate Symbol Format: {}".format(url.scheme))
|
||||
# Inherit
|
||||
super().__init__(name, native_types)
|
||||
|
||||
# Open the file and test the version
|
||||
self._versions = dict([(x.version, x) for x in class_subclasses(ISFormatTable)])
|
||||
with open(url.path, "r") as fp:
|
||||
self._json = json.load(fp)
|
||||
json_object = json.load(fp)
|
||||
metadata = json_object.get('metadata', None)
|
||||
|
||||
# Determine the delegate or throw an exception
|
||||
self._delegate = self._closest_version(metadata.get('version', "0.0.0"), self._versions)(name, json_object,
|
||||
native_types)
|
||||
|
||||
def _closest_version(self, version, versions):
|
||||
"""Determines the highest suitable handler for specified version format"""
|
||||
"""Finds the highest suitable format version to read the data"""
|
||||
supported, age, revision = [int(x) for x in version.split(".")]
|
||||
supported_versions = [x for x in versions.keys() if x[0] == supported and x[1] >= age]
|
||||
if not supported_versions:
|
||||
raise ValueError("No Intermediate Format versions support file version: {}".format(version))
|
||||
return versions[max(supported_versions)]
|
||||
|
||||
def _construct_delegate_function(name, is_property = False):
|
||||
def _delegate_function(self, *args, **kwargs):
|
||||
if is_property:
|
||||
return getattr(self._delegate, name)
|
||||
return getattr(self._delegate, name)(*args, **kwargs)
|
||||
|
||||
if is_property:
|
||||
return property(_delegate_function)
|
||||
return _delegate_function
|
||||
|
||||
symbols = _construct_delegate_function('symbols', True)
|
||||
types = _construct_delegate_function('types', True)
|
||||
get_type = _construct_delegate_function('get_type')
|
||||
get_symbol = _construct_delegate_function('get_symbol')
|
||||
get_type_class = _construct_delegate_function('get_type_class')
|
||||
set_type_class = _construct_delegate_function('set_type_class')
|
||||
del_type_class = _construct_delegate_function('del_type_class')
|
||||
|
||||
|
||||
class ISFormatTable(interfaces.symbols.SymbolTableInterface):
|
||||
"""Provide a base class to identify all subclasses"""
|
||||
pass
|
||||
|
||||
|
||||
class Version1Format(ISFormatTable):
|
||||
"""Class for storing intermediate debugging data as objects and classes"""
|
||||
current = 0
|
||||
revision = 0
|
||||
age = 0
|
||||
version = (current - age, age, revision)
|
||||
|
||||
def __init__(self, name, json_object, native_types = None):
|
||||
super().__init__(name, native_types)
|
||||
self._json_object = json_object
|
||||
self._validate_json()
|
||||
self._overrides = {}
|
||||
self._symbol_cache = None
|
||||
@@ -26,16 +78,16 @@ class IntermediateSymbolTable(interfaces.symbols.SymbolTableInterface):
|
||||
# TODO: Check the format and make use of the other metadata
|
||||
|
||||
def _validate_json(self):
|
||||
if (not 'user_types' in self._json or
|
||||
not 'base_types' in self._json or
|
||||
not 'metadata' in self._json or
|
||||
not 'symbols' in self._json or
|
||||
not 'enums' in self._json):
|
||||
if (not 'user_types' in self._json_object or
|
||||
not 'base_types' in self._json_object or
|
||||
not 'metadata' in self._json_object or
|
||||
not 'symbols' in self._json_object or
|
||||
not 'enums' in self._json_object):
|
||||
raise exceptions.SymbolSpaceError("Malformed JSON file provided")
|
||||
|
||||
def get_symbol(self, name):
|
||||
"""Returns the location offset given by the symbol name"""
|
||||
symbol = self._json['symbols'].get(name, None)
|
||||
symbol = self._json_object['symbols'].get(name, None)
|
||||
if not symbol:
|
||||
raise KeyError("Unknown symbol: {}".format(name))
|
||||
return interfaces.symbols.Symbol(name = name, address = symbol['address'])
|
||||
@@ -43,8 +95,9 @@ class IntermediateSymbolTable(interfaces.symbols.SymbolTableInterface):
|
||||
@property
|
||||
def symbols(self):
|
||||
if not self._symbol_cache:
|
||||
self._symbol_cache = [interfaces.symbols.Symbol(name = x, address = self._json['symbols'][x]['address']) for
|
||||
x in self._json['symbols']]
|
||||
self._symbol_cache = [
|
||||
interfaces.symbols.Symbol(name = x, address = self._json_object['symbols'][x]['address']) for
|
||||
x in self._json_object['symbols']]
|
||||
return self._symbol_cache
|
||||
|
||||
# TODO: Add the ability to add/remove/change symbols after creation, note that this should invalidate the cache
|
||||
@@ -64,7 +117,7 @@ class IntermediateSymbolTable(interfaces.symbols.SymbolTableInterface):
|
||||
@property
|
||||
def types(self):
|
||||
"""Returns an iterator of the symbol names"""
|
||||
return self._json.get('user_types', {})
|
||||
return self._json_object.get('user_types', {})
|
||||
|
||||
def _interdict_to_template(self, dictionary):
|
||||
"""Converts an intermediate format dict into an object template"""
|
||||
@@ -102,7 +155,7 @@ class IntermediateSymbolTable(interfaces.symbols.SymbolTableInterface):
|
||||
|
||||
def _lookup_enum(self, name):
|
||||
"""Looks up an enumeration and returns a dictionary of __init__ parameters for an Enum"""
|
||||
lookup = self._json['enums'].get(name, None)
|
||||
lookup = self._json_object['enums'].get(name, None)
|
||||
if not lookup:
|
||||
raise exceptions.SymbolSpaceError("Unknown enumeration found: {}".format(name))
|
||||
result = {"choices": copy.deepcopy(lookup['constants']),
|
||||
@@ -111,9 +164,9 @@ class IntermediateSymbolTable(interfaces.symbols.SymbolTableInterface):
|
||||
|
||||
def get_type(self, type_name):
|
||||
"""Resolves an individual symbol"""
|
||||
if type_name not in self._json['user_types']:
|
||||
if type_name not in self._json_object['user_types']:
|
||||
raise exceptions.SymbolError("Unknown symbol: {}".format(type_name))
|
||||
curdict = self._json['user_types'][type_name]
|
||||
curdict = self._json_object['user_types'][type_name]
|
||||
members = {}
|
||||
for member_name in curdict['fields']:
|
||||
interdict = curdict['fields'][member_name]
|
||||
|
||||
Reference in New Issue
Block a user