11# This file is Copyright 2019 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 __future__ import annotations
45
5- from dataclasses import dataclass
66import logging
77import re
8- from typing import Dict , Generator , List , Set , Tuple , Optional
8+ from dataclasses import dataclass
9+ from typing import Generator
910
10- from volatility3 .framework import interfaces , renderers , exceptions , constants
11+ from volatility3 .framework import constants , exceptions , interfaces , renderers
1112from volatility3 .framework .configuration import requirements
12- from volatility3 .framework .layers import intel , resources , linear
13+ from volatility3 .framework .layers import intel , linear , resources
1314from volatility3 .framework .renderers import format_hints
1415from volatility3 .plugins .windows import pslist
1516
1819
1920@dataclass
2021class MappingNode :
21- def __init__ (
22- self ,
23- physical_addr_start ,
24- physical_addr_end ,
25- virtual_addr_start ,
26- virtual_addr_end ,
27- process_id ,
28- region ,
29- ) -> None :
30- self .physical_addr_start = physical_addr_start
31- self .physical_addr_end = physical_addr_end
32- self .virtual_addr_start = virtual_addr_start
33- self .virtual_addr_end = virtual_addr_end
34- self .process_id = process_id
35- self .region = region
22+ physical_addr_start : int
23+ physical_addr_end : int
24+ virtual_addr_start : int
25+ virtual_addr_end : int
26+ process_id : int | str
27+ region : str
3628
3729
30+ @dataclass
3831class MappingTree :
39- def __init__ (self , root = None ) -> None :
40- self .root = root
41- self .left = None
42- self .right = None
43-
44- def add (self , node ):
45- if isinstance (node , MappingNode ):
46- if self .root == None :
47- self .root = node
48- elif node .physical_addr_start < self .root .physical_addr_start :
49- if self .left == None :
50- self .left = MappingTree (node )
32+ root : MappingNode | None = None
33+ left : MappingTree | None = None
34+ right : MappingTree | None = None
35+
36+ def add (self , node : MappingNode , depth : int = 0 ) -> None :
37+ # Iteratively add to avoid recursion issues
38+ if not isinstance (node , MappingNode ):
39+ raise TypeError
40+ parent_node : MappingTree | None = self
41+ while parent_node is not None :
42+ if parent_node .root is None :
43+ parent_node .root = node
44+ parent_node = None
45+ elif node .physical_addr_start < parent_node .root .physical_addr_start :
46+ if parent_node .left is None :
47+ parent_node .left = MappingTree (node )
48+ parent_node = None
5149 else :
52- self .left . add ( node )
50+ parent_node = parent_node .left
5351 else :
54- if self .right == None :
55- self .right = MappingTree (node )
52+ if parent_node .right is None :
53+ parent_node .right = MappingTree (node )
54+ parent_node = None
5655 else :
57- self .right .add (node )
58- else :
59- raise TypeError ()
56+ parent_node = parent_node .right
6057
6158 def at (self , point ):
6259 if self .root :
@@ -80,7 +77,7 @@ class Strings(interfaces.plugins.PluginInterface):
8077 strings_pattern = re .compile (rb"^(?:\W*)([0-9]+)(?:\W*)(\w[\w\W]+)\n?" )
8178
8279 @classmethod
83- def get_requirements (cls ) -> List [interfaces .configuration .RequirementInterface ]:
80+ def get_requirements (cls ) -> list [interfaces .configuration .RequirementInterface ]:
8481 return [
8582 requirements .ModuleRequirement (
8683 name = "kernel" ,
@@ -113,13 +110,14 @@ def run(self):
113110 self ._generator (),
114111 )
115112
116- def _generator (self ) -> Generator [Tuple , None , None ]:
113+ def _generator (self ) -> Generator [tuple , None , None ]:
117114 """Generates results from a strings file."""
118- string_list : List [ Tuple [int , bytes ]] = []
115+ string_list : list [ tuple [int , bytes ]] = []
119116
120117 # Test strings file format is accurate
121- accessor = resources .ResourceAccessor ()
122- strings_fp = accessor .open (self .config ["strings_file" ], "rb" )
118+ strings_fp = resources .ResourceAccessor ().open (
119+ self .config ["strings_file" ], "rb"
120+ )
123121 line = strings_fp .readline ()
124122 count : float = 0
125123 while line :
@@ -140,9 +138,9 @@ def _generator(self) -> Generator[Tuple, None, None]:
140138 pid_list = self .config ["pid" ],
141139 )
142140
143- last_prog : float = 0
141+ _last_prog : float = 0
144142 line_count : float = 0
145- num_strings = len (string_list )
143+ _num_strings = len (string_list )
146144
147145 for phys_offset , string in string_list :
148146 line_count += 1
@@ -177,7 +175,7 @@ def _generator(self) -> Generator[Tuple, None, None]:
177175 ),
178176 )
179177
180- def _parse_line (self , line : bytes ) -> Tuple [int , bytes ]:
178+ def _parse_line (self , line : bytes ) -> tuple [int , bytes ]:
181179 """Parses a single line from a strings file.
182180
183181 Args:
@@ -200,8 +198,8 @@ def generate_mapping(
200198 layer_name : str ,
201199 symbol_table : str ,
202200 progress_callback : constants .ProgressCallback = None ,
203- pid_list : Optional [ List [ int ]] = None ,
204- ) -> Dict [ int , Set [ Tuple [ str , int ]]] :
201+ pid_list : list [ int ] | None = None ,
202+ ) -> MappingTree :
205203 """Creates a reverse mapping between virtual addresses and physical
206204 addresses.
207205
@@ -219,7 +217,7 @@ def generate_mapping(
219217 revmap_tree = MappingTree ()
220218
221219 # start with kernel mappings
222- layer = context .layers [layer_name ]
220+ layer : intel . Intel = context .layers [layer_name ]
223221 min_kernel_addr = 2 ** (layer ._maxvirtaddr - 1 )
224222 if isinstance (layer , intel .Intel ):
225223 # We don't care about errors, we just wanted chunks that map correctly
@@ -247,7 +245,7 @@ def generate_mapping(
247245 if progress_callback :
248246 progress_callback (
249247 (virt_offset * 100 ) / layer .maximum_address ,
250- f"Creating custom tree mapping for kernel" ,
248+ f"Creating custom tree mapping for kernel at offset : { virt_offset :x } " ,
251249 )
252250
253251 # now process normal processes, ignoring kernel addrs
@@ -259,13 +257,11 @@ def generate_mapping(
259257 proc_layer_name = process .add_process_layer ()
260258 except exceptions .InvalidAddressException as excp :
261259 vollog .debug (
262- "Process {}: invalid address {} in layer {}" .format (
263- proc_id , excp .invalid_address , excp .layer_name
264- )
260+ f"Process { proc_id } : invalid address { excp .invalid_address } in layer { excp .layer_name } "
265261 )
266262 continue
267263
268- proc_layer = context .layers [proc_layer_name ]
264+ proc_layer : intel . Intel = context .layers [proc_layer_name ]
269265 max_proc_addr = (2 ** (proc_layer ._maxvirtaddr - 1 )) - 1
270266 if isinstance (proc_layer , linear .LinearlyMappedLayer ):
271267 for mapval in proc_layer .mapping (
@@ -284,14 +280,14 @@ def generate_mapping(
284280 phy_offset + phy_mapping_size ,
285281 virt_offset ,
286282 virt_offset + virt_size ,
287- proc_id ,
288- "Process" ,
283+ process_id = proc_id ,
284+ region = "Process" ,
289285 )
290286 revmap_tree .add (node )
291287
292288 if progress_callback :
293289 progress_callback (
294290 (virt_offset * 100 ) / max_proc_addr ,
295- f"Creating custom tree mapping for task { proc_id } " ,
291+ f"Creating custom tree mapping for task { proc_id } : { virt_offset :x } " ,
296292 )
297293 return revmap_tree
0 commit comments