Add in write support, and change symbols to be both structures and constants.

This commit is contained in:
Mike Auty
2013-12-28 05:30:54 +00:00
parent cea4969b49
commit 26f8d0f7cc
10 changed files with 179 additions and 88 deletions
+27 -7
View File
@@ -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()
+1 -1
View File
@@ -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)
+1 -1
View File
@@ -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):
@@ -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)
+54 -37
View File
@@ -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 []
+50
View File
@@ -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")
+1 -1
View File
@@ -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)
+13 -13
View File
@@ -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:
+11 -11
View File
@@ -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)
+17 -17
View File
@@ -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)