From c48ad901b03c72e7c1ceffe3712dc8322c19de38 Mon Sep 17 00:00:00 2001 From: David McDonald Date: Thu, 10 Apr 2025 14:49:50 -0500 Subject: [PATCH] Extensions: Add cache decorators as appropriate I noticed that many plugins were creating duplicate per-process translation layers - for instance, `windows.envars.Envars` was ending up with > 30 process layers per process due to repeated calls to `get_peb()`, which calls `add_process_space()` internally. This adds `@functools.lru_cache` to the `get_peb()` and `get_peb32()` methods on the `EPROCESS` extension, since these should only need to be created once. Also adds `@functools.lru_cache` to `add_process_space` to enable reusing the same process address space, provided the same arguments are passed to the `add_process_space()` method. --- volatility3/framework/symbols/linux/extensions/__init__.py | 1 + volatility3/framework/symbols/mac/extensions/__init__.py | 2 ++ volatility3/framework/symbols/windows/extensions/__init__.py | 5 ++++- 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/volatility3/framework/symbols/linux/extensions/__init__.py b/volatility3/framework/symbols/linux/extensions/__init__.py index b4bde1aba..d281e2b9b 100644 --- a/volatility3/framework/symbols/linux/extensions/__init__.py +++ b/volatility3/framework/symbols/linux/extensions/__init__.py @@ -471,6 +471,7 @@ class task_struct(generic.GenericIntelProcess): return True + @functools.lru_cache def add_process_layer( self, config_prefix: Optional[str] = None, preferred_name: Optional[str] = None ) -> Optional[str]: diff --git a/volatility3/framework/symbols/mac/extensions/__init__.py b/volatility3/framework/symbols/mac/extensions/__init__.py index cc700f209..08ec63afa 100644 --- a/volatility3/framework/symbols/mac/extensions/__init__.py +++ b/volatility3/framework/symbols/mac/extensions/__init__.py @@ -2,6 +2,7 @@ # which is available at https://www.volatilityfoundation.org/license/vsl-v1.0 # import contextlib +import functools import logging from typing import Generator, Iterable, Optional, Set, Tuple @@ -17,6 +18,7 @@ class proc(generic.GenericIntelProcess): def get_task(self): return self.task.dereference().cast("task") + @functools.lru_cache def add_process_layer( self, config_prefix: Optional[str] = None, preferred_name: Optional[str] = None ) -> Optional[str]: diff --git a/volatility3/framework/symbols/windows/extensions/__init__.py b/volatility3/framework/symbols/windows/extensions/__init__.py index 9fe250ba5..b90391af3 100755 --- a/volatility3/framework/symbols/windows/extensions/__init__.py +++ b/volatility3/framework/symbols/windows/extensions/__init__.py @@ -732,9 +732,10 @@ class EPROCESS(generic.GenericIntelProcess, pool.ExecutiveObject): return True + @functools.lru_cache def add_process_layer( self, config_prefix: Optional[str] = None, preferred_name: Optional[str] = None - ): + ) -> str: """Constructs a new layer based on the process's DirectoryTableBase.""" parent_layer = self._context.layers[self.vol.layer_name] @@ -761,6 +762,7 @@ class EPROCESS(generic.GenericIntelProcess, pool.ExecutiveObject): self._context, dtb, config_prefix, preferred_name ) + @functools.lru_cache def get_peb(self) -> interfaces.objects.ObjectInterface: """Constructs a PEB object""" if constants.BANG not in self.vol.type_name: @@ -786,6 +788,7 @@ class EPROCESS(generic.GenericIntelProcess, pool.ExecutiveObject): ) return peb + @functools.lru_cache def get_peb32(self) -> Optional[interfaces.objects.ObjectInterface]: """Constructs a PEB32 object""" if constants.BANG not in self.vol.type_name: