From d6918f852e486268eb5a368f2c91c32d043ff71d Mon Sep 17 00:00:00 2001 From: eve Date: Fri, 25 Apr 2025 14:09:47 +0100 Subject: [PATCH 1/5] Windows: update psscan to fix issue #591 --- .../framework/plugins/windows/psscan.py | 81 ++++++++++++------- 1 file changed, 51 insertions(+), 30 deletions(-) diff --git a/volatility3/framework/plugins/windows/psscan.py b/volatility3/framework/plugins/windows/psscan.py index ae37c20a10..ae653f3cae 100644 --- a/volatility3/framework/plugins/windows/psscan.py +++ b/volatility3/framework/plugins/windows/psscan.py @@ -269,39 +269,60 @@ def _generator(self): filter_func=pslist.PsList.create_pid_filter(self.config.get("pid", None)), ): file_output = "Disabled" - if self.config["dump"]: - # windows 10 objects (maybe others in the future) are already in virtual memory - if proc.vol.layer_name == kernel.layer_name: - vproc = proc + + # windows 10 objects (maybe others in the future) are already in virtual memory + # if the proc native_layer_name and layer_name match then it is in 'virtual' memory. + if proc.vol.layer_name == proc.vol.native_layer_name: + # proc is already in a virtual mem, so a new object is not needed. it means + # that if physical addresses are requested in the output then proc.vol.offset + # cannot be used because it will be virtual, so the mapping is needed. + vproc = proc + if self.config["physical"]: + # the display should be physical addresses, so proc cannot be used. The + # mappings are needed to find where it would be physically. + _, _, offset, _, _ = list( + memory.mapping(offset=proc.vol.offset, length=0) + )[0] else: - try: - vproc = self.virtual_process_from_physical( - self.context, - self.config["kernel"], - proc, - ) - except exceptions.PagedInvalidAddressException: - vproc = None + # the display should be virtual addresses, so proc can be used + offset = proc.vol.offset + + # renderers.UnreadableValue() + else: + # proc is in virtual mem, so a new object needs to be creatd. + vproc = self.virtual_process_from_physical( + self.context, self.config["kernel"], proc + ) + if self.config["physical"]: + # the display should be physical addresses, so proc can be used + # as it is + offset = proc.vol.offset + else: + # the display should be virtual address, so vproc should be used + # however virtual_process_from_physical is not always able to create + # a vproc, in that case we need to display a UnreadableValue() + if vproc is not None: + offset = vproc.vol.offset + else: + offset = None + if self.config["dump"]: + file_handle = pslist.PsList.process_dump( + self.context, + kernel.symbol_table_name, + pe_table_name, + vproc, + self.open, + ) file_output = "Error outputting file" - if vproc: - file_handle = pslist.PsList.process_dump( - self.context, - kernel.symbol_table_name, - pe_table_name, - vproc, - self.open, - ) - - if file_handle: - file_output = file_handle.preferred_filename - - if not self.config["physical"]: - offset = proc.vol.offset + if file_handle: + file_output = file_handle.preferred_filename + + # format offset for display + if offset is None: + display_offset = renderers.UnreadableValue() else: - (_, _, offset, _, _) = list( - memory.mapping(offset=proc.vol.offset, length=0) - )[0] + display_offset = format_hints.Hex(offset) try: yield ( @@ -314,7 +335,7 @@ def _generator(self): max_length=proc.ImageFileName.vol.count, errors="replace", ), - format_hints.Hex(offset), + display_offset, proc.ActiveThreads, proc.get_handle_count(), proc.get_session_id(), From a3e903e475e133906b176d55995cfe7246e57cc6 Mon Sep 17 00:00:00 2001 From: eve Date: Fri, 25 Apr 2025 14:23:50 +0100 Subject: [PATCH 2/5] Add test for windows.psscan --physical option --- test/plugins/windows/windows.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/test/plugins/windows/windows.py b/test/plugins/windows/windows.py index 4272b64d2b..2aaa800387 100644 --- a/test/plugins/windows/windows.py +++ b/test/plugins/windows/windows.py @@ -72,6 +72,17 @@ def test_windows_specific_psscan(self, volatility, python): assert out.find(b"svchost.exe") != -1 assert out.count(b"\n") > 10 + def test_windows_specific_psscan_physical(self, volatility, python): + image = WindowsSamples.WINDOWSXP_GENERIC.value.path + rc, out, _err = test_volatility.runvol_plugin( + "windows.psscan.PsScan", image, volatility, python,pluginargs=("--physical"") + ) + assert rc == 0 + out = out.lower() + assert out.find(b"system") != -1 + assert out.find(b"csrss.exe") != -1 + assert out.find(b"svchost.exe") != -1 + assert out.count(b"\n") > 10 class TestWindowsDlllist: def test_windows_generic_dlllist(self, volatility, python, image): From 2ea6e2f9435009328871aff20c83f48bd3352b60 Mon Sep 17 00:00:00 2001 From: eve Date: Fri, 25 Apr 2025 14:24:47 +0100 Subject: [PATCH 3/5] Add test for windows.psscan --physical option --- test/plugins/windows/windows.py | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/test/plugins/windows/windows.py b/test/plugins/windows/windows.py index 2aaa800387..5d2e2cc496 100644 --- a/test/plugins/windows/windows.py +++ b/test/plugins/windows/windows.py @@ -75,7 +75,11 @@ def test_windows_specific_psscan(self, volatility, python): def test_windows_specific_psscan_physical(self, volatility, python): image = WindowsSamples.WINDOWSXP_GENERIC.value.path rc, out, _err = test_volatility.runvol_plugin( - "windows.psscan.PsScan", image, volatility, python,pluginargs=("--physical"") + "windows.psscan.PsScan", + image, + volatility, + python, + pluginargs=("--physical"), ) assert rc == 0 out = out.lower() @@ -84,6 +88,7 @@ def test_windows_specific_psscan_physical(self, volatility, python): assert out.find(b"svchost.exe") != -1 assert out.count(b"\n") > 10 + class TestWindowsDlllist: def test_windows_generic_dlllist(self, volatility, python, image): rc, out, _err = test_volatility.runvol_plugin( @@ -783,19 +788,19 @@ def test_windows_specific_symlinkscan(self, volatility, python): assert test_volatility.count_entries_flat(json_out) > 5 expected_rows = [ { - "CreateTime": "2005-06-25T16:47:28+00:00", - "From Name": "AUX", - "Offset": 453082584, - "To Name": "\\DosDevices\\COM1", - "__children": [] + "CreateTime": "2005-06-25T16:47:28+00:00", + "From Name": "AUX", + "Offset": 453082584, + "To Name": "\\DosDevices\\COM1", + "__children": [], }, { - "CreateTime": "2005-06-25T16:47:28+00:00", - "From Name": "UNC", - "Offset": 453176664, - "To Name": "\\Device\\Mup", - "__children": [] - } + "CreateTime": "2005-06-25T16:47:28+00:00", + "From Name": "UNC", + "Offset": 453176664, + "To Name": "\\Device\\Mup", + "__children": [], + }, ] for expected_row in expected_rows: From 70632685f5e0dae00fba0e28cbfa4abe7d3a1d00 Mon Sep 17 00:00:00 2001 From: eve Date: Fri, 25 Apr 2025 15:47:29 +0100 Subject: [PATCH 4/5] Ensure that pluginargs is a tuple for test_windows_specific_psscan_physical --- test/plugins/windows/windows.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/plugins/windows/windows.py b/test/plugins/windows/windows.py index 5d2e2cc496..5fb576a2ce 100644 --- a/test/plugins/windows/windows.py +++ b/test/plugins/windows/windows.py @@ -79,7 +79,7 @@ def test_windows_specific_psscan_physical(self, volatility, python): image, volatility, python, - pluginargs=("--physical"), + pluginargs=("--physical",), ) assert rc == 0 out = out.lower() From 0674909553b0bf58f204b41b346f7626331c08c3 Mon Sep 17 00:00:00 2001 From: eve Date: Fri, 25 Apr 2025 17:28:14 +0100 Subject: [PATCH 5/5] Windows: update patch version of psscan --- volatility3/framework/plugins/windows/psscan.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/volatility3/framework/plugins/windows/psscan.py b/volatility3/framework/plugins/windows/psscan.py index ae653f3cae..0506e71840 100644 --- a/volatility3/framework/plugins/windows/psscan.py +++ b/volatility3/framework/plugins/windows/psscan.py @@ -23,7 +23,7 @@ class PsScan(interfaces.plugins.PluginInterface, timeliner.TimeLinerInterface): """Scans for processes present in a particular windows memory image.""" _required_framework_version = (2, 3, 1) - _version = (2, 0, 0) + _version = (2, 0, 1) @classmethod def get_requirements(cls):