22# which is available at https://www.volatilityfoundation.org/license/vsl-v1.0
33#
44
5+ from volatility3 .framework import interfaces , renderers
6+ from volatility3 .framework .configuration import requirements
7+ from volatility3 .framework .renderers import format_hints
58from volatility3 .plugins .linux import pslist
69
710
8- class PsTree (pslist . PsList ):
11+ class PsTree (interfaces . plugins . PluginInterface ):
912 """Plugin for listing processes in a tree based on their parent process
1013 ID."""
1114
12- def __init__ (self , * args , ** kwargs ):
13- super ().__init__ (* args , ** kwargs )
14- self ._tasks = {}
15- self ._levels = {}
16- self ._children = {}
15+ _required_framework_version = (2 , 0 , 0 )
16+
17+ @classmethod
18+ def get_requirements (cls ):
19+ # Since we're calling the plugin, make sure we have the plugin's requirements
20+ return [
21+ requirements .ModuleRequirement (
22+ name = "kernel" ,
23+ description = "Linux kernel" ,
24+ architectures = ["Intel32" , "Intel64" ],
25+ ),
26+ requirements .PluginRequirement (
27+ name = "pslist" , plugin = pslist .PsList , version = (2 , 2 , 0 )
28+ ),
29+ requirements .ListRequirement (
30+ name = "pid" ,
31+ description = "Filter on specific process IDs" ,
32+ element_type = int ,
33+ optional = True ,
34+ ),
35+ requirements .BooleanRequirement (
36+ name = "threads" ,
37+ description = "Include user threads" ,
38+ optional = True ,
39+ default = False ,
40+ ),
41+ requirements .BooleanRequirement (
42+ name = "decorate_comm" ,
43+ description = "Show `user threads` comm in curly brackets, and `kernel threads` comm in square brackets" ,
44+ optional = True ,
45+ default = False ,
46+ ),
47+ ]
1748
1849 def find_level (self , pid : int ) -> None :
1950 """Finds how deep the PID is in the tasks hierarchy.
@@ -39,29 +70,27 @@ def find_level(self, pid: int) -> None:
3970 self ._levels [pid ] = level
4071
4172 def _generator (
42- self , pid_filter , include_threads : bool = False , decorate_com : bool = False
73+ self ,
74+ tasks : list ,
75+ decorate_comm : bool = False ,
4376 ):
4477 """Generates the tasks hierarchy tree.
4578
4679 Args:
47- pid_filter: A function which takes a process object and returns True if the process should be ignored/filtered
48- include_threads: If True, the output will also show the user threads
49- If False, only the thread group leaders will be shown
50- Defaults to False.
80+ tasks: A list of task objects to be displayed
5181 decorate_comm: If True, it decorates the comm string of
5282 - User threads: in curly brackets,
5383 - Kernel threads: in square brackets
5484 Defaults to False.
5585 Yields:
5686 Each rows
5787 """
58- vmlinux = self .context .modules [self .config ["kernel" ]]
59- for proc in self .list_tasks (
60- self .context ,
61- vmlinux .name ,
62- filter_func = pid_filter ,
63- include_threads = include_threads ,
64- ):
88+
89+ self ._tasks = {}
90+ self ._levels = {}
91+ self ._children = {}
92+
93+ for proc in tasks :
6594 self ._tasks [proc .pid ] = proc
6695
6796 # Build the child/level maps
@@ -71,7 +100,10 @@ def _generator(
71100 def yield_processes (pid ):
72101 task = self ._tasks [pid ]
73102
74- row = self ._get_task_fields (task , decorate_com )
103+ row = pslist .PsList .get_task_fields (task , decorate_comm )
104+ # update the first element, the offset, in the row tuple to use format_hints.Hex
105+ # as a simple int is returned from get_task_fields.
106+ row = (format_hints .Hex (row [0 ]),) + row [1 :]
75107
76108 tid = task .pid
77109 yield (self ._levels [tid ] - 1 , row )
@@ -82,3 +114,27 @@ def yield_processes(pid):
82114 for pid , level in self ._levels .items ():
83115 if level == 1 :
84116 yield from yield_processes (pid )
117+
118+ def run (self ):
119+ filter_func = pslist .PsList .create_pid_filter (self .config .get ("pid" , None ))
120+ include_threads = self .config .get ("threads" )
121+ decorate_comm = self .config .get ("decorate_comm" )
122+
123+ return renderers .TreeGrid (
124+ [
125+ ("OFFSET (V)" , format_hints .Hex ),
126+ ("PID" , int ),
127+ ("TID" , int ),
128+ ("PPID" , int ),
129+ ("COMM" , str ),
130+ ],
131+ self ._generator (
132+ pslist .PsList .list_tasks (
133+ self .context ,
134+ self .config ["kernel" ],
135+ filter_func = filter_func ,
136+ include_threads = include_threads ,
137+ ),
138+ decorate_comm = decorate_comm ,
139+ ),
140+ )
0 commit comments