Initial implementation of the Intermediate Format, breaks the vtypes format and needs a lot of tidying.

This commit is contained in:
Mike Auty
2016-10-26 01:09:29 +01:00
parent ea9ff20ca0
commit 0b447b6958
6 changed files with 134 additions and 12 deletions
+4 -3
View File
@@ -59,9 +59,10 @@ class CommandLine(object):
ctx.config["ui.single_location"] = "file:///run/media/mike/disk/memory/private/jon-fres.dmp"
ctx.config["plugins.pslist.offset"] = 0x01bcc830
ctx.config["plugins.pslist.ntkrnlmp.class"] = "volatility.framework.symbols.windows.WindowsKernelVTypeSymbols"
ctx.config["plugins.pslist.ntkrnlmp.vtype_pymodule"] = "volatility.framework.symbols.windows.xp_sp2_x86_vtypes"
ctx.config["plugins.pslist.ntkrnlmp.vtype_variable"] = "ntkrnlmp_types"
ctx.config[
"plugins.pslist.ntkrnlmp.class"] = "volatility.framework.symbols.windows.WindowsKernelIntermedSymbols"
ctx.config[
"plugins.pslist.ntkrnlmp.idd_filepath"] = "file:///home/mike/workspace/volatility3/aux/ntoskrnl.pdb.json"
###
# BACK TO THE FRAMEWORK
+1 -1
View File
@@ -105,7 +105,7 @@ class SymbolSpace(collections.abc.Mapping):
return getattr(self._dict[table_name], get_function)(component_name)
elif name in self.natives.types:
return getattr(self.natives, get_function)(name)
raise exceptions.SymbolError("Malformed symbol name")
raise exceptions.SymbolError("Malformed symbol name: " + repr(name))
def get_type(self, type_name):
"""Takes a symbol name and resolves it
+106
View File
@@ -0,0 +1,106 @@
import copy
import json
import logging
import urllib.parse
from volatility.framework import constants, exceptions, interfaces, objects
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)
url = urllib.parse.urlparse(idd_filepath)
if url.scheme != 'file':
raise NotImplementedError("The {0} scheme is not yet implement for the Intermediate Symbol Format.")
with open(url.path, "r") as fp:
self._json = json.load(fp)
self._validate_json()
self._overrides = {}
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):
raise exceptions.SymbolSpaceError("Malformed JSON file provided")
def get_type_class(self, name):
return self._overrides.get(name, objects.Struct)
def set_type_class(self, name, clazz):
if name not in self.types:
raise ValueError("Symbol type " + name + " not in " + self.name + " SymbolTable")
self._overrides[name] = clazz
def del_type_class(self, name):
if name in self._overrides:
del self._overrides[name]
@property
def types(self):
"""Returns an iterator of the symbol names"""
return self._json.get('user_types', {})
def _interdict_to_template(self, dictionary):
"""Converts an intermediate format dict into an object template"""
if not dictionary:
raise exceptions.SymbolSpaceError("Invalid intermediate dictionary: " + repr(dictionary))
type_name = dictionary['kind']
if type_name == 'base':
type_name = dictionary['name']
if type_name in self.natives.types:
# The symbol is a native type
native_template = self.natives.get_type(type_name)
# Add specific additional parameters, etc
update = {}
if type_name == 'array':
update['count'] = dictionary['count']
update['target'] = self._interdict_to_template(dictionary['subtype'])
elif type_name == 'pointer':
update["target"] = self._interdict_to_template(dictionary['subtype'])
elif type_name == 'enum':
update = self._lookup_enum(dictionary['name'])
elif type_name == 'bitfield':
update = {'start_bit': dictionary['bit_position'], 'end_bit': dictionary['bit_length']}
update['target'] = self._interdict_to_template(dictionary['type'])
native_template.update_vol(**update) # pylint: disable=W0142
return native_template
# Otherwise
if dictionary['kind'] not in ['struct', 'union']:
raise exceptions.SymbolSpaceError("Unknown Intermediate format: " + repr(dictionary))
return objects.templates.ReferenceTemplate(type_name = self.name + constants.BANG + dictionary['name'])
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)
if not lookup:
raise exceptions.SymbolSpaceError("Unknown enumeration found: " + repr(name))
result = {"choices": copy.deepcopy(lookup['constants']),
"target": self.natives.get_type(lookup['base'])}
return result
def get_type(self, type_name):
"""Resolves an individual symbol"""
if type_name not in self._json['user_types']:
raise exceptions.SymbolError("Unknown symbol:" + repr(type_name))
curdict = self._json['user_types'][type_name]
members = {}
for member_name in curdict['fields']:
interdict = curdict['fields'][member_name]
member = (interdict['offset'], self._interdict_to_template(interdict['type']))
members[member_name] = member
object_class = self.get_type_class(type_name)
return objects.templates.ObjectTemplate(type_name = self.name + constants.BANG + type_name,
object_class = object_class,
size = curdict['length'],
members = members)
+6 -6
View File
@@ -20,7 +20,7 @@ class NativeTable(interfaces.symbols.NativeTableInterface):
self._overrides[native_type] = native_class
# Create this once early, because it may get used a lot
self._types = set(self._native_dictionary).union(
{'Enumeration', 'array', 'BitField', 'void', 'pointer', 'String', 'Bytes'})
{'enum', 'array', 'bitfield', 'void', 'pointer', 'string', 'bytes', 'function'})
def get_type_class(self, name):
ntype, fmt = native_types.get(name, (objects.Integer, ''))
@@ -39,21 +39,21 @@ class NativeTable(interfaces.symbols.NativeTableInterface):
# NOTE: These need updating whenever the object init signatures change
additional = {}
obj = None
if type_name == 'void':
if type_name == 'void' or type_name == 'function':
obj = objects.Void
elif type_name == 'array':
obj = objects.Array
additional = {"count": 0, "target": self.get_type('void')}
elif type_name == 'Enumeration':
elif type_name == 'enum':
obj = objects.Enumeration
additional = {"target": self.get_type('void'), "choices": {}}
elif type_name == 'BitField':
elif type_name == 'bitfield':
obj = objects.BitField
additional = {"start_bit": 0, "end_bit": 0}
elif type_name == 'String':
elif type_name == 'string':
obj = objects.String
additional = {"max_length": 0}
elif type_name == 'Bytes':
elif type_name == 'bytes':
obj = objects.Bytes
additional = {"length": 0}
if obj is not None:
@@ -1,5 +1,5 @@
from volatility.framework.configuration import requirements
from volatility.framework.symbols import vtypes
from volatility.framework.symbols import vtypes, intermed
from volatility.framework.symbols.windows import extensions
__author__ = 'mike'
@@ -21,3 +21,18 @@ class WindowsKernelVTypeSymbols(vtypes.VTypeSymbolTable):
return [requirements.StringRequirement("vtype_pymodule", description = "Python module containing the vtypes"),
requirements.StringRequirement("vtype_variable",
description = "Python vtypes variable within the module")]
class WindowsKernelIntermedSymbols(intermed.IntermediateSymbolTable):
provides = {"type": "interface"}
def __init__(self, context, config_path, name, idd_filepath):
super().__init__(name = name, idd_filepath = idd_filepath, native_types = context.symbol_space.natives)
# Set-up windows specific types
self.set_type_class('_ETHREAD', extensions._ETHREAD)
self.set_type_class('_LIST_ENTRY', extensions._LIST_ENTRY)
@classmethod
def get_requirements(cls):
return [requirements.StringRequirement("idd_filepath", description = "JSON file containnig the symbols")]
+1 -1
View File
@@ -34,7 +34,7 @@ class PsList(plugins.PluginInterface):
def _generator(self, eproc):
for proc in eproc.ActiveProcessLinks:
yield (0, (proc.UniqueProcessId, proc.InheritedFromUniqueProcessId,
proc.ImageFileName.cast("String", max_length = proc.ImageFileName.vol.count,
proc.ImageFileName.cast("string", max_length = proc.ImageFileName.vol.count,
errors = 'replace')))
def run(self):