From 26f8d0f7cce19d81f72f65805e668b13c37efbb1 Mon Sep 17 00:00:00 2001 From: Mike Auty Date: Sat, 28 Dec 2013 05:30:54 +0000 Subject: [PATCH] Add in write support, and change symbols to be both structures and constants. --- test_rig.py | 34 ++++++-- volatility/framework/__init__.py | 2 +- volatility/framework/exceptions.py | 2 +- volatility/framework/interfaces/objects.py | 4 + volatility/framework/interfaces/symbols.py | 91 +++++++++++++--------- volatility/framework/objects/__init__.py | 50 ++++++++++++ volatility/framework/objects/templates.py | 2 +- volatility/framework/symbols/__init__.py | 26 +++---- volatility/framework/symbols/native.py | 22 +++--- volatility/framework/symbols/vtypes.py | 34 ++++---- 10 files changed, 179 insertions(+), 88 deletions(-) diff --git a/test_rig.py b/test_rig.py index de465324e..0ef0b784f 100644 --- a/test_rig.py +++ b/test_rig.py @@ -18,14 +18,26 @@ def test_symbols(): ctx = framework.Context(nativelst) # ctx.symbol_space.append(nativelst) - ctx.symbol_space.append(ntkrnlmp) - print("Symbols,", nativelst.symbols) + ctx = utils_load_as() + print("Symbols,", nativelst.structures) - for i in list(ntkrnlmp.symbols): - symbol = ctx.symbol_space.resolve('ntkrnlmp!' + i) + for i in list(ntkrnlmp.structures): + symbol = ctx.symbol_space.get_structure('ntkrnlmp!' + i) print(symbol.symbol_name, symbol, symbol.size) _objthing = symbol(ctx, layer_name = '', offset = 0) - symbol = ctx.symbol_space.resolve('ntkrnlmp!_EPROCESS') + symbol = ctx.symbol_space.get_structure('ntkrnlmp!_EPROCESS') + +def utils_load_as(): + nativelst = native.x86NativeTable + + virtual_types = xp_sp2_x86_vtypes.ntkrnlmp_types + + ntkrnlmp = vtypes.VTypeSymbolTable('ntkrnlmp', virtual_types, nativelst) + + ctx = framework.Context(nativelst) + # ctx.symbol_space.append(nativelst) + ctx.symbol_space.append(ntkrnlmp) + return ctx def test_memory(): nativelst = native.x86NativeTable @@ -47,6 +59,14 @@ def test_memory(): val = ctx.object('ntkrnlmp!TEST_POINTER', 'data', 0) print(hex(val.point1.test1), val.point1.test2) +def test_kdbgfind(ctx): + ctx = utils_load_as() + base = layers.physical.FileLayer(ctx, 'data', filename = '/home/mike/memory/xp-laptop-2005-06-25.img') + ctx.memory.add_layer(base) + intel = layers.intel.Intel(ctx, 'intel', 'data', page_map_offset = 0x39000) + ctx.memory.add_layer(intel) + + def intel32(ctx): base = layers.physical.FileLayer(ctx, 'data', filename = '/home/mike/memory/xp-laptop-2005-06-25.img') ctx.memory.add_layer(base) @@ -94,9 +114,9 @@ if __name__ == '__main__': # import timeit # print(timeit.Timer(main).timeit(10)) try: - # test_symbols() + test_symbols() # test_memory() - test_translation() + # test_translation() except Exception as e: print(repr(e)) pdb.post_mortem() diff --git a/volatility/framework/__init__.py b/volatility/framework/__init__.py index c36e883f6..977f7b090 100644 --- a/volatility/framework/__init__.py +++ b/volatility/framework/__init__.py @@ -64,7 +64,7 @@ class Context(interfaces.context.ContextInterface): Returns a fully constructed object """ - object_template = self._symbol_space.resolve(symbol) + object_template = self._symbol_space.get_structure(symbol) return object_template(self, layer_name = layer_name, offset = offset) diff --git a/volatility/framework/exceptions.py b/volatility/framework/exceptions.py index 7c0f233fa..9ef1d1cdf 100644 --- a/volatility/framework/exceptions.py +++ b/volatility/framework/exceptions.py @@ -7,7 +7,7 @@ Created on 1 Dec 2012 class VolatilityException(Exception): """Class to allow filtering of all VolatilityExceptions""" -class SymbolNotFoundException(VolatilityException): +class SymbolError(VolatilityException): """Thrown when a symbol lookup has failed""" class InvalidAddressException(VolatilityException): diff --git a/volatility/framework/interfaces/objects.py b/volatility/framework/interfaces/objects.py index f829a042e..9145fa907 100644 --- a/volatility/framework/interfaces/objects.py +++ b/volatility/framework/interfaces/objects.py @@ -21,7 +21,11 @@ class ObjectInterface(validity.ValidityRoutines): self._symbol_name = symbol_name self._size = size + def write(self, value): + """Writes the new value into the format at the offset the object currently resides at""" + def cast(self, new_symbol_name): + """Returns a new object at the offset and from the layer that the current object inhabits""" object_template = self._context.symbol_space.resolve(new_symbol_name) return object_template(context = self._context, layer_name = self._layer_name, offset = self._offset) diff --git a/volatility/framework/interfaces/symbols.py b/volatility/framework/interfaces/symbols.py index eee21a3ef..b1b54f70f 100644 --- a/volatility/framework/interfaces/symbols.py +++ b/volatility/framework/interfaces/symbols.py @@ -4,70 +4,87 @@ Created on 4 May 2013 @author: mike ''' -from volatility.framework import validity +from volatility.framework import validity, exceptions class SymbolTableInterface(validity.ValidityRoutines): """Handles a table of symbols""" - def __init__(self, name, native_symbols = None): + def __init__(self, name, native_structures = None): self.name = self.type_check(name or None, str) - self._native_symbols = self.type_check(native_symbols, NativeTableInterface) + self._native_structures = self.type_check(native_structures, NativeTableInterface) - #TODO: Add in support for constants + ### Required Constant symbol functions - ### Required Symbol List functions + def get_constant(self, name): + """Resolves a symbol name into a constant + + If the symbol isn't found, it raises a SymbolError exception + """ - def resolve(self, symbol): + @ property + def constants(self): + """Returns an iterator of the constant symbols""" + + ### Required Structure symbol functions + + def get_structure(self, name): """Resolves a symbol name into an object template - If the symbol isn't found it raises a SymbolNotFound exception + If the symbol isn't found it raises a SymbolError exception """ @property - def symbols(self): - """Returns an iterator of the symbol names""" + def structures(self): + """Returns an iterator of the structure symbols""" ### Native Type Handler @property def natives(self): """Returns None or a symbol_space for handling space specific native types""" - return self._native_symbols + return self._native_structures ### Functions for overriding classes - def set_symbol_class(self, symbol, clazz): - """Overrides the object class for a specific symbol + def set_structure_class(self, name, clazz): + """Overrides the object class for a specific structure symbol - Symbol *must* be present in self.symbols + Name *must* be present in self.structures """ - def get_symbol_class(self, symbol): - """Returns the class associated with a symbol""" + def get_structure_class(self, name): + """Returns the class associated with a structure symbol""" - def del_symbol_class(self, symbol): - """Removes the associated class override for a specific symbol""" + def del_structure_class(self, name): + """Removes the associated class override for a specific structure 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 +# ### Helper functions that can be overridden +# +# def __len__(self): +# """Returns the number of items in the symbol list""" +# return len(self.structures) +# +# 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.get_structure(key) +# +# def __iter__(self): +# """Returns an iterator of the available keys""" +# return self.structures +# +# def __contains__(self, symbol): +# """Determines whether a symbol exists in the list or not""" +# return symbol in self.structures class NativeTableInterface(SymbolTableInterface): """Class to distinguish NativeSymbolLists from other symbol lists""" + + def constant(self): + raise exceptions.SymbolError("NativeTables never hold constants") + + @property + def constants(self): + return [] diff --git a/volatility/framework/objects/__init__.py b/volatility/framework/objects/__init__.py index dde7f4608..2e5f2a116 100644 --- a/volatility/framework/objects/__init__.py +++ b/volatility/framework/objects/__init__.py @@ -65,27 +65,65 @@ class Integer(PrimitiveObject, int): def __new__(cls, context, layer_name, offset, symbol_name, struct_format, **kwargs): return int.__new__(cls, cls._struct_value(struct_format, context, layer_name, offset, symbol_name)) + def write(self, value): + """Writes the object into the layer of the context at the current offset""" + if isinstance(value, int): + data = struct.pack(self._struct_format, value) + return self._context.memory.write(self._layer_name, self._offset, data) + raise TypeError("Integer objects require an integer to be written") + class Float(PrimitiveObject, float): """Primitive Object that handles double or floating point numbers""" def __new__(cls, context, layer_name, offset, symbol_name, struct_format, **kwargs): return float.__new__(cls, cls._struct_value(struct_format, context, layer_name, offset, symbol_name)) + def write(self, value): + """Writes the object into the layer of the context at the current offset""" + if isinstance(value, float): + data = struct.pack(self._struct_format, value) + return self._context.memory.write(self._layer_name, self._offset, data) + raise TypeError("Float objects require a float to be written") + class Bytes(PrimitiveObject, bytes): """Primitive Object that handles specific series of bytes""" + def __init__(self, context, layer_name, offset, symbol_name, size = None, parent = None, length = 1, **kwargs): + bytes.__init__() + PrimitiveObject.__init__(self, context, layer_name, offset, symbol_name, size, parent, struct_format = str(length) + 's') + self.length = length + def __new__(cls, context, layer_name, offset, symbol_name, length = 1, **kwargs): return bytes.__new__(cls, cls._struct_value(str(length) + "s", context, layer_name, offset, symbol_name)) + def write(self, value): + """Writes the object into the layer of the context at the current offset""" + if isinstance(value, bytes): + data = struct.pack(self._struct_format, value) + return self._context.memory.write(self._layer_name, self._offset, data) + raise TypeError("Bytes objects require a bytes type to be written") + class String(PrimitiveObject, str): """Primitive Object that handles string values length: specifies the maximum possible length that the string could hold in memory """ + def __init__(self, context, layer_name, offset, symbol_name, size = None, parent = None, length = 1, **kwargs): + str.__init__() + PrimitiveObject.__init__(self, context, layer_name, offset, symbol_name, size, parent, struct_format = str(length) + 's') + self.length = length + def __new__(cls, context, layer_name, offset, symbol_name, length = 1, **kwargs): return str.__new__(cls, cls._struct_value(str(length) + "s", context, layer_name, offset, symbol_name)) + def write(self, value): + """Writes the object into the layer of the context at the current offset""" + if isinstance(value, str): + data = struct.pack(self._struct_format, value) + return self._context.memory.write(self._layer_name, self._offset, data) + raise TypeError("String objects require a string to be written") + class Pointer(Integer): """Pointer which points to another object""" def __init__(self, context, layer_name, offset, symbol_name, size = None, parent = None, struct_format = None, target = None): @@ -147,6 +185,9 @@ class BitField(PrimitiveObject, int): return [arguments['target']] return [] + def write(self, value): + raise NotImplementedError("Writing to BitFields is not yet implemented") + class Enumeration(interfaces.objects.ObjectInterface): """Returns an object made up of choices""" # FIXME: Add in body for the enumeration object @@ -154,6 +195,9 @@ class Enumeration(interfaces.objects.ObjectInterface): def template_children(cls, arguments): return [] + def write(self, value): + raise NotImplementedError("Writing to Enumerations is not yet implemented") + class Array(interfaces.objects.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, parent = None, count = 0, target = None): @@ -198,6 +242,9 @@ class Array(interfaces.objects.ObjectInterface, collections.Sequence): """Returns the length of the array""" return self._count + def write(self, value): + raise NotImplementedError("Writing to Arrays is not yet implemented") + class Struct(interfaces.objects.ObjectInterface): """Object which can contain members that are other objects""" @@ -253,3 +300,6 @@ class Struct(interfaces.objects.ObjectInterface): self._concrete_members[attr] = member return member raise AttributeError("'" + self._symbol_name + "' Struct has no attribute '" + attr + "'") + + def write(self, value): + raise TypeError("Structs cannot be written to directly, invidivual members must be written instead") diff --git a/volatility/framework/objects/templates.py b/volatility/framework/objects/templates.py index 7fe3af497..61422f826 100644 --- a/volatility/framework/objects/templates.py +++ b/volatility/framework/objects/templates.py @@ -56,5 +56,5 @@ class ReferenceTemplate(interfaces.objects.Template): It should not return any attributes """ def __call__(self, context, *args, **kwargs): - template = context.symbol_space.resolve(self._symbol_name) + template = context.symbol_space.get_structure(self._symbol_name) return template(context = context, *args, **kwargs) diff --git a/volatility/framework/symbols/__init__.py b/volatility/framework/symbols/__init__.py index 3a63983ad..98aa426c4 100644 --- a/volatility/framework/symbols/__init__.py +++ b/volatility/framework/symbols/__init__.py @@ -14,18 +14,18 @@ class SymbolSpace(collections.Mapping): proceed down through the ranks if a namespace isn't specified. """ - def __init__(self, native_symbols): - if not isinstance(native_symbols, interfaces.symbols.NativeTableInterface): - raise TypeError("SymbolSpace native_symbols must be NativeSymbolInterface") + def __init__(self, native_structures): + if not isinstance(native_structures, interfaces.symbols.NativeTableInterface): + raise TypeError("SymbolSpace native_structures must be NativeSymbolInterface") self._dict = collections.OrderedDict() - self._native_symbols = native_symbols + self._native_structures = native_structures # Permanently cache all resolved symbols self._resolved = {} @property def natives(self): """Returns the native_types for this symbol space""" - return self._native_symbols + return self._native_structures def __len__(self): return len(self._dict) @@ -46,7 +46,7 @@ class SymbolSpace(collections.Mapping): def remove(self, key): """Removes a named symbol_list from the space""" - # Reset the resolved list, since we're removing ssome symbols + # Reset the resolved list, since we're removing some symbols self._resolved = {} del self._dict[key] @@ -56,16 +56,16 @@ class SymbolSpace(collections.Mapping): if len(symarr) == 2: table_name = symarr[0] symbol_name = symarr[1] - return self._dict[table_name].resolve(symbol_name) - elif symbol in self.natives: - return self.natives.resolve(symbol) - raise exceptions.SymbolNotFoundException("Malformed symbol name") + return self._dict[table_name].get_structure(symbol_name) + elif symbol in self.natives.structures: + return self.natives.get_structure(symbol) + raise exceptions.SymbolError("Malformed symbol name") - def resolve(self, symbol): + def get_structure(self, symbol): """Takes a symbol name and resolves it - This method ensures that all referenced templatess (inlcuding self-referential templates) - are satifsfied as ObjectTemplates + This method ensures that all referenced templates (including self-referential templates) + are satisfied as ObjectTemplates """ # Traverse down any resolutions if symbol not in self._resolved: diff --git a/volatility/framework/symbols/native.py b/volatility/framework/symbols/native.py index bf4d49465..1db5e692d 100644 --- a/volatility/framework/symbols/native.py +++ b/volatility/framework/symbols/native.py @@ -17,18 +17,18 @@ class NativeTable(interfaces.symbols.NativeTableInterface): native_class, _native_struct = self._native_dictionary[native_type] self._overrides[native_type] = native_class # Create this once early, because it may get used a lot - self._symbols = set(self._native_dictionary.keys()).union(set(['Enumeration', 'array', 'BitField', 'void', 'pointer'])) + self._structures = set(self._native_dictionary.keys()).union(set(['Enumeration', 'array', 'BitField', 'void', 'pointer'])) - def get_symbol_class(self, symbol): - ntype, fmt = native_types.get(symbol, (objects.Integer, '')) + def get_structure_class(self, name): + ntype, fmt = native_types.get(name, (objects.Integer, '')) return ntype @property - def symbols(self): - """Returns an iterator of the symbol names""" - return self._symbols + def structures(self): + """Returns an iterator of the structure symbol names""" + return self._structures - def resolve(self, symbol_name): + def get_structure(self, symbol_name): """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 @@ -37,16 +37,16 @@ class NativeTable(interfaces.symbols.NativeTableInterface): if symbol_name == 'void': return objects.templates.ObjectTemplate(objects.Void, symbol_name = symbol_name) elif symbol_name == 'array': - return objects.templates.ObjectTemplate(objects.Array, symbol_name = symbol_name, count = 0, target = self.resolve('void')) + return objects.templates.ObjectTemplate(objects.Array, symbol_name = symbol_name, count = 0, target = self.get_structure('void')) elif symbol_name == 'Enumeration': - return objects.templates.ObjectTemplate(objects.Enumeration, symbol_name = symbol_name, target = self.resolve('void'), choices = {}) + return objects.templates.ObjectTemplate(objects.Enumeration, symbol_name = symbol_name, target = self.get_structure('void'), choices = {}) elif symbol_name == 'BitField': return objects.templates.ObjectTemplate(objects.BitField, symbol_name = symbol_name, start_bit = 0, end_bit = 0) _native_type, native_format = self._native_dictionary[symbol_name] if symbol_name == 'pointer': - additional = {'target': self.resolve('void')} - return objects.templates.ObjectTemplate(self.get_symbol_class(symbol_name), #pylint: disable-msg=W0142 + additional = {'target': self.get_structure('void')} + return objects.templates.ObjectTemplate(self.get_structure_class(symbol_name), #pylint: disable-msg=W0142 symbol_name = symbol_name, struct_format = native_format, **additional) diff --git a/volatility/framework/symbols/vtypes.py b/volatility/framework/symbols/vtypes.py index b8e1488ac..836bab94e 100644 --- a/volatility/framework/symbols/vtypes.py +++ b/volatility/framework/symbols/vtypes.py @@ -36,22 +36,22 @@ from volatility.framework import exceptions, objects, interfaces class VTypeSymbolTable(interfaces.symbols.SymbolTableInterface): """Symbol Table that handles vtype datastructures""" - def __init__(self, name, vtype_dictionary, native_symbols = None): - interfaces.symbols.SymbolTableInterface.__init__(self, name, native_symbols) + def __init__(self, name, vtype_dictionary, native_structures = None): + interfaces.symbols.SymbolTableInterface.__init__(self, name, native_structures) self._vtypedict = vtype_dictionary self._overrides = {} - def get_symbol_class(self, symbol): - return self._overrides.get(symbol, objects.Struct) + def get_structure_class(self, name): + return self._overrides.get(name, objects.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 set_structure_class(self, name, clazz): + if name not in self.structures: + raise ValueError("Symbol " + name + " not in " + self.name + " SymbolTable") + self._overrides[name] = clazz - def del_symbol_class(self, symbol): - if symbol in self._overrides: - del self._overrides[symbol] + def del_structure_class(self, name): + if name in self._overrides: + del self._overrides[name] def _vtypedict_to_template(self, dictionary): """Converts a vtypedict into an object template""" @@ -60,9 +60,9 @@ class VTypeSymbolTable(interfaces.symbols.SymbolTableInterface): symbol_name = dictionary[0] - if symbol_name in self.natives: + if symbol_name in self.natives.structures: # The symbol is a native type - native_template = self.natives.resolve(symbol_name) + native_template = self.natives.get_structure(symbol_name) # Add specific additional parameters, etc update = {} @@ -87,19 +87,19 @@ class VTypeSymbolTable(interfaces.symbols.SymbolTableInterface): return objects.templates.ReferenceTemplate(symbol_name = self.name + "!" + symbol_name) @property - def symbols(self): + def structures(self): """Returns an iterator of the symbol names""" return self._vtypedict.keys() - def resolve(self, symbol_name): + def get_structure(self, symbol_name): """Resolves an individual symbol""" if symbol_name not in self._vtypedict: - raise exceptions.SymbolNotFoundException + raise exceptions.SymbolError size, curdict = self._vtypedict[symbol_name] members = {} for member_name in curdict: relative_offset, vtypedict = curdict[member_name] member = (relative_offset, self._vtypedict_to_template(vtypedict)) members[member_name] = member - object_class = self.get_symbol_class(symbol_name) + object_class = self.get_structure_class(symbol_name) return objects.templates.ObjectTemplate(object_class = object_class, symbol_name = symbol_name, size = size, members = members)