11# This file is Copyright 2021 Volatility Foundation and licensed under the Volatility Software License 1.0
22# which is available at https://www.volatilityfoundation.org/license/vsl-v1.0
33#
4- from typing import Any , Callable , Iterable , List
4+ from typing import Any , Callable , Iterable , List , Tuple
55
66from volatility3 .framework import interfaces , renderers
77from volatility3 .framework .configuration import requirements
@@ -17,7 +17,7 @@ class PsList(interfaces.plugins.PluginInterface):
1717
1818 _required_framework_version = (2 , 0 , 0 )
1919
20- _version = (2 , 1 , 0 )
20+ _version = (2 , 1 , 1 )
2121
2222 @classmethod
2323 def get_requirements (cls ) -> List [interfaces .configuration .RequirementInterface ]:
@@ -78,6 +78,71 @@ def filter_func(x):
7878 else :
7979 return lambda _ : False
8080
81+ def _get_task_fields (
82+ self , task : interfaces .objects .ObjectInterface , decorate_comm : bool = False
83+ ) -> Tuple [int , int , int , str ]:
84+ """Extract the fields needed for the final output
85+ Args:
86+ task: A task object from where to get the fields.
87+ decorate_comm: If True, it decorates the comm string of
88+ - User threads: in curly brackets,
89+ - Kernel threads: in square brackets
90+ Defaults to False.
91+ Returns:
92+ A tuple with the fields to show in the plugin output.
93+ """
94+ pid = task .tgid
95+ tid = task .pid
96+ ppid = task .parent .tgid if task .parent else 0
97+ name = utility .array_to_string (task .comm )
98+ if decorate_comm :
99+ if task .is_kernel_thread :
100+ name = f"[{ name } ]"
101+ elif task .is_user_thread :
102+ name = f"{{{ name } }}"
103+
104+ task_fields = (format_hints .Hex (task .vol .offset ), pid , tid , ppid , name )
105+ return task_fields
106+
107+ def _get_file_output (self , task : interfaces .objects .ObjectInterface ) -> str :
108+ """Extract the elf for the process if requested
109+ Args:
110+ task: A task object to extract from.
111+ Returns:
112+ A string showing the results of the extraction, either
113+ the filename used or an error.
114+ """
115+ elf_table_name = intermed .IntermediateSymbolTable .create (
116+ self .context ,
117+ self .config_path ,
118+ "linux" ,
119+ "elf" ,
120+ class_types = elf .class_types ,
121+ )
122+ proc_layer_name = task .add_process_layer ()
123+ if not proc_layer_name :
124+ # if we can't build a proc layer we can't
125+ # extract the elf
126+ return renderers .NotApplicableValue ()
127+ else :
128+ # Find the vma that belongs to the main ELF of the process
129+ file_output = "Error outputting file"
130+ for v in task .mm .get_mmap_iter ():
131+ if v .vm_start == task .mm .start_code :
132+ file_handle = elfs .Elfs .elf_dump (
133+ self .context ,
134+ proc_layer_name ,
135+ elf_table_name ,
136+ v ,
137+ task ,
138+ self .open ,
139+ )
140+ if file_handle :
141+ file_output = str (file_handle .preferred_filename )
142+ file_handle .close ()
143+ break
144+ return file_output
145+
81146 def _generator (
82147 self ,
83148 pid_filter : Callable [[Any ], bool ],
@@ -104,49 +169,15 @@ def _generator(
104169 for task in self .list_tasks (
105170 self .context , self .config ["kernel" ], pid_filter , include_threads
106171 ):
107- elf_table_name = intermed .IntermediateSymbolTable .create (
108- self .context ,
109- self .config_path ,
110- "linux" ,
111- "elf" ,
112- class_types = elf .class_types ,
113- )
114- file_output = "Disabled"
115172 if dump :
116- proc_layer_name = task .add_process_layer ()
117- if not proc_layer_name :
118- continue
119-
120- # Find the vma that belongs to the main ELF of the process
121- file_output = "Error outputting file"
122-
123- for v in task .mm .get_mmap_iter ():
124- if v .vm_start == task .mm .start_code :
125- file_handle = elfs .Elfs .elf_dump (
126- self .context ,
127- proc_layer_name ,
128- elf_table_name ,
129- v ,
130- task ,
131- self .open ,
132- )
133- if file_handle :
134- file_output = str (file_handle .preferred_filename )
135- file_handle .close ()
136- break
137-
138- pid = task .tgid
139- tid = task .pid
140- ppid = task .parent .tgid if task .parent else 0
141- name = utility .array_to_string (task .comm )
142- if decorate_comm :
143- if task .is_kernel_thread :
144- name = f"[{ name } ]"
145- elif task .is_user_thread :
146- name = f"{{{ name } }}"
173+ file_output = self ._get_file_output (task )
174+ else :
175+ file_output = "Disabled"
176+
177+ offset , pid , tid , ppid , name = self ._get_task_fields (task , decorate_comm )
147178
148179 yield 0 , (
149- format_hints . Hex ( task . vol . offset ) ,
180+ offset ,
150181 pid ,
151182 tid ,
152183 ppid ,
0 commit comments