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.
This commit is contained in:
David McDonald
2025-04-10 14:57:46 -05:00
parent e00f0961c2
commit c48ad901b0
3 changed files with 7 additions and 1 deletions
@@ -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]:
@@ -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]:
@@ -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: