From e434909e503487a160a3177e445ff160a4cd0d02 Mon Sep 17 00:00:00 2001 From: Mike Auty Date: Fri, 11 Aug 2017 19:25:13 +0100 Subject: [PATCH] Make SymbolTable.symbols consistent with enumerations and types. --- volatility/framework/interfaces/symbols.py | 8 ++-- volatility/framework/symbols/intermed.py | 43 +++++++++++++--------- 2 files changed, 31 insertions(+), 20 deletions(-) diff --git a/volatility/framework/interfaces/symbols.py b/volatility/framework/interfaces/symbols.py index 85fa18724..f5036ad89 100644 --- a/volatility/framework/interfaces/symbols.py +++ b/volatility/framework/interfaces/symbols.py @@ -163,15 +163,17 @@ class BaseSymbolTableInterface(validity.ValidityRoutines): def get_symbols_by_type(self, type_name): """Returns the name of all symbols in this table that have type matching type_name""" - for symbol in self.symbols: + for symbol_name in self.symbols: # This allows for searching with and without the table name (in case multiple tables contain # the same symbol name and we've not specifically been told which one) + symbol = self.get_symbol(symbol_name) if symbol.type_name == type_name or (symbol.type_name.endswith(constants.BANG + type_name)): yield symbol.name def get_symbols_by_location(self, offset): - """Returns the name of all symbols in this table that have type matching type_name""" - sort_symbols = [(s.offset, s) for s in sorted(self.symbols, key = lambda x: x.offset)] + """Returns the name of all symbols in this table that live at a particular offset""" + sort_symbols = [(s.offset, s) for s in + sorted([self.get_symbol(sn) for sn in self.symbols], key = lambda x: x.offset)] result = bisect.bisect_left(sort_symbols, offset) if result == len(sort_symbols): raise StopIteration diff --git a/volatility/framework/symbols/intermed.py b/volatility/framework/symbols/intermed.py index f226e7501..a69ddb792 100644 --- a/volatility/framework/symbols/intermed.py +++ b/volatility/framework/symbols/intermed.py @@ -166,7 +166,7 @@ class Version1Format(ISFormatTable): nt.name = name + "_natives" super().__init__(context, config_path, name, nt) self._overrides = {} - self._symbol_cache = None + self._symbol_cache = {} def _get_natives(self): """Determines the appropriate native_types to use from the JSON data""" @@ -197,24 +197,30 @@ class Version1Format(ISFormatTable): def get_symbol(self, name): """Returns the location offset given by the symbol name""" + # TODO: Add the ability to add/remove/change symbols after creation + # note that this should invalidate/update the cache + if self._symbol_cache.get(name, None): + return self._symbol_cache[name] symbol = self._json_object['symbols'].get(name, None) if not symbol: raise exceptions.SymbolError("Unknown symbol: {}".format(name)) - return interfaces.symbols.Symbol(name = name, address = symbol['address']) + self._symbol_cache[name] = interfaces.symbols.Symbol(name = name, address = symbol['address']) + return self._symbol_cache[name] @property def symbols(self): - if not self._symbol_cache: - self._symbol_cache = [self.get_symbol(x) for x in self._json_object['symbols']] - return self._symbol_cache - - # TODO: Add the ability to add/remove/change symbols after creation, note that this should invalidate the cache + return self._json_object.get('symbols', {}).keys() @property def enumerations(self): """Returns an iterator of the available enumerations""" return self._json_object.get('enums', {}).keys() + @property + def types(self): + """Returns an iterator of the symbol names""" + return list(self._json_object.get('user_types', {}).keys()) + list(self.natives.types) + def get_type_class(self, name): return self._overrides.get(name, objects.Struct) @@ -227,11 +233,6 @@ class Version1Format(ISFormatTable): if name in self._overrides: del self._overrides[name] - @property - def types(self): - """Returns an iterator of the symbol names""" - return list(self._json_object.get('user_types', {}).keys()) + list(self.natives.types) - def _interdict_to_template(self, dictionary): """Converts an intermediate format dict into an object template""" if not dictionary: @@ -366,14 +367,18 @@ class Version3Format(Version2Format): version = (current - age, age, revision) def get_symbol(self, name): - """Returns the location offset given by the symbol name""" + """Returns the symbol given by the symbol name""" + if self._symbol_cache.get(name, None): + return self._symbol_cache[name] symbol = self._json_object['symbols'].get(name, None) if not symbol: raise exceptions.SymbolError("Unknown symbol: {}".format(name)) symbol_type = None if 'type' in symbol: symbol_type = self._interdict_to_template(symbol['type']) - return interfaces.symbols.Symbol(name = name, address = symbol['address'], type = symbol_type) + self._symbol_cache[name] = interfaces.symbols.Symbol(name = name, address = symbol['address'], + type = symbol_type) + return self._symbol_cache[name] class Version4Format(Version3Format): @@ -422,7 +427,9 @@ class Version5Format(Version4Format): version = (current - age, age, revision) def get_symbol(self, name): - """Returns the location offset given by the symbol name""" + """Returns the symbol given by the symbol name""" + if self._symbol_cache.get(name, None): + return self._symbol_cache[name] symbol = self._json_object['symbols'].get(name, None) if not symbol: raise exceptions.SymbolError("Unknown symbol: {}".format(name)) @@ -432,5 +439,7 @@ class Version5Format(Version4Format): symbol_constant_data = None if 'constant_data' in symbol: symbol_constant_data = base64.b64decode(symbol.get('constant_data')) - return interfaces.symbols.Symbol(name = name, address = symbol['address'], type = symbol_type, - constant_data = symbol_constant_data) + self._symbol_cache[name] = interfaces.symbols.Symbol(name = name, address = symbol['address'], + type = symbol_type, + constant_data = symbol_constant_data) + return self._symbol_cache[name]