diff --git a/test_rig.py b/test_rig.py index e8608c529..0d9b9f076 100644 --- a/test_rig.py +++ b/test_rig.py @@ -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() diff --git a/volatility/framework/context.py b/volatility/framework/context.py index 02f65545f..7c6e4f051 100644 --- a/volatility/framework/context.py +++ b/volatility/framework/context.py @@ -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 diff --git a/volatility/framework/interfaces.py b/volatility/framework/interfaces.py index 3975011bc..3d51b990d 100644 --- a/volatility/framework/interfaces.py +++ b/volatility/framework/interfaces.py @@ -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""" diff --git a/volatility/framework/obj.py b/volatility/framework/obj.py index 554b83623..87ac52fe2 100644 --- a/volatility/framework/obj.py +++ b/volatility/framework/obj.py @@ -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 = 'H', - 'short' : 'H'), + 'short' : (obj.Integer, ' 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) diff --git a/volatility/framework/templates.py b/volatility/framework/templates.py index 794470959..9d1291791 100644 --- a/volatility/framework/templates.py +++ b/volatility/framework/templates.py @@ -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)