From de9ad62412ecf8071d2ba7e09a9cbb0bdbe2f82b Mon Sep 17 00:00:00 2001 From: Mike Auty Date: Thu, 8 Mar 2018 00:26:25 +0000 Subject: [PATCH] Add in support for AbsentValues. --- volatility/framework/interfaces/renderers.py | 10 +++++++- volatility/framework/renderers/__init__.py | 14 ++++++++++- volatility/framework/renderers/text.py | 26 +++++++++++++++----- 3 files changed, 42 insertions(+), 8 deletions(-) diff --git a/volatility/framework/interfaces/renderers.py b/volatility/framework/interfaces/renderers.py index b3c40e54b..cb9ec1407 100644 --- a/volatility/framework/interfaces/renderers.py +++ b/volatility/framework/interfaces/renderers.py @@ -73,9 +73,17 @@ class TreeNode(collections.Sequence, metaclass = ABCMeta): """ +class BaseAbsentValue(object): + """Class that represents values which are not present for some reason""" + + _Type = typing.TypeVar("_Type") ColumnsType = typing.List[typing.Tuple[str, typing.Type]] -SimpleTypes = typing.Union[typing.Type[int], typing.Type[str], typing.Type[float], typing.Type[bytes]] +SimpleTypes = typing.Union[typing.Type[int], + typing.Type[str], + typing.Type[float], + typing.Type[bytes], + typing.Type[BaseAbsentValue]] VisitorSignature = typing.Callable[[TreeNode, _Type], _Type] diff --git a/volatility/framework/renderers/__init__.py b/volatility/framework/renderers/__init__.py index c6ca3ac1b..aabb141d7 100644 --- a/volatility/framework/renderers/__init__.py +++ b/volatility/framework/renderers/__init__.py @@ -8,6 +8,18 @@ import typing from volatility.framework import interfaces +class UnreadableValue(interfaces.renderers.BaseAbsentValue): + """Class that represents values which are empty because the data cannot be read""" + + +class UnparsableValue(interfaces.renderers.BaseAbsentValue): + """Class that represents values which are empty because the data cannot be interpreted correctly""" + + +class NotApplicableValue(interfaces.renderers.BaseAbsentValue): + """Class that represents values which are empty because they don't make sense for this node""" + + class TreeNode(interfaces.renderers.TreeNode): """Class representing a particular node in a tree grid""" @@ -40,7 +52,7 @@ class TreeNode(interfaces.renderers.TreeNode): "Values must be a list of objects made up of simple types and number the same as the columns") for index in range(len(self._treegrid.columns)): column = self._treegrid.columns[index] - if not isinstance(values[index], column.type): + if not isinstance(values[index], (column.type, interfaces.renderers.BaseAbsentValue)): raise TypeError( "Values item with index {} is the wrong type for column {} (got {} but expected {})".format( index, diff --git a/volatility/framework/renderers/text.py b/volatility/framework/renderers/text.py index b4dd6e299..59a6ce203 100644 --- a/volatility/framework/renderers/text.py +++ b/volatility/framework/renderers/text.py @@ -1,6 +1,7 @@ import sys +import typing -from volatility.framework import interfaces +from volatility.framework import interfaces, renderers from volatility.framework.renderers import format_hints @@ -24,12 +25,25 @@ def hex_bytes_as_text(value: bytes) -> str: return output +class Optional(object): + def __init__(self, func: typing.Callable[[typing.Any], str]) -> None: + self._func = func + + def __call__(self, x: typing.Any) -> str: + if isinstance(x, interfaces.renderers.BaseAbsentValue): + if isinstance(x, renderers.NotApplicableValue): + return "N/A" + else: + return "-" + return self._func(x) + + class QuickTextRenderer(interfaces.renderers.Renderer): - type_renderers = {format_hints.Bin: lambda x: "0b{:b}".format(x), - format_hints.Hex: lambda x: "0x{:x}".format(x), - format_hints.HexBytes: hex_bytes_as_text, - bytes: lambda x: x.decode("utf-8"), - 'default': lambda x: "{}".format(x)} + type_renderers = {format_hints.Bin: Optional(lambda x: "0b{:b}".format(x)), + format_hints.Hex: Optional(lambda x: "0x{:x}".format(x)), + format_hints.HexBytes: Optional(hex_bytes_as_text), + bytes: Optional(lambda x: x.decode("utf-8")), + 'default': Optional(lambda x: "{}".format(x))} def __init__(self, options = None) -> None: super().__init__(options)