From 8e7ad364c7dec46d7121306d43321ac9408de21b Mon Sep 17 00:00:00 2001 From: Mike Auty Date: Tue, 8 Apr 2014 00:59:08 +0100 Subject: [PATCH] Alter type/class checking structure so that it can be optimized out (either throws an exception or does nothing). --- test_rig.py | 33 +++++++++++++--------- volatility/framework/config.py | 11 ++++---- volatility/framework/interfaces/layers.py | 6 ++-- volatility/framework/interfaces/objects.py | 11 ++++++-- volatility/framework/interfaces/plugins.py | 3 +- volatility/framework/interfaces/symbols.py | 7 +++-- volatility/framework/objects/templates.py | 11 +++++++- volatility/framework/renderers/__init__.py | 9 +++--- volatility/framework/renderers/basic.py | 20 +++++++++++++ volatility/framework/validity.py | 22 +++++++++------ 10 files changed, 93 insertions(+), 40 deletions(-) diff --git a/test_rig.py b/test_rig.py index 62f869ac5..16e4d579b 100644 --- a/test_rig.py +++ b/test_rig.py @@ -1,8 +1,8 @@ -''' +""" Created on 10 Mar 2013 @author: mike -''' +""" import pdb from volatility import framework @@ -24,7 +24,7 @@ def test_symbols(): for i in list(ntkrnlmp.structures): symbol = ctx.symbol_space.get_structure('ntkrnlmp!' + i) print(symbol.structure_name, symbol, symbol.size) - _objthing = symbol(ctx, layer_name = '', offset = 0) + _ = symbol(ctx, layer_name = '', offset = 0) symbol = ctx.symbol_space.get_structure('ntkrnlmp!_EPROCESS') def utils_load_as(): @@ -42,13 +42,8 @@ def utils_load_as(): def test_memory(): nativelst = native.x86NativeTable virtual_types = xp_sp2_x86_vtypes.ntkrnlmp_types - virtual_types['TEST_POINTER'] = [0x4, - {'point1': [0x0, ['pointer', ['TEST_SYMBOL']]] - }] - virtual_types['TEST_SYMBOL'] = [0x6, - {'test1': [0x0, ['unsigned int']], - 'test2': [0x4, ['unsigned short']] - }] + virtual_types['TEST_POINTER'] = [0x4, {'point1': [0x0, ['pointer', ['TEST_SYMBOL']]]}] + virtual_types['TEST_SYMBOL'] = [0x6, {'test1': [0x0, ['unsigned int']], 'test2': [0x4, ['unsigned short']]}] ntkrnlmp = vtypes.VTypeSymbolTable('ntkrnlmp', virtual_types, nativelst) ctx = framework.Context(nativelst) @@ -71,21 +66,33 @@ def intel32(ctx): 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) - x = [0x823c87c0, 0x81fdf020, 0x81f5a3b8, 0x81f8eb10, 0x820e0da0, 0x82199668, 0x81fa5aa0, 0x81fa8650, 0x81faba78, 0x81fa8240, 0x81f8dda0, 0x81f6e7e8, 0x81f9a670, 0x81f5f020, 0x8202bda0, 0x82113c48, 0x81f67500, 0x81f6ca90, 0x820dd588, 0x82025608, 0x81faf280, 0x821125d0, 0x82076558, 0x81f68518, 0x82059da0, 0x81f6db28, 0x82021a78, 0x81f48da0, 0x820238e0, 0x82081da0, 0x821ca3d0, 0x821ce4d8, 0x821d4da0, 0x81343790, 0xffab8020, 0x8205eda0, 0xffaa0c10, 0x82218020, 0x814b13b0, 0x81ed76b0, 0x81f269e0, 0xffadc9d0, 0x821fb3b8, 0x82079c18, 0x82000980, 0x822148f0, 0x81ed84e8] + x = [0x823c87c0, 0x81fdf020, 0x81f5a3b8, 0x81f8eb10, 0x820e0da0, 0x82199668, 0x81fa5aa0, 0x81fa8650, 0x81faba78, + 0x81fa8240, 0x81f8dda0, 0x81f6e7e8, 0x81f9a670, 0x81f5f020, 0x8202bda0, 0x82113c48, 0x81f67500, 0x81f6ca90, + 0x820dd588, 0x82025608, 0x81faf280, 0x821125d0, 0x82076558, 0x81f68518, 0x82059da0, 0x81f6db28, 0x82021a78, + 0x81f48da0, 0x820238e0, 0x82081da0, 0x821ca3d0, 0x821ce4d8, 0x821d4da0, 0x81343790, 0xffab8020, 0x8205eda0, + 0xffaa0c10, 0x82218020, 0x814b13b0, 0x81ed76b0, 0x81f269e0, 0xffadc9d0, 0x821fb3b8, 0x82079c18, 0x82000980, + 0x822148f0, 0x81ed84e8] return intel, x def intelpae(ctx): base = layers.physical.FileLayer(ctx, 'data', filename = '/home/mike/memory/private/jon-fres.dmp') ctx.memory.add_layer(base) intel = layers.intel.IntelPAE(ctx, 'intel', 'data', page_map_offset = 0x319000) - x = [0x81bcc830, 0x81989940, 0x81915020, 0x8192ad18, 0x818fa7b8, 0x818f6da0, 0x818d1020, 0x818b2878, 0x8189f180, 0x8188db58, 0x81884a40, 0x818766b0, 0x8185a948, 0x8183ad70, 0x81826020, 0x818a64c8, 0x81818020, 0x81800020, 0x817ff460, 0x817eb020, 0x817e9020, 0x817a62a8, 0x817a4b28, 0x81865020, 0x817972c0] + x = [0x81bcc830, 0x81989940, 0x81915020, 0x8192ad18, 0x818fa7b8, 0x818f6da0, 0x818d1020, 0x818b2878, 0x8189f180, + 0x8188db58, 0x81884a40, 0x818766b0, 0x8185a948, 0x8183ad70, 0x81826020, 0x818a64c8, 0x81818020, 0x81800020, + 0x817ff460, 0x817eb020, 0x817e9020, 0x817a62a8, 0x817a4b28, 0x81865020, 0x817972c0] return intel, x def intel32e(ctx): base = layers.physical.FileLayer(ctx, 'data', filename = '/home/mike/memory/private/ikelos-winxpsp2-x64.dmp') ctx.memory.add_layer(base) intel = layers.intel.Intel32e(ctx, 'intel', 'data', page_map_offset = 0x3c3000) - x = [0xfffffadffa517c20, 0xfffffadffa2c9510, 0xfffffadffb16a660, 0xfffffadff9d77c20, 0xfffffadffb0fe040, 0xfffffadffb0f2040, 0xfffffadffb0c2040, 0xfffffadffb0b7c20, 0xfffffadffb087c20, 0xfffffadffb06a760, 0xfffffadffb039c20, 0xfffffadffb02c040, 0xfffffadffafe9c20, 0xfffffadffafa7040, 0xfffffadffaf2e040, 0xfffffadffaf279a0, 0xfffffadffaf24600, 0xfffffadffaed3040, 0xfffffadffaecf040, 0xfffffadffaeb35a0, 0xfffffadffae747b0, 0xfffffadffae30040, 0xfffffadffae2b040, 0xfffffadffae1d8b0, 0xfffffadffae1a040, 0xfffffadffae34810] + x = [0xfffffadffa517c20, 0xfffffadffa2c9510, 0xfffffadffb16a660, 0xfffffadff9d77c20, 0xfffffadffb0fe040, + 0xfffffadffb0f2040, 0xfffffadffb0c2040, 0xfffffadffb0b7c20, 0xfffffadffb087c20, 0xfffffadffb06a760, + 0xfffffadffb039c20, 0xfffffadffb02c040, 0xfffffadffafe9c20, 0xfffffadffafa7040, 0xfffffadffaf2e040, + 0xfffffadffaf279a0, 0xfffffadffaf24600, 0xfffffadffaed3040, 0xfffffadffaecf040, 0xfffffadffaeb35a0, + 0xfffffadffae747b0, 0xfffffadffae30040, 0xfffffadffae2b040, 0xfffffadffae1d8b0, 0xfffffadffae1a040, + 0xfffffadffae34810] return intel, x diff --git a/volatility/framework/config.py b/volatility/framework/config.py index 77a450b36..b1af15b3e 100644 --- a/volatility/framework/config.py +++ b/volatility/framework/config.py @@ -10,7 +10,8 @@ class Option(validity.ValidityRoutines): """Class to handle a single specific configuration option""" def __init__(self, name, option_type, definition = None, description = None): """Creates a new option""" - self._option_type = self.type_check(option_type, type) + self.type_check(option_type, type) + self._option_type = option_type self._name = name self._description = description self._definition = definition @@ -45,8 +46,8 @@ class ConfigurationGroup(validity.ValidityRoutines): def __setattr__(self, name, value): if name == '_options': setattr(self, name, value) - if self.type_check(value, Option): - self._options[name] = value + self.type_check(value, Option) + self._options[name] = value raise TypeError("Attribute " + name + " must be an Option object") class Configuration(validity.ValidityRoutines): @@ -64,6 +65,6 @@ class Configuration(validity.ValidityRoutines): def __setattr__(self, attr, value): if attr == '_config_groups': setattr(self, attr, value) - if self.type_check(value, ConfigurationGroup): - self._config_groups[attr] = value + self.type_check(value, ConfigurationGroup) + self._config_groups[attr] = value raise TypeError("Attribute " + attr + " must be a ConfigurationGroup") diff --git a/volatility/framework/interfaces/layers.py b/volatility/framework/interfaces/layers.py index 4e2f50a05..2520ece4d 100644 --- a/volatility/framework/interfaces/layers.py +++ b/volatility/framework/interfaces/layers.py @@ -13,8 +13,10 @@ class DataLayerInterface(validity.ValidityRoutines): """A Layer that directly holds data (and does not translate it""" def __init__(self, context, name): - self._name = self.type_check(name, str) - self._context = self.type_check(context, context_module.ContextInterface) + self.type_check(name, str) + self.type_check(context, context_module.ContextInterface) + self._name = name + self._context = context @property def name(self): diff --git a/volatility/framework/interfaces/objects.py b/volatility/framework/interfaces/objects.py index 887fb8013..0700aef53 100644 --- a/volatility/framework/interfaces/objects.py +++ b/volatility/framework/interfaces/objects.py @@ -12,10 +12,15 @@ class ObjectInterface(validity.ValidityRoutines): """ A base object required to be the ancestor of every object used in volatility """ def __init__(self, context, layer_name, offset, structure_name, size, parent = None): # Since objects are likely to be instantiated often, - # we're only checking that a context is a context + # we're only checking that context, offset and parent # Everything else may be wrong, but that will get caught later on - self._context = self.type_check(context, context_module.ContextInterface) - self._parent = None if not parent else self.type_check(parent, ObjectInterface) + self.type_check(context, context_module.ContextInterface) + self.type_check(offset, int) + if parent: + self.type_check(parent, ObjectInterface) + + self._context = context + self._parent = None if not parent else parent self._offset = offset self._layer_name = layer_name self._structure_name = structure_name diff --git a/volatility/framework/interfaces/plugins.py b/volatility/framework/interfaces/plugins.py index 1d65b635c..2fc82604d 100644 --- a/volatility/framework/interfaces/plugins.py +++ b/volatility/framework/interfaces/plugins.py @@ -12,7 +12,8 @@ class PluginInterface(validity.ValidityRoutines): """Class that defines the interface all Plugins must maintain""" def __init__(self, context): - self._context = self.type_check(context, context_module.ContextInterface) + self.type_check(context, context_module.ContextInterface) + self._context = context @property def context(self): diff --git a/volatility/framework/interfaces/symbols.py b/volatility/framework/interfaces/symbols.py index 547b6d6c8..f0f5e6cd7 100644 --- a/volatility/framework/interfaces/symbols.py +++ b/volatility/framework/interfaces/symbols.py @@ -10,8 +10,11 @@ class SymbolTableInterface(validity.ValidityRoutines): """Handles a table of symbols""" def __init__(self, name, native_structures = None): - self.name = self.type_check(name or None, str) - self._native_structures = self.type_check(native_structures, NativeTableInterface) + self.type_check(native_structures, NativeTableInterface) + if name: + self.type_check(name, str) + self.name = name or None + self._native_structures = native_structures ### Required Constant symbol functions diff --git a/volatility/framework/objects/templates.py b/volatility/framework/objects/templates.py index 6dc1ee973..fba88298b 100644 --- a/volatility/framework/objects/templates.py +++ b/volatility/framework/objects/templates.py @@ -17,7 +17,16 @@ class ObjectTemplate(interfaces.objects.Template, validity.ValidityRoutines): """ def __init__(self, object_class = None, structure_name = None, **kwargs): interfaces.objects.Template.__init__(self, structure_name = structure_name, **kwargs) - self.object_class = self.class_check(object_class, interfaces.objects.ObjectInterface) + self.class_check(object_class, interfaces.objects.ObjectInterface) + self.object_class = object_class + + @classmethod + def template_children(cls, **kwargs): + raise NotImplementedError("Abstract method template_children not implemented yet.") + + @classmethod + def template_size(cls, **kwargs): + raise NotImplementedError("Abstract method template_size not implemented yet.") @property def size(self): diff --git a/volatility/framework/renderers/__init__.py b/volatility/framework/renderers/__init__.py index f223720ce..99aa8704a 100644 --- a/volatility/framework/renderers/__init__.py +++ b/volatility/framework/renderers/__init__.py @@ -54,6 +54,7 @@ class TreeGrid(TreeRow): """Class providing the interface for a TreeGrid (which contains TreeRows)""" simple_types = {int, str, float, bytes} + column_formats = {"address"} def __init__(self, columns): """Constructs a TreeGrid object using a specific set of columns @@ -66,14 +67,12 @@ class TreeGrid(TreeRow): for (name, column_type, column_format) in columns: is_simple_type = False for t in self.simple_types: - try: - self.class_check(column_type, t) - is_simple_type = True - except TypeError: - pass + is_simple_type = is_simple_type or issubclass(column_type, t) if not is_simple_type: raise TypeError("Column " + name + "'s type " + column_type.__class__.__name__ + " is not a simple type") + if not column_format is None and not column_format in self.column_formats: + raise TypeError("Column " + name + "'s format " + column_format + " is not an accepted formatter.") self._columns = columns # We can use the special type None because we're the top level node without values diff --git a/volatility/framework/renderers/basic.py b/volatility/framework/renderers/basic.py index abd656b80..4c61d3173 100644 --- a/volatility/framework/renderers/basic.py +++ b/volatility/framework/renderers/basic.py @@ -1,12 +1,32 @@ __author__ = 'mike' from volatility.framework.interfaces import renderers as interface +from volatility.framework import renderers class TextRenderer(interface.Renderer): def __init__(self, options): interface.Renderer.__init__(self, options) self._options = options + self._headers = [] def render(self, grid): """Renders a text grid based on the contents of each element""" + # Render headers and calculate column widths + self.type_check(grid, renderers.TreeGrid) + grid.iterator() + + def _determine_headers(self, grid): + self.type_check(grid, renderers.TreeGrid) + self._headers = [] + for column in grid.columns: + self._headers.append((column.name, len(column.name))) + + + def render_row(self, row, level): + pass + + def _subrender(self, subgrid, level): + for child in subgrid: + self.render_row(child, level + 1) + self._subrender(child, level + 1) diff --git a/volatility/framework/validity.py b/volatility/framework/validity.py index f678c7373..b482ce811 100644 --- a/volatility/framework/validity.py +++ b/volatility/framework/validity.py @@ -9,20 +9,26 @@ class ValidityRoutines(object): def type_check(self, value, valid_type): """Checks that value is an instance of valid_type, and returns value if it is, or throws a TypeError otherwise + + :param value: The value of which to validate the type + :type value: object + :param valid_type: The type against which to validate + :type valid_type: type """ - if not isinstance(value, valid_type): - print(repr(valid_type), repr(type(value).__name__)) - raise TypeError(self.__class__.__name__ + " expected " + - valid_type.__name__ + ", not " + type(value).__name__) + assert isinstance(value, valid_type), self.__class__.__name__ + " expected " + \ + valid_type.__name__ + ", not " + type(value).__name__ return value def class_check(self, klass, valid_class): """Checks that class is an instance of valid_class, and returns klass if it is, or throws a TypeError otherwise + + :param klass: Class to validate + :type klass: class + :param valid_class: Valid class against which to check class validity + :type valid_class: class """ - if not issubclass(klass, valid_class): - raise TypeError(self.__class__.__name__ + " expected " + - valid_class.__name__ + ", not " + klass.__name__) - return klass + assert issubclass(klass, valid_class), self.__class__.__name__ + " expected " + \ + valid_class.__name__ + ", not " + klass.__name__ def confirm(assertion, error): """Acts like an assertion, but will not be disabled when __debug__ is disabled"""