From 748dceefb74d943bd7e51cd53b03dbe9f43276b0 Mon Sep 17 00:00:00 2001 From: gcmoreira Date: Mon, 17 Aug 2020 15:05:38 +1000 Subject: [PATCH] Fix #291. It supports any level of depth of nested anonymous types. --- volatility/framework/symbols/intermed.py | 55 ++++++++++++++---------- 1 file changed, 32 insertions(+), 23 deletions(-) diff --git a/volatility/framework/symbols/intermed.py b/volatility/framework/symbols/intermed.py index 9ae560ac2..f10aca005 100644 --- a/volatility/framework/symbols/intermed.py +++ b/volatility/framework/symbols/intermed.py @@ -637,43 +637,52 @@ class Version8Format(Version7Format): """Class for storing intermediate debugging data as objects and classes.""" version = (6, 2, 0) - def _reduce_indirect_members(self, members: Dict[str, Dict[str, Any]]) -> Dict[str, Dict[str, Any]]: - result = {} - for member in members: - if isinstance(members[member], dict) and members[member].get('anonymous', False): - # Do checks to make sure the new dictionary is appropriate - parent_item = members[member] - submembers = self._reduce_indirect_members(self._json_object['user_types'].get(parent_item['type'], {})) - for item in submembers: - result[item] = submembers[item].copy() - result[item]['offset'] = submembers[item]['offset'] + parent_item.get('offset', 0) + def _process_fields(self, fields: Dict[str, Dict[str, Any]]) -> Dict[Any, Tuple[int, interfaces.objects.Template]]: + """For each type field, it walks its tree of subtypes, reducing the hierarchy to just one level. + It creates a tuple of offset and object templates for each field. + """ + members = {} + for new_offset, member_name, member_value in self._reduce_fields(fields): + member = (new_offset, self._interdict_to_template(member_value['type'])) + members[member_name] = member + return members + + def _reduce_fields(self, + fields: Dict[str, Dict[str, Any]], + parent_offset: int = 0) -> Generator[Tuple[int, str, Dict], None, None]: + """Reduce the fields bringing them one level up. It supports anonymous types such as structs or unions in any + level of depth.""" + for member_name, member_value in fields.items(): + new_offset = parent_offset + member_value.get('offset', 0) + if member_value.get('anonymous', False) and isinstance(member_value, dict): + # Gets the subtype from the json ISF and recursively reduce its fields + subtype = self._json_object['user_types'].get(member_value['type']['name'], {}) + yield from self._reduce_fields(subtype['fields'], new_offset) else: - result[member] = members[member] - return result + yield new_offset, member_name, member_value def get_type(self, type_name: str) -> interfaces.objects.Template: """Resolves an individual symbol.""" - if constants.BANG in type_name: - index = type_name.find(constants.BANG) + index = type_name.find(constants.BANG) + if index != -1: table_name, type_name = type_name[:index], type_name[index + 1:] raise exceptions.SymbolError( type_name, table_name, "Symbol for a different table requested: {}".format(table_name + constants.BANG + type_name)) - if type_name not in self._json_object['user_types']: + + type_definition = self._json_object['user_types'].get(type_name) + if type_definition is None: # Fall back to the natives table return self.natives.get_type(self.name + constants.BANG + type_name) - curdict = self._json_object['user_types'][type_name] - members = {} - for member_name in curdict['fields']: - interdict = self._reduce_indirect_members(curdict['fields'][member_name]) - member = (interdict['offset'], self._interdict_to_template(interdict['type'])) - members[member_name] = member + + members = self._process_fields(type_definition['fields']) + object_class = self.get_type_class(type_name) if object_class == objects.AggregateType: for clazz in objects.AggregateTypes: - if objects.AggregateTypes[clazz] == curdict['kind']: + if objects.AggregateTypes[clazz] == type_definition['kind']: object_class = clazz return objects.templates.ObjectTemplate(type_name = self.name + constants.BANG + type_name, object_class = object_class, - size = curdict['size'], + size = type_definition['size'], members = members)