From e381a0078037210f8650b80eade94224acd8421b Mon Sep 17 00:00:00 2001 From: Mike Auty Date: Sun, 18 Feb 2024 21:58:26 +0000 Subject: [PATCH] Core: Support hidden by default columns in plugins This adds the ability to provide a third argument in the column definition ("name", "type", "extra"). Extra columns will not be shown by the CLI by default, but can be seen by passing an empty list to the CLI (ie, provide no parameters to the `--columns` flag). Otherwise any columns passed to `--columns` will be displayed and no other columns will. If no valid column name are passed to columns, then the normal list of columns (not including extra) will be displayed. All other UIs will need to implement support for the extra column, otherwise they will silently ignore it. --- volatility3/cli/text_renderer.py | 12 +++++++----- volatility3/framework/interfaces/renderers.py | 4 ++-- volatility3/framework/renderers/__init__.py | 13 ++++++++++--- 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/volatility3/cli/text_renderer.py b/volatility3/cli/text_renderer.py index 090a82d4a..f63e97c18 100644 --- a/volatility3/cli/text_renderer.py +++ b/volatility3/cli/text_renderer.py @@ -149,6 +149,8 @@ class CLIRenderer(interfaces.renderers.Renderer): accept = True if not accept: ignored_columns.append(column) + elif self.column_output_list is not None: + return [] return ignored_columns @@ -182,12 +184,12 @@ class QuickTextRenderer(CLIRenderer): outfd = sys.stdout line = [] - ignored_columns = [] + ignored_columns = [column for column in grid.columns if column.extra == True] for column in grid.columns: # Ignore the type because namedtuples don't realize they have accessible attributes ignored_columns = self.ignore_columns(column, ignored_columns) if column not in ignored_columns: - line.append(f"column.name") + line.append(f"{column.name}") if not line: raise exceptions.RenderException("No visible columns") @@ -260,7 +262,7 @@ class CSVRenderer(CLIRenderer): outfd = sys.stdout header_list = ["TreeDepth"] - ignored_columns = [] + ignored_columns = [column for column in grid.columns if column.extra == True] for column in grid.columns: # Ignore the type because namedtuples don't realize they have accessible attributes ignored_columns = self.ignore_columns(column, ignored_columns) @@ -325,7 +327,7 @@ class PrettyTextRenderer(CLIRenderer): [(column.name, len(column.name)) for column in grid.columns] ) - ignored_columns = [] + ignored_columns = [column for column in grid.columns if column.extra == True] for column in grid.columns: ignored_columns = self.ignore_columns(column, ignored_columns) @@ -446,7 +448,7 @@ class JsonRenderer(CLIRenderer): List[interfaces.renderers.TreeNode], ] = ({}, []) - ignored_columns = [] + ignored_columns = [column for column in grid.columns if column.extra == True] for column in grid.columns: ignored_columns = self.ignore_columns(column, ignored_columns) diff --git a/volatility3/framework/interfaces/renderers.py b/volatility3/framework/interfaces/renderers.py index b13de1834..4692a112c 100644 --- a/volatility3/framework/interfaces/renderers.py +++ b/volatility3/framework/interfaces/renderers.py @@ -26,7 +26,7 @@ from typing import ( Union, ) -Column = NamedTuple("Column", [("name", str), ("type", Any)]) +Column = NamedTuple("Column", [("name", str), ("type", Any), ("extra", bool)]) RenderOption = Any @@ -133,7 +133,7 @@ BaseTypes = Union[ Type[BaseAbsentValue], Type[Disassembly], ] -ColumnsType = List[Tuple[str, BaseTypes]] +ColumnsType = List[Tuple[str, BaseTypes, bool]] VisitorSignature = Callable[[TreeNode, _Type], _Type] diff --git a/volatility3/framework/renderers/__init__.py b/volatility3/framework/renderers/__init__.py index 43bb59a21..1d6e39d3f 100644 --- a/volatility3/framework/renderers/__init__.py +++ b/volatility3/framework/renderers/__init__.py @@ -166,7 +166,7 @@ class TreeGrid(interfaces.renderers.TreeGrid): def __init__( self, - columns: List[Tuple[str, interfaces.renderers.BaseTypes]], + columns: interfaces.renderers.ColumnsType, generator: Optional[Iterable[Tuple[int, Tuple]]], ) -> None: """Constructs a TreeGrid object using a specific set of columns. @@ -185,7 +185,12 @@ class TreeGrid(interfaces.renderers.TreeGrid): converted_columns: List[interfaces.renderers.Column] = [] if len(columns) < 1: raise ValueError("Columns must be a list containing at least one column") - for name, column_type in columns: + for column_info in columns: + if len(column_info) < 3: + name, column_type = column_info + extra = False + else: + name, column_type, extra = column_info is_simple_type = issubclass(column_type, self.base_types) if not is_simple_type: raise TypeError( @@ -193,7 +198,9 @@ class TreeGrid(interfaces.renderers.TreeGrid): name, column_type.__class__.__name__ ) ) - converted_columns.append(interfaces.renderers.Column(name, column_type)) + converted_columns.append( + interfaces.renderers.Column(name, column_type, extra) + ) self.RowStructure = RowStructureConstructor( [column.name for column in converted_columns] )