33#
44
55import logging
6- from typing import Dict , List , Optional
6+ from typing import Dict , Iterator , List , Optional
77
88from volatility3 .framework import constants , exceptions , interfaces , renderers , symbols
99from volatility3 .framework .configuration import requirements
@@ -18,13 +18,9 @@ class Handles(interfaces.plugins.PluginInterface):
1818 """Lists process open handles."""
1919
2020 _required_framework_version = (2 , 0 , 0 )
21- _version = (3 , 0 , 0 )
21+ _version = (4 , 0 , 0 )
2222
23- def __init__ (self , * args , ** kwargs ):
24- super ().__init__ (* args , ** kwargs )
25- self ._type_map = None
26- self ._cookie = None
27- self ._level_mask = 7
23+ LEVEL_MASK = 7
2824
2925 @classmethod
3026 def get_requirements (cls ) -> List [interfaces .configuration .RequirementInterface ]:
@@ -54,18 +50,27 @@ def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]
5450 ),
5551 ]
5652
57- def _get_item (self , handle_table_entry , handle_value ):
58- """Given a handle table entry (_HANDLE_TABLE_ENTRY) structure from a
53+ @classmethod
54+ def _get_item (
55+ cls ,
56+ context : interfaces .context .ContextInterface ,
57+ kernel_module_name : str ,
58+ handle_table_entry : interfaces .objects .ObjectInterface ,
59+ handle_value : int ,
60+ ) -> Optional [interfaces .objects .ObjectInterface ]:
61+ """
62+ Given a handle table entry (_HANDLE_TABLE_ENTRY) structure from a
5963 process' handle table, determine where the corresponding object's
60- _OBJECT_HEADER can be found."""
64+ _OBJECT_HEADER can be found, and construct and return the _OBJECT_HEADER
65+ """
6166
62- kernel = self . context .modules [self . config [ "kernel" ] ]
67+ kernel = context .modules [kernel_module_name ]
6368
6469 virtual = kernel .layer_name
6570
6671 try :
6772 # before windows 7
68- if not self . context .layers [virtual ].is_valid (handle_table_entry .Object ):
73+ if not context .layers [virtual ].is_valid (handle_table_entry .Object ):
6974 return None
7075 fast_ref = handle_table_entry .Object .cast ("_EX_FAST_REF" )
7176
@@ -78,7 +83,7 @@ def _get_item(self, handle_table_entry, handle_value):
7883 except AttributeError :
7984 # starting with windows 8
8085 is_64bit = symbols .symbol_table_is_64bit (
81- context = self . context , symbol_table_name = kernel .symbol_table_name
86+ context = context , symbol_table_name = kernel .symbol_table_name
8287 )
8388
8489 if is_64bit :
@@ -104,7 +109,7 @@ def _get_item(self, handle_table_entry, handle_value):
104109 offset = info_table & ~ 7
105110
106111 # print("LowValue: {0:#x} Magic: {1:#x} Offset: {2:#x}".format(handle_table_entry.InfoTable, magic, offset))
107- object_header = self . context .object (
112+ object_header = context .object (
108113 kernel .symbol_table_name + constants .BANG + "_OBJECT_HEADER" ,
109114 virtual ,
110115 offset = offset ,
@@ -205,11 +210,23 @@ def find_cookie(
205210 offset = symbol_offset ,
206211 )
207212
208- def _make_handle_array (self , offset , level , depth = 0 ):
209- """Parse a process' handle table and yield valid handle table entries,
210- going as deep into the table "levels" as necessary."""
213+ @classmethod
214+ def _make_handle_array (
215+ cls ,
216+ context : interfaces .context .ContextInterface ,
217+ kernel_module_name : str ,
218+ offset : int ,
219+ level : int ,
220+ depth : int = 0 ,
221+ ) -> Iterator [interfaces .objects .ObjectInterface ]:
222+ """
223+ Parses a process' handle table by constructing an array of
224+ `_HANDLE_TABLE_ENTRY` structures at the given offset, and yields valid
225+ handle table entries, going as deep into the table "levels" as
226+ necessary.
227+ """
211228
212- kernel = self . context .modules [self . config [ "kernel" ] ]
229+ kernel = context .modules [kernel_module_name ]
213230
214231 if level > 0 :
215232 subtype = kernel .get_type ("pointer" )
@@ -218,7 +235,7 @@ def _make_handle_array(self, offset, level, depth=0):
218235 subtype = kernel .get_type ("_HANDLE_TABLE_ENTRY" )
219236 count = 0x1000 / subtype .size
220237
221- if not self . context .layers [kernel .layer_name ].is_valid (offset ):
238+ if not context .layers [kernel .layer_name ].is_valid (offset ):
222239 return None
223240
224241 table = kernel .object (
@@ -229,7 +246,7 @@ def _make_handle_array(self, offset, level, depth=0):
229246 absolute = True ,
230247 )
231248
232- layer_object = self . context .layers [kernel .layer_name ]
249+ layer_object = context .layers [kernel .layer_name ]
233250 masked_offset = offset & layer_object .maximum_address
234251
235252 for i in range (len (table )):
@@ -243,11 +260,13 @@ def _make_handle_array(self, offset, level, depth=0):
243260 # The code above this calls `is_valid` on the `offset`
244261 # It is sent but then does not validate `entry` before
245262 # sending it to `_get_item`
246- if not self . context .layers [kernel .layer_name ].is_valid (entry .vol .offset ):
263+ if not context .layers [kernel .layer_name ].is_valid (entry .vol .offset ):
247264 continue
248265
249266 if level > 0 :
250- yield from self ._make_handle_array (entry , level - 1 , depth )
267+ yield from cls ._make_handle_array (
268+ context , kernel_module_name , entry , level - 1 , depth
269+ )
251270 depth += 1
252271 else :
253272 handle_multiplier = 4
@@ -258,7 +277,7 @@ def _make_handle_array(self, offset, level, depth=0):
258277 / (subtype .size / handle_multiplier )
259278 ) + handle_level_base
260279
261- item = self ._get_item (entry , handle_value )
280+ item = cls ._get_item (context , kernel_module_name , entry , handle_value )
262281
263282 if item is None :
264283 continue
@@ -272,18 +291,31 @@ def _make_handle_array(self, offset, level, depth=0):
272291 except exceptions .InvalidAddressException :
273292 continue
274293
275- def handles (self , handle_table ):
294+ @classmethod
295+ def handles (
296+ cls ,
297+ context : interfaces .context .ContextInterface ,
298+ kernel_module_name : str ,
299+ handle_table : interfaces .objects .ObjectInterface ,
300+ ) -> Iterator [interfaces .objects .ObjectInterface ]:
301+ """
302+ Takes a context, kernel module name, and handle table structure
303+ (_HANDLE_TABLE), and yields _HANDLE_TABLE_ENTRY structures from the
304+ handle table.
305+ """
276306 try :
277- TableCode = handle_table .TableCode & ~ self . _level_mask
278- table_levels = handle_table .TableCode & self . _level_mask
307+ TableCode = handle_table .TableCode & ~ cls . LEVEL_MASK
308+ table_levels = handle_table .TableCode & cls . LEVEL_MASK
279309 except exceptions .InvalidAddressException :
280310 vollog .log (
281311 constants .LOGLEVEL_VVV ,
282312 "Handle table parsing was aborted due to an invalid address exception" ,
283313 )
284314 return None
285315
286- yield from self ._make_handle_array (TableCode , table_levels )
316+ yield from cls ._make_handle_array (
317+ context , kernel_module_name , TableCode , table_levels
318+ )
287319
288320 def _generator (self , procs ):
289321 type_map = self .get_type_map (
@@ -306,7 +338,9 @@ def _generator(self, procs):
306338
307339 process_name = utility .array_to_string (proc .ImageFileName )
308340
309- for entry in self .handles (object_table ):
341+ for entry in self .handles (
342+ self .context , self .config ["kernel" ], object_table
343+ ):
310344 try :
311345 obj_type = entry .get_object_type (type_map , cookie )
312346 if obj_type is None :
0 commit comments