55found in Linux's /proc file system."""
66
77import logging
8- from typing import Callable , List , Generator , Iterable , Type , Optional
8+ from typing import Callable , Generator , Type , Optional
99
1010from volatility3 .framework import renderers , interfaces , exceptions
1111from volatility3 .framework .configuration import requirements
1616
1717vollog = logging .getLogger (__name__ )
1818
19+
1920class Maps (plugins .PluginInterface ):
2021 """Lists all memory maps for all processes."""
2122
@@ -48,9 +49,9 @@ def get_requirements(cls):
4849 ),
4950 requirements .ListRequirement (
5051 name = "address" ,
51- description = "Process virtual memory address to include "
52- "(all other address ranges are excluded). This must be "
53- "a base address, not an address within the desired range ." ,
52+ description = "Process virtual memory addresses to include "
53+ "(all other VMA sections are excluded). This can be any "
54+ "virtual address within the VMA section ." ,
5455 element_type = int ,
5556 optional = True ,
5657 ),
@@ -69,21 +70,25 @@ def list_vmas(
6970 task : interfaces .objects .ObjectInterface ,
7071 filter_func : Callable [
7172 [interfaces .objects .ObjectInterface ], bool
72- ] = lambda _ : False ,
73+ ] = lambda _ : True ,
7374 ) -> Generator [interfaces .objects .ObjectInterface , None , None ]:
7475 """Lists the Virtual Memory Areas of a specific process.
7576
7677 Args:
7778 task: task object from which to list the vma
78- filter_func: Function to take a vma and return True if it should be filtered out
79+ filter_func: Function to take a vma and return False if it should be filtered out
7980
8081 Returns:
81- A list of vmas based on the task and filtered based on the filter function
82+ Yields vmas based on the task and filtered based on the filter function
8283 """
8384 if task .mm :
8485 for vma in task .mm .get_mmap_iter ():
85- if not filter_func (vma ):
86+ if filter_func (vma ):
8687 yield vma
88+ else :
89+ vollog .debug (
90+ f"Excluded vma at offset { vma .vol .offset :#x} for pid { task .pid } due to filter_func"
91+ )
8792
8893 @classmethod
8994 def vma_dump (
@@ -106,23 +111,15 @@ def vma_dump(
106111 Returns:
107112 An open FileInterface object containing the complete data for the task or None in the case of failure
108113 """
114+ pid = task .pid
109115 try :
110116 vm_start = vma .vm_start
111117 vm_end = vma .vm_end
112118 except AttributeError :
113- vollog .debug ("Unable to find the vm_start and vm_end" )
114- return None
115-
116- vm_size = vm_end - vm_start
117- if 0 < maxsize < vm_size :
118- vollog .debug (
119- f"Skip virtual memory dump { vm_start :#x} -{ vm_end :#x} due to maxsize limit"
120- )
119+ vollog .debug (f"Unable to find the vm_start and vm_end for pid { pid } " )
121120 return None
122121
123- pid = "Unknown"
124122 try :
125- pid = task .tgid
126123 proc_layer_name = task .add_process_layer ()
127124 except exceptions .InvalidAddressException as excp :
128125 vollog .debug (
@@ -132,6 +129,13 @@ def vma_dump(
132129 )
133130 return None
134131
132+ vm_size = vm_end - vm_start
133+ if 0 < maxsize < vm_size :
134+ vollog .warning (
135+ f"Skip virtual memory dump for pid { pid } between { vm_start :#x} -{ vm_end :#x} as { vm_size } is larger than maxsize limit of { maxsize } "
136+ )
137+ return None
138+
135139 proc_layer = context .layers [proc_layer_name ]
136140 file_name = f"pid.{ pid } .vma.{ vm_start :#x} -{ vm_end :#x} .dmp"
137141 try :
@@ -141,8 +145,6 @@ def vma_dump(
141145 while offset < vm_start + vm_size :
142146 to_read = min (chunk_size , vm_start + vm_size - offset )
143147 data = proc_layer .read (offset , to_read , pad = True )
144- if not data :
145- break
146148 file_handle .write (data )
147149 offset += to_read
148150
@@ -154,24 +156,32 @@ def vma_dump(
154156
155157 def _generator (self , tasks ):
156158 # build filter for addresses if required
157- address_list = self .config .get ("address" , [] )
158- if address_list == [] :
159+ address_list = self .config .get ("address" , None )
160+ if not address_list :
159161 # do not filter as no address_list was supplied
160- filter_func = lambda _ : False
162+ vma_filter_func = lambda _ : True
161163 else :
162164 # filter for any vm_start that matches the supplied address config
163- def filter_function (x : interfaces .objects .ObjectInterface ) -> bool :
164- return x .vm_start not in address_list
165+ def vma_filter_function (x : interfaces .objects .ObjectInterface ) -> bool :
166+ addrs_in_vma = [
167+ addr for addr in address_list if x .vm_start <= addr <= x .vm_end
168+ ]
169+
170+ # if any of the user supplied addresses would fall within this vma return true
171+ if addrs_in_vma :
172+ return True
173+ else :
174+ return False
165175
166- filter_func = filter_function
176+ vma_filter_func = vma_filter_function
167177
168178 for task in tasks :
169179 if not task .mm :
170180 continue
171181
172182 name = utility .array_to_string (task .comm )
173183
174- for vma in self .list_vmas (task , filter_func = filter_func ):
184+ for vma in self .list_vmas (task , filter_func = vma_filter_func ):
175185 flags = vma .get_protection ()
176186 page_offset = vma .get_page_offset ()
177187 major = 0
0 commit comments