Rework templates so that they're created referentially, and that attributes are generated by the underlying class and arguments.

This commit is contained in:
Mike Auty
2013-04-21 18:22:38 +01:00
parent b0345ce9ab
commit 9b91bfa88c
8 changed files with 478 additions and 302 deletions
+24 -12
View File
@@ -4,22 +4,34 @@ Created on 10 Mar 2013
@author: mike
'''
from volatility.framework import xp_sp2_x86_vtypes, context
import pdb
from volatility.framework import xp_sp2_x86_vtypes, context, symbols
from volatility.framework.symbols import vtypes, native
if __name__ == '__main__':
def main():
nativelst = native.x86NativeTable
virtual_types = xp_sp2_x86_vtypes.ntkrnlmp_types
ntkrnlmp = vtypes.VTypeSymbolList('ntkrnlmp', virtual_types)
native = native.x86NativeSymbolList
ntkrnlmp = vtypes.VTypeSymbolTable('ntkrnlmp', virtual_types, nativelst)
ctx = context.Context()
ctx.add_symbol_list(native)
ctx.add_symbol_list(ntkrnlmp)
print("Symbols,", native.symbols)
ctx = context.Context(symbols.SymbolSpace(nativelst))
ctx.symbol_space.append(nativelst)
ctx.symbol_space.append(ntkrnlmp)
print("Symbols,", nativelst.symbols)
for i in ntkrnlmp.symbols:
symbol = ctx.resolve('ntkrnlmp!' + i)
print(symbol)
# objthing = symbol(context, layer_name = '', offset = 0)
for _ in [1, 2]:
for i in list(ntkrnlmp.symbols):
symbol = ctx.symbol_space.resolve('ntkrnlmp!' + i)
print(symbol.symbol_name, symbol, symbol.size)
# objthing = symbol(context, layer_name = '', offset = 0)
if __name__ == '__main__':
# import timeit
# print(timeit.Timer(main).timeit(10))
try:
main()
except:
pdb.post_mortem()
+8 -15
View File
@@ -4,28 +4,21 @@ Created on 12 Feb 2013
@author: mike
'''
import volatility.framework.symbols as symbols
import volatility.framework.interfaces as interfaces
class Context(object):
class Context(interfaces.ContextInterface):
"""Maintains the context within which to construct objects"""
def __init__(self):
self._symbol_space = symbols.SymbolSpace()
def __init__(self, symbol_space):
super(Context, self).__init__()
self._symbol_space = symbol_space
self._layers = {}
### Symbol Space Functions
def add_symbol_list(self, symbol_list):
"""Adds a symbol list to the symbol space used by the context"""
self._symbol_space.append(symbol_list)
def remove_symbol_list(self, symbol_list_name):
"""Removes a symbol list from the symbol space used by the context"""
self._symbol_space.remove(symbol_list_name)
def resolve(self, symbol_name):
"""Resolves a symbol name from the various symbol lists in the symbol space"""
return self._symbol_space.resolve(symbol_name)
@property
def symbol_space(self):
return self._symbol_space
### Address Space Functions
+130 -1
View File
@@ -4,6 +4,8 @@ Created on 12 Apr 2013
@author: mike
'''
import copy
class ObjectInterface(object):
""" A base object required to be the ancestor of every object used in volatility """
def __init__(self, context, layer_name, offset, symbol_name, size, **kwargs):
@@ -14,5 +16,132 @@ class ObjectInterface(object):
self._size = size
def cast(self, new_symbol_name):
object_template = self._context.resolve()
object_template = self._context.resolve(new_symbol_name)
return object_template(context = self._context, layer_name = self._layer_name, offset = self._offset)
class ContextInterface(object):
"""Class for providing the interface for the Context object"""
def __init__(self):
"""Intializes the context with a symbol_space"""
### Symbol Space Functions
@property
def symbol_space(self):
"""Returns the symbol_space for the context"""
### Address Space Functions
def add_translation_layer(self, layer, name = None):
"""Adds a named translation layer to the context"""
### Object Factory Functions
def object(self, symbol, layer_name, offset):
"""Object factory, takes a context, symbol, offset and optional layername
Looks up the layername in the context, finds the object template based on the symbol,
and constructs an object using the object template on the layer at the offset.
Returns a fully constructed object
"""
class Template(object):
"""Class for all Factories that take offsets, and data layers and produce objects
This is effectively a class for currying object calls
"""
def __init__(self, symbol_name = None, **kwargs):
"""Stores the keyword arguments for later use"""
self._kwargs = kwargs
self._symbol_name = symbol_name
@property
def symbol_name(self):
"""Returns the name of the particular symbol"""
return self._symbol_name
@property
def arguments(self):
"""Returns the keyword arguments stored earlier"""
return copy.deepcopy(self._kwargs)
def update_arguments(self, **newargs):
"""Updates the keyword arguments"""
self._kwargs.update(newargs)
def __call__(self, context, layer_name, offset, parent = None):
"""Constructs the object
Returns: an object adhereing to the Object interface
"""
class SymbolTableInterface(object):
"""Handles a table of symbols"""
def __init__(self, name, native_symbols = None, *args, **kwargs):
super(SymbolTableInterface, self).__init__(*args, **kwargs)
if not isinstance(name, str) or not name:
raise TypeError("Symbol Table name must be a string")
if not isinstance(native_symbols, NativeTableInterface):
raise TypeError("Symbol Table native_symbols must be a NativeTable, not " + str(type(native_symbols)))
self.name = name
self._native_symbols = native_symbols
### Required Symbol List functions
def resolve(self, symbol):
"""Resolves a symbol name into an object template
If the symbol isn't found it raises a SymbolNotFound exception
"""
@property
def symbols(self):
"""Returns an iterator of the symbol names"""
### Native Type Handler
@property
def natives(self):
"""Returns None or a symbol_space for handling space specific native types"""
return self._native_symbols
### Functions for overriding classes
def set_symbol_class(self, symbol, clazz):
"""Overrides the object class for a specific symbol
Symbol *must* be present in self.symbols
"""
def get_symbol_class(self, symbol):
"""Returns the class associated with a symbol"""
def del_symbol_class(self, symbol):
"""Removes the associated class override for a specific symbol"""
### Helper functions that can be overridden
def __len__(self):
"""Returns the number of items in the symbol list"""
return len(self.symbols)
def __getitem__(self, key):
"""Resolves a symbol name into an object template
Note, this method cannot sub-resolve throughout a whole symbol space
"""
return self.resolve(key)
def __iter__(self):
"""Returns an iterator of the available keys"""
return self.symbols
def __contains__(self, symbol):
"""Determines whether a symbol exists in the list or not"""
return symbol in self.symbols
class NativeTableInterface(SymbolTableInterface):
"""Class to distinguish NativeSymbolLists from other symbol lists"""
+126 -48
View File
@@ -9,39 +9,55 @@ import collections
import volatility.framework.interfaces as interfaces
import volatility.framework.templates as templates
class Void(interfaces.ObjectInterface):
"""Returns an object to represent void/unknown types"""
pass
class PrimitiveObject(interfaces.ObjectInterface):
"""PrimitiveObject is an interface for any objects that should simulate a Python primitive"""
def __init__(self, context, layer_name, offset, symbol_name, struct_format = '<I', **kwargs):
super(PrimitiveObject, self).__init__(context = context, layer_name = layer_name, offset = offset, symbol_name = symbol_name)
self._struct_format = struct_format
@classmethod
def _struct_value(cls, struct_format, context, layer_name, offset, symbol_name, size):
def _struct_value(cls, struct_format, context, layer_name, offset, symbol_name):
aspace = context.get_address_space(layer_name)
length = struct.calcsize(struct_format)
data = aspace.read(offset, length)
(value,) = struct.unpack(struct_format, data)
return value
@classmethod
def template_size(cls, arguments):
"""Returns the size of the templated object"""
return struct.calcsize(arguments.get('struct_format', '<I'))
@classmethod
def template_children(cls, arguments):
"""Since primitives have no children, this returns an empty list"""
return []
def template_replace_child(self, old_child, new_child, arguments):
"""Since this template can't ever have children, this method can be empty"""
class Integer(PrimitiveObject, int):
"""Primitive Object that handles standard numeric types"""
def __new__(cls, context, layer_name, offset, symbol_name, struct_format, **kwargs):
struct_format = context.get_primitive_struct_type("int", symbol_name)
struct_size = struct.calcsize(struct_format)
return cls._struct_value(struct_format, context, layer_name, offset, symbol_name, size = struct_size)
return cls._struct_value(struct_format, context, layer_name, offset, symbol_name)
class Float(PrimitiveObject, float):
"""Primitive Object that handles double or floating point numbers"""
def __new__(cls, context, layer_name, offset, symbol_name, size, **kwargs):
struct_format = context.get_primitive_struct_type("float", symbol_name)
struct_size = struct.calcsize(struct_format)
return cls._struct_value(struct_format, context, layer_name, offset, symbol_name, size = struct_size)
def __new__(cls, context, layer_name, offset, symbol_name, struct_format, **kwargs):
return cls._struct_value(struct_format, context, layer_name, offset, symbol_name)
class Bytes(PrimitiveObject, bytes):
"""Primitive Object that handles specific series of bytes
"""
"""Primitive Object that handles specific series of bytes"""
def __new__(cls, context, layer_name, offset, symbol_name, size, **kwargs):
return cls._struct_value(str(size) + "s", context, layer_name, offset, symbol_name, size)
def __new__(cls, context, layer_name, offset, symbol_name, length = 1):
return cls._struct_value(str(length) + "s", context, layer_name, offset, symbol_name)
class String(PrimitiveObject, str):
"""Primitive Object that handles string values
@@ -49,15 +65,19 @@ class String(PrimitiveObject, str):
length: specifies the maximum possible length that the string could hold in memory
"""
def __new__(cls, context, layer_name, offset, symbol_name, size = None, length = 1):
return cls._struct_value(str(length) + "s", context, layer_name, offset, symbol_name, size)
def __new__(cls, context, layer_name, offset, symbol_name, length = 1):
return cls._struct_value(str(length) + "s", context, layer_name, offset, symbol_name)
class Pointer(Integer):
"""Pointer which points to another object"""
def __init__(self, context, layer_name, offset, symbol_name, size = None, target = None):
if not isinstance(target, interfaces.ObjectInterface):
raise TypeError("Pointer targets must be an ObjectInterface")
super(Pointer, self).__init__(context, layer_name, offset, symbol_name, size)
def __init__(self, context, layer_name, offset, symbol_name, struct_format = None, target = None):
if not isinstance(target, templates.ObjectTemplate):
raise TypeError("Pointer targets must be an ObjectTemplate")
super(Pointer, self).__init__(context,
layer_name = layer_name,
offset = offset,
symbol_name = symbol_name,
struct_format = struct_format)
self._target = target
def derefenence(self):
@@ -71,46 +91,104 @@ class Pointer(Integer):
"""Convenience function to access unknown attributes by getting them from the target object"""
return getattr(self.dereference(), attr)
class BitField(Integer):
""""""
def __new__(self, context, layer_name, offset, symbol_name, size = None, start_bit = 0, end_bit = 0):
# TODO: Determine endianness of the bitfield
struct_size = (end_bit + 7) // 8
if struct_size == 1:
struct_format = "c"
elif struct_size <= 2:
struct_format = "H"
elif struct_size <= 4:
struct_format = "I"
else:
struct_format = "Q"
return super(BitField, self).__new__(context, layer_name, offset, symbol_name, size = None, struct_format = struct_format)
class BitField(PrimitiveObject):
"""Object containing a field which is made up of bits rather than whole bytes"""
def __new__(cls, context, layer_name, offset, symbol_name, target = None, start_bit = 0, end_bit = 0):
return target(context = context, layer_name = layer_name, offset = offset, symbol_name = symbol_name)
class Enumeration(interfaces.ObjectInterface):
"""Returns an object made up of choices"""
# FIXME: Add in body for the enumeration object
pass
class Array(interfaces.ObjectInterface, collections.Sequence):
"""Object which can contain a fixed number of an object type"""
def __init__(self, context, layer_name, offset, symbol_name, size = None, count = 0, target = None):
if not isinstance(target, templates.ObjectTemplate):
raise TypeError("Array target must be an ObjectTemplate")
super(Array, self).__init__(context = context, layer_name = layer_name, offset = offset, symbol_name = symbol_name, size = size)
self._count = count
self._target = target
@classmethod
def template_size(cls, arguments):
"""Returns the size of the array, based on the count and the target"""
if 'target' not in arguments and 'count' not in arguments:
raise TypeError("Array ObjectTemplate must be provided a count and target")
return arguments.get('target', None).size * arguments.get('count', 0)
@classmethod
def template_children(cls, arguments):
"""Returns the children of the template"""
if 'target' in arguments:
return [arguments['target']]
return []
@classmethod
def template_replace_child(cls, old_child, new_child, arguments):
"""Substitutes the old_child for the new_child"""
if 'target' in arguments:
if arguments['target'] == old_child:
arguments['target'] = new_child
def __getitem__(self, i):
"""Returns the i-th item from the array"""
return self._target(context = self._context, layer_name = self._layer_name, offset = self._offset + (self._target.size * i), parent = self)
def __len__(self):
"""Returns the length of the array"""
return self._count
class Struct(interfaces.ObjectInterface):
"""Object which can contain members that are other objects"""
def __init__(self, context, layer_name, offset, symbol_name, size = None, members = None):
super(Struct, self).__init__(context, layer_name, offset, symbol_name, size)
# Members should be an iterable mapping of symbol names to callable Object Templates
super(Struct, self).__init__(context = context,
layer_name = layer_name,
offset = offset,
symbol_name = symbol_name,
size = size)
self.check_members(members)
self._members = members
self._concrete_members = {}
@classmethod
def template_children(cls, arguments):
"""Method to list children of a template"""
cls.check_members(arguments.get('members', None))
return arguments['members'].values()
@classmethod
def template_size(cls, arguments):
"""Method to return the size of this structure"""
if arguments.get('size', None) is None:
raise TypeError("Struct ObjectTemplate not provided with a size")
return arguments['size']
@classmethod
def template_replace_child(cls, old_child, new_child, arguments):
"""Replace a child elements within the arguments handed to the template"""
for member in arguments.get('members', {}):
relative_offset, member_template = arguments['members'][member]
if member_template == old_child:
arguments['members'][member] = (relative_offset, new_child)
@classmethod
def check_members(cls, members):
# Members should be an iterable mapping of symbol names to tuples of (relative_offset, ObjectTemplate)
# An object template is a callable that when called with a context, offset, layer_name and symbol_name
if not isinstance(members, collections.Iterable):
raise TypeError("Struct members parameter must be iterable not " + type(members))
if not all([isinstance(members, templates.MemberTemplate)]):
raise TypeError("Struct members must be derived from MemberTemplate objects")
if size is None:
# Attempt to determine the maximum size by asking
for i in members:
pass
self._members = members
if not all([(isinstance(member, tuple) and len(member) == 2) for member in members.values()]):
raise TypeError("Struct members must be a tuple of relative_offsets and templates")
def __getattr__(self, attr):
"""Method for accessing members of the structure"""
if attr in self._members:
member = self._members[attr]
# Cache the constructed object
if isinstance(member, templates.ObjectTemplate):
member = member(context = self.context, layer_name = self.layer_name, offset = self.offset + member.relative_offset, parent = self)
self._members[attr] = member
if attr in self._concrete_members:
return self._concrete_members[attr]
elif attr in self._members:
relative_offset, member = self._members[attr]
member = member(context = self._context, layer_name = self._layer_name, offset = self._offset + relative_offset, parent = self)
self._concrete_members[attr] = member
return member
raise AttributeError("'" + self._symbol_name + "' Struct has no attribute '" + attr + "'")
+55 -95
View File
@@ -5,19 +5,27 @@ Created on 7 Feb 2013
'''
import collections
import volatility.framework.exceptions as exceptions
from volatility.framework import obj, templates, interfaces
from volatility.framework.exceptions import SymbolNotFoundException
import volatility.framework.exceptions as exceptions
class SymbolSpace(collections.Mapping):
"""Handles an ordered collection of SymbolLists
"""Handles an ordered collection of SymbolTables
This collection is ordered so that resolution of symbols can
proceed down through the ranks if a namespace isn't specified.
"""
def __init__(self):
def __init__(self, native_symbols):
if not isinstance(native_symbols, interfaces.NativeTableInterface):
raise TypeError("SymbolSpace native_symbols must be NativeSymbolInterface")
self._dict = collections.OrderedDict()
self._native_symbols = native_symbols
@property
def natives(self):
"""Returns the native_types for this symbol space"""
return self._native_symbols
def __len__(self):
return len(self._dict)
@@ -30,7 +38,7 @@ class SymbolSpace(collections.Mapping):
def append(self, value):
"""Adds a symbol_list to the end of the space"""
if not isinstance(value, SymbolListInterface):
if not isinstance(value, interfaces.SymbolTableInterface):
raise TypeError(value)
if value.name in self._dict:
del self._dict[value.name]
@@ -40,102 +48,54 @@ class SymbolSpace(collections.Mapping):
"""Removes a named symbol_list from the space"""
del self._dict[key]
def resolve(self, symbol, start_from = None):
"""Takes a symbol name and resolves it"""
def _weak_resolve(self, symbol):
"""Takes a symbol name and resolves it with ReferentialTemplates"""
symarr = symbol.split("!")
if len(symarr) == 2:
listname = symarr[0]
symname = symarr[1]
for symlistname in reversed(self._dict):
if symlistname == listname:
if symname in self[symlistname]:
return self[symlistname].resolve(symname, self)
else:
raise exceptions.SymbolNotFoundException("Symbol \"" + symname + "\" could not be found in the \"" + listname + "\" list")
else:
raise exceptions.SymbolNotFoundException("Symbol list \"" + listname + "\" was not present in the symbol space")
elif len(symarr) == 1:
# Establish skipping all elements before the symbol list to start from
skip = (start_from is not None)
for slist in reversed(self._dict):
if skip:
skip = (slist.name != start_from)
else:
if symbol in self[slist]:
return self[slist].resolve(symbol, self)
else:
if skip:
raise exceptions.SymbolSpaceError("Symbol search for \"" + symbol + "\" failed because symbol list \"" + start_from.name + "\" is not in the search space")
raise exceptions.SymbolNotFoundException("Symbol \"" + symbol + "\" could not be found in any symbol list")
table_name = symarr[0]
symbol_name = symarr[1]
return self._dict[table_name].resolve(symbol_name)
else:
raise exceptions.SymbolNotFoundException("Malformed symbol name")
raise RuntimeError("Symbol Space Resolution hit an unexpected branch!")
class SymbolListInterface(object):
"""Handles a list of symbols"""
def __init__(self, name, symbol_space = None, *args, **kwargs):
super(SymbolListInterface, self).__init__(*args, **kwargs)
if not isinstance(name, str) or not name:
raise exceptions.SymbolSpaceError("Symbol lists cannot be nameless")
self.name = name
self._overrides = {}
### Required Symbol List functions
def resolve(self, symbol, symbol_space = None):
"""Resolves a symbol name into an object template
def resolve(self, symbol):
"""Takes a symbol name and resolves it
symbol_space is used to resolve any target symbols if they don't exist in this list
This method ensures that all referenced templatess (inlcuding self-referential templates)
are satifsfied as ObjectTemplates
"""
resolved = {symbol: self._weak_resolve(symbol)}
weakref_list = [symbol]
while weakref_list:
weakref, weakref_list = resolved[weakref_list[0]], weakref_list[1:]
for child in weakref.children:
if isinstance(child, templates.ReferenceTemplate):
child_resolved = self._weak_resolve(child.symbol_name)
resolved[child.symbol_name] = child_resolved
weakref_list.append(child.symbol_name)
weakref.replace_child(child, child_resolved)
return resolved[symbol]
@property
def symbols(self):
"""Returns an iterator of the symbol names"""
### Functions for overriding classes
def set_symbol_class(self, symbol, clazz):
"""Overrides the object class for a specific symbol
We can only override existing classes, otherwise determining the complete symbol list
will become complicated for each subclass.
"""
if not symbol in self.symbols:
raise exceptions.SymbolNotFoundException("Cannot override \"" + symbol + "\" in \"" + self.name + "\", symbol not already present")
if not issubclass(clazz, interfaces.ObjectInterface):
raise exceptions.SymbolSpaceError("Attempting to add an object that does not inherit from ObjectInterface as a symbol class override")
self._overrides[symbol] = clazz
def has_symbol_class(self, symbol):
"""Returns whether the symbol's class has bee overridden or not"""
return symbol in self._overrides
def get_symbol_class(self, symbol):
"""Returns the class associated with a symbol or None if there is no associated symbol
"""
return self._overrides[symbol]
def del_symbol_class(self, symbol):
"""Removes the associated class override for a specific symbol"""
del self._overrides[symbol]
### Helper functions that can be overridden
def __len__(self):
"""Returns the number of items in the symbol list"""
return len(self.symbols)
def __getitem__(self, key):
"""Resolves a symbol name into an object template"""
return self.resolve(key)
def __iter__(self):
"""Returns an iterator of the available keys"""
return self.symbols
def __contains__(self, symbol):
"""Determines whether a symbol exists in the list or not"""
return symbol in self.symbols
# symarr = symbol.split("!")
# if len(symarr) == 2:
# tablename = symarr[0]
# symname = symarr[1]
# untied = set()
# symbol = self._dict[tablename].resolve(symname)
# else:
# raise exceptions.SymbolNotFoundException("Malformed symbol name")
#
#
# elif len(symarr) == 1:
# # Establish skipping all elements before the symbol list to start from
# skip = (start_from is not None)
# for slist in reversed(self._dict):
# if skip:
# skip = (slist.name != start_from)
# else:
# if symbol in self[slist]:
# return self[slist].resolve(symbol, self)
# else:
# if skip:
# raise exceptions.SymbolSpaceError("Symbol search for \"" + symbol + "\" failed because symbol list \"" + start_from.name + "\" is not in the search space")
# raise exceptions.SymbolNotFoundException("Symbol \"" + symbol + "\" could not be found in any symbol list")
+51 -39
View File
@@ -6,53 +6,65 @@ Created on 10 Apr 2013
import copy
import struct
import volatility.framework.obj as obj
import volatility.framework.symbols as symbols
import volatility.framework.templates as templates
import volatility.framework.exceptions as exceptions
import volatility.framework.interfaces as interfaces
class NativeSymbolList(symbols.SymbolListInterface):
class NativeTable(interfaces.NativeTableInterface):
"""Symbol List that handles Native types"""
def __init__(self, name, native_dictionary):
super(NativeSymbolList, self).__init__(name)
self._native_dictionary = native_dictionary
for item in self._native_dictionary:
self._overrides[item] = obj.Integer
super(NativeTable, self).__init__(name, self)
self._native_dictionary = copy.deepcopy(native_dictionary)
self._overrides = {}
for native_type in self._native_dictionary.keys():
native_class, _native_struct = self._native_dictionary[native_type]
self._overrides[native_type] = native_class
def get_symbol_class(self, symbol):
ntype, fmt = native_types.get(symbol, (obj.Integer, ''))
return ntype
@property
def symbols(self):
return self._native_dictionary.keys()
"""Returns an iterator of the symbol names"""
return set(self._native_dictionary.keys()).union(set(['Enumeration', 'array', 'BitField', 'void', 'pointer']))
def resolve(self, symbol, symbol_space = None):
"""Resolve the native symbols by looking up their struct types in a dictionary"""
if symbol in self._native_dictionary:
fmt = self._native_dictionary[symbol]
return templates.ObjectTemplate(self.get_symbol_class(symbol), symbol_name = symbol, size = struct.calcsize(fmt), format_string = fmt)
if isinstance(symbol_space, symbols.SymbolSpace):
return symbol_space.resolve(symbol, self.name)
raise exceptions.SymbolNotFoundException()
def resolve(self, symbol_name, **kwargs):
"""Resolves a symbol name into an object template
symbol_space is used to resolve any target symbols if they don't exist in this list
"""
if symbol_name == 'void':
return templates.ObjectTemplate(obj.Void, size = 0)
elif symbol_name == 'array':
return templates.ObjectTemplate(obj.Array, count = 0, target = self.resolve('void'), size = 0)
elif symbol_name == 'Enumeration':
return templates.ObjectTemplate(obj.Enumeration, target = self.resolve('void'), choices = {}, size = 0)
elif symbol_name == 'BitField':
return templates.ObjectTemplate(obj.BitField, start_bit = 0, end_bit = 0, size = 0)
x86_native_types = {'int' : '<i',
'long': '<i',
'unsigned long' : '<I',
'unsigned int' : '<I',
'address' : '<I',
'char' : '<c',
'unsigned char' : '<B',
'unsigned short int' : '<H',
'unsigned short' : '<H',
'unsigned be short' : '>H',
'short' : '<h',
'long long' : '<q',
'unsigned long long' : '<Q',
'void': "<I",
'float': "",
'double': "d"}
x64_native_types = copy.deepcopy(x86_native_types)
x64_native_types['address'] = '<Q'
_native_type, native_format = self._native_dictionary[symbol_name]
native_size = struct.calcsize(native_format)
if symbol_name == 'pointer':
return templates.ObjectTemplate(obj.Pointer, target = self.resolve('void'), size = native_size)
return templates.ObjectTemplate(self.get_symbol_class(symbol_name), symbol_name = symbol_name, struct_format = native_format, size = native_size)
x86NativeSymbolList = NativeSymbolList("native", x86_native_types)
x64NativeSymbolList = NativeSymbolList("native", x64_native_types)
for ftype in ['double', 'float']:
x86NativeSymbolList.set_symbol_class(ftype, obj.Float)
x64NativeSymbolList.set_symbol_class(ftype, obj.Float)
native_types = {'int' : (obj.Integer, '<i'),
'long': (obj.Integer, '<i'),
'unsigned long' : (obj.Integer, '<I'),
'unsigned int' : (obj.Integer, '<I'),
'pointer' : (obj.Pointer, '<I'),
'char' : (obj.Integer, '<b'),
'byte' : (obj.Bytes, '<c'),
'unsigned char' : (obj.Integer, '<B'),
'unsigned short int' : (obj.Integer, '<H'),
'unsigned short' : (obj.Integer, '<H'),
'unsigned be short' : (obj.Integer, '>H'),
'short' : (obj.Integer, '<h'),
'long long' : (obj.Integer, '<q'),
'unsigned long long' : (obj.Integer, '<Q'),
'float': (obj.Float, "<d"),
'double': (obj.Float, "<d")}
x86NativeTable = NativeTable("native", native_types)
native_types['pointer'] = '<Q'
x64NativeTable = NativeTable("native", native_types)
+58 -47
View File
@@ -4,8 +4,9 @@ Created on 10 Apr 2013
@author: mike
'''
import copy
import volatility.framework.exceptions as exceptions
import volatility.framework.symbols as symbols
import volatility.framework.interfaces as interfaces
import volatility.framework.templates as templates
import volatility.framework.obj as obj
@@ -20,69 +21,81 @@ import volatility.framework.obj as obj
# Symbol list could be a dict with knowledge of its parent?
# Class split is arbitrary, it's an extension for developers
# Object template should contain both class and initial parameters
#
#
# *** Resolution should not happen in the resolve function
# It should only happen on access of contained types ***
#
# Recursive objects can be fixed by having caching the objects
# (however, they have to be built first!)
#
# Single hop resolution is probably the solution
# Could probably deal iwth it by having a property that caches
# for container types
#
# Need to figure out how to tell the difference for vtypes between
# vtype list and a struct dictionary
class VTypeSymbolTable(interfaces.SymbolTableInterface):
"""Symbol Table that handles vtype datastructures"""
class VTypeSymbolList(symbols.SymbolListInterface):
"""Symbol List that handles vtype datastructures"""
def __init__(self, name, vtype_dictionary):
super(VTypeSymbolList, self).__init__(name)
def __init__(self, name, vtype_dictionary, native_symbols = None):
super(VTypeSymbolTable, self).__init__(name, native_symbols)
self._vtypedict = vtype_dictionary
self._default_object_class = obj.Struct
self._overrides = {}
def _vtypedict_to_template(self, dictionary, symbol_space = None):
def get_symbol_class(self, symbol):
return self._overrides.get(symbol, obj.Struct)
def set_symbol_class(self, symbol, clazz):
if symbol not in self.symbols:
raise ValueError("Symbol " + symbol + " not in " + self.name + " SymbolTable")
self._overrides[symbol] = clazz
def del_symbol_class(self, symbol):
if symbol in self._overrides:
del self._overrides[symbol]
def _vtypedict_to_template(self, dictionary):
"""Converts a vtypedict into an object template"""
if not dictionary:
raise exceptions.SymbolSpaceError("Invalid vtype dictionary: " + repr(dictionary))
# print(repr(dictionary))
symbol_name = dictionary[0]
# Establish the defaults
result = {"object_class": self._default_object_class, "symbol_name": symbol_name, "size" : 0}
# Can we handle the next layer ourselves?
if symbol_name in self.symbols:
# Check if the class has been overridden
if self.has_symbol_class(symbol_name):
result["object_class"] = self.get_symbol_class(symbol_name)
if symbol_name not in self.symbols:
# Handle specific "well known" symbols
if symbol_name in self.natives:
# The symbol is a native type
native_template = self.natives.resolve(symbol_name)
# Add specific additional parameters, etc
update = {}
if symbol_name == 'array':
result["object_class"] = obj.Integer
result["count"] = dictionary[1]
result["target"] = self._vtypedict_to_template(dictionary[2], symbol_space = symbol_space)
result["size"] = dictionary[1] * result["target"].size
update['count'] = dictionary[1],
update['target'] = self._vtypedict_to_template(dictionary[2])
elif symbol_name == 'pointer':
result["object_class"] = obj.Pointer
result["target"] = self._vtypedict_to_template(dictionary[1], symbol_space = symbol_space)
update["target"] = self._vtypedict_to_template(dictionary[1])
elif symbol_name == 'Enumeration':
result["object_class"] = obj.Integer
result.update(dictionary[1])
result["target"] = self._vtypedict_to_template([result["target"]], symbol_space = symbol_space)
update = copy.deepcopy(dictionary[1])
update["target"] = self._vtypedict_to_template([update['target']])
elif symbol_name == 'BitField':
result["object_class"] = obj.Pointer
result["fields"] = dictionary[1]
elif symbol_name == 'void':
result["object_class"] = obj.Integer
elif len(dictionary) > 1:
raise exceptions.SymbolSpaceError("Unknown vtype format: " + repr(dictionary))
elif isinstance(symbol_space, symbols.SymbolSpace):
# Resolve the object class for this
return symbol_space.resolve(symbol_name)
else:
raise exceptions.SymbolNotFoundException("Unable to resolve \"" + symbol_name + "\" in \"" + self.name + "\", no symbol space to rescurse through")
elif self.has_symbol_class(symbol_name):
result["object_class"] = self.get_symbol_class(symbol_name)
update = dictionary[1]
update['target'] = self._vtypedict_to_template([update['native_type']])
native_template.update_arguments(**update) #pylint: disable-msg=W0142
return native_template
print(result)
return templates.ObjectTemplate(**result) #pylint: disable-msg=W0142
# Otherwise
if len(dictionary) > 1:
print("Symbol name", symbol_name)
raise exceptions.SymbolSpaceError("Unknown vtype format: " + repr(dictionary))
return templates.ReferenceTemplate(symbol_name = symbol_name)
@property
def symbols(self):
"""Returns an iterator of the symbol names"""
return self._vtypedict.keys()
def resolve(self, symbol_name, symbol_space = None):
def resolve(self, symbol_name):
"""Resolves an individual symbol"""
if symbol_name not in self._vtypedict:
raise exceptions.SymbolNotFoundException
@@ -90,9 +103,7 @@ class VTypeSymbolList(symbols.SymbolListInterface):
members = {}
for member_name in curdict:
relative_offset, vtypedict = curdict[member_name]
member = templates.member_from_object_template(relative_offset = relative_offset, object_template = self._vtypedict_to_template(vtypedict, symbol_space))
member = (relative_offset, self._vtypedict_to_template(vtypedict))
members[member_name] = member
object_class = self._default_object_class
if self.has_symbol_class(symbol_name):
object_class = self.get_symbol_class(symbol_name)
object_class = self.get_symbol_class(symbol_name)
return templates.ObjectTemplate(object_class = object_class, symbol_name = symbol_name, size = size, members = members)
+26 -45
View File
@@ -4,10 +4,9 @@ Created on 1 Mar 2013
@author: mike
'''
import copy
import volatility.framework.interfaces as interfaces
class ObjectTemplate(object):
class ObjectTemplate(interfaces.Template):
"""Factory class that produces objects that adhere to the Object interface on demand
This is effectively a method of currying, but adds more structure to avoid abuse.
@@ -16,62 +15,44 @@ class ObjectTemplate(object):
* Members, etc
etc.
"""
def __init__(self, object_class = None, symbol_name = None, size = None, **kwargs):
def __init__(self, object_class = None, symbol_name = None, **kwargs):
super(ObjectTemplate, self).__init__(symbol_name = symbol_name, **kwargs)
if not issubclass(object_class, interfaces.ObjectInterface):
raise TypeError("ObjectTemplate object_class must be a class, not " + str(type(object_class)))
if not isinstance(size, int):
raise TypeError("ObjectTemplate size must be numeric, not " + str(type(size)))
self._size = size
self._symbol_name = symbol_name
self._kwargs = kwargs
self._object_class = object_class
@property
def object_class(self):
return self._object_class
raise TypeError("ObjectTemplate object_class must inherit from ObjectInterface")
self.object_class = object_class
@property
def size(self):
return self._size
"""Returns the size of the template"""
return self.object_class.template_size(self._kwargs)
@property
def symbol_name(self):
"""Returns the name of the symbol if one was provided"""
return self._symbol_name
def children(self):
"""A function that returns a list of child templates of a template
This is used to traverse the template tree
"""
return self.object_class.template_children(self._kwargs)
@property
def kwargs(self):
return copy.deepcopy(self._kwargs)
def replace_child(self, old_child, new_child):
"""A function for replacing one child with another
We pass in the kwargs directly so they can be changed
"""
self.object_class.replace_child(old_child, new_child, self._kwargs)
def __call__(self, context, layer_name, offset, parent = None):
"""Constructs the object
Returns: an object adhereing to the Object interface
"""
return self._object_class(context = context, layer_name = layer_name, offset = offset, symbol_name = self.symbol_name, size = self.size, parent = parent, **self._kwargs)
return self.object_class(context = context, layer_name = layer_name, offset = offset, symbol_name = self.symbol_name, size = self.size, parent = parent, **self._kwargs)
def member_from_object_template(relative_offset, object_template):
"""Returns a MemberTemplate based upon an existing ObjectTemplate"""
if not isinstance(object_template, ObjectTemplate):
raise TypeError("object_template must be an ObjectTemplate, not " + str(type(object_template)))
return MemberTemplate(relative_offset = relative_offset,
object_class = object_template.object_class,
symbol_name = object_template.symbol_name,
size = object_template.size,
**object_template.kwargs)
class MemberTemplate(ObjectTemplate):
"""Factory class that produces members of Structs
class ReferenceTemplate(interfaces.Template):
"""Factory class that produces objects based on a delayed reference type
This is just like a normal ObjectTemplate, but contains the relative offset
fron the parent object.
It should not return any attributes
"""
def __init__(self, relative_offset, **kwargs):
super(MemberTemplate, self).__init__(**kwargs)
if not isinstance(relative_offset, int):
raise TypeError("MemberTemplate relative_offset must be numeric, not " + str(type(relative_offset)))
self._relative_offset = relative_offset
@property
def relative_offset(self):
return self._relative_offset
def __call__(self, context, *args, **kwargs):
template = context.symbol_space.resolve(self._symbol_name)
return template(context = context, *args, **kwargs)