@@ -32,12 +32,6 @@ def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]
3232 requirements .PluginRequirement (
3333 name = "lsmod" , plugin = lsmod .Lsmod , version = (2 , 0 , 0 )
3434 ),
35- requirements .BooleanRequirement (
36- name = "fast" ,
37- description = "Fast scan method. Recommended only for kernels 4.2 and above" ,
38- optional = True ,
39- default = False ,
40- ),
4135 ]
4236
4337 @staticmethod
@@ -86,134 +80,13 @@ def get_modules_memory_boundaries(
8680
8781 return modules_addr_min , modules_addr_max
8882
89- @staticmethod
90- def _get_module_state_values_bytes (
91- context : interfaces .context .ContextInterface ,
92- vmlinux_module_name : str ,
93- ) -> List [bytes ]:
94- """Retrieve the module state values bytes by introspecting its enum type
95-
96- Args:
97- context: The context to retrieve required elements (layers, symbol tables) from
98- vmlinux_module_name: The name of the kernel module on which to operate
99-
100- Returns:
101- A list with the module state values bytes
102- """
103- vmlinux = context .modules [vmlinux_module_name ]
104- module_state_type_template = vmlinux .get_type ("module" ).vol .members ["state" ][1 ]
105- data_format = module_state_type_template .base_type .vol .data_format
106- values = module_state_type_template .choices .values ()
107- values_bytes = [
108- objects .convert_value_to_data (value , int , data_format )
109- for value in sorted (values )
110- ]
111- return values_bytes
112-
113- @classmethod
114- def _get_hidden_modules_vol2 (
115- cls ,
116- context : interfaces .context .ContextInterface ,
117- vmlinux_module_name : str ,
118- known_module_addresses : Set [int ],
119- modules_memory_boundaries : Tuple ,
120- ) -> Iterable [interfaces .objects .ObjectInterface ]:
121- """Enumerate hidden modules using the traditional implementation.
122-
123- This is a port of the Volatility2 plugin, with minor code improvements.
124-
125- Args:
126- context: The context to retrieve required elements (layers, symbol tables) from
127- vmlinux_module_name: The name of the kernel module on which to operate
128- known_module_addresses: Set with known module addresses
129- modules_memory_boundaries: Minimum and maximum address boundaries for module allocation.
130-
131- Yields:
132- module objects
133- """
134- vmlinux = context .modules [vmlinux_module_name ]
135- vmlinux_layer = context .layers [vmlinux .layer_name ]
136-
137- check_nums = (
138- 3000 ,
139- 2800 ,
140- 2700 ,
141- 2500 ,
142- 2300 ,
143- 2100 ,
144- 2000 ,
145- 1500 ,
146- 1300 ,
147- 1200 ,
148- 1024 ,
149- 512 ,
150- 256 ,
151- 128 ,
152- 96 ,
153- 64 ,
154- 48 ,
155- 32 ,
156- 24 ,
157- )
158- modules_addr_min , modules_addr_max = modules_memory_boundaries
159- modules_addr_min = modules_addr_min & ~ 0xFFF
160- modules_addr_max = (modules_addr_max & ~ 0xFFF ) + vmlinux_layer .page_size
161-
162- check_bufs = []
163- replace_bufs = []
164- minus_size = vmlinux .get_type ("pointer" ).size
165- null_pointer_bytes = b"\x00 " * minus_size
166- for num in check_nums :
167- check_bufs .append (b"\x00 " * num )
168- replace_bufs .append ((b"\xff " * (num - minus_size )) + null_pointer_bytes )
169-
170- all_ffs = b"\xff " * 4096
171- scan_list = []
172- for page_addr in range (
173- modules_addr_min , modules_addr_max , vmlinux_layer .page_size
174- ):
175- content_fixed = all_ffs
176- with contextlib .suppress (
177- exceptions .InvalidAddressException ,
178- exceptions .PagedInvalidAddressException ,
179- ):
180- content = vmlinux_layer .read (page_addr , vmlinux_layer .page_size )
181-
182- all_nulls = all (x == 0 for x in content )
183- if content and not all_nulls :
184- content_fixed = content
185- for check_bytes , replace_bytes in zip (check_bufs , replace_bufs ):
186- content_fixed = content_fixed .replace (
187- check_bytes , replace_bytes
188- )
189-
190- scan_list .append (content_fixed )
191-
192- scan_buf = b"" .join (scan_list )
193- del scan_list
194-
195- module_state_values_bytes = cls ._get_module_state_values_bytes (
196- context , vmlinux_module_name
197- )
198- values_bytes_pattern = b"|" .join (module_state_values_bytes )
199- # f'strings cannot be combined with bytes literals
200- for cur_addr in re .finditer (b"(?=(%s))" % values_bytes_pattern , scan_buf ):
201- module_addr = modules_addr_min + cur_addr .start ()
202-
203- if module_addr in known_module_addresses :
204- continue
205-
206- module = vmlinux .object ("module" , offset = module_addr , absolute = True )
207- if module and module .is_valid ():
208- yield module
209-
21083 @classmethod
21184 def _get_module_address_alignment (
21285 cls ,
21386 context : interfaces .context .ContextInterface ,
21487 vmlinux_module_name : str ,
21588 ) -> int :
216- """Obtain the module memory address alignment. This is only used with the fast scan method.
89+ """Obtain the module memory address alignment.
21790
21891 struct module is aligned to the L1 cache line, which is typically 64 bytes for most
21992 common i386/AMD64/ARM64 configurations. In some cases, it can be 128 bytes, but this
@@ -231,8 +104,24 @@ def _get_module_address_alignment(
231104 # essential for retrieving type metadata in the future.
232105 return 64
233106
107+ @staticmethod
108+ def _validate_alignment_patterns (
109+ addresses : Iterable [int ],
110+ address_alignment : int ,
111+ ) -> bool :
112+ """Check if the memory addresses meet our alignments patterns
113+
114+ Args:
115+ addresses: Iterable with the address values
116+ address_alignment: Number of bytes for alignment validation
117+
118+ Returns:
119+ True if all the addresses meet the alignment
120+ """
121+ return all (addr % address_alignment == 0 for addr in addresses )
122+
234123 @classmethod
235- def _get_hidden_modules_fast (
124+ def get_hidden_modules (
236125 cls ,
237126 context : interfaces .context .ContextInterface ,
238127 vmlinux_module_name : str ,
@@ -268,6 +157,14 @@ def _get_hidden_modules_fast(
268157 module_address_alignment = cls ._get_module_address_alignment (
269158 context , vmlinux_module_name
270159 )
160+ if not cls ._validate_alignment_patterns (
161+ known_module_addresses , module_address_alignment
162+ ):
163+ vollog .warning (
164+ f"Module addresses aren't aligned to { module_address_alignment } bytes. "
165+ "Switching to 1 byte aligment scan method."
166+ )
167+ module_address_alignment = 1
271168
272169 mkobj_offset = vmlinux .get_type ("module" ).relative_child_offset ("mkobj" )
273170 mod_offset = vmlinux .get_type ("module_kobject" ).relative_child_offset ("mod" )
@@ -302,66 +199,6 @@ def _get_hidden_modules_fast(
302199 if module and module .is_valid ():
303200 yield module
304201
305- @staticmethod
306- def _validate_alignment_patterns (
307- addresses : Iterable [int ],
308- address_alignment : int ,
309- ) -> bool :
310- """Check if the memory addresses meet our alignments patterns
311-
312- Args:
313- addresses: Iterable with the address values
314- address_alignment: Number of bytes for alignment validation
315-
316- Returns:
317- True if all the addresses meet the alignment
318- """
319- return all (addr % address_alignment == 0 for addr in addresses )
320-
321- @classmethod
322- def get_hidden_modules (
323- cls ,
324- context : interfaces .context .ContextInterface ,
325- vmlinux_module_name : str ,
326- known_module_addresses : Set [int ],
327- modules_memory_boundaries : Tuple ,
328- fast_method : bool = False ,
329- ) -> Iterable [interfaces .objects .ObjectInterface ]:
330- """Enumerate hidden modules
331-
332- Args:
333- context: The context to retrieve required elements (layers, symbol tables) from
334- vmlinux_module_name: The name of the kernel module on which to operate
335- known_module_addresses: Set with known module addresses
336- modules_memory_boundaries: Minimum and maximum address boundaries for module allocation.
337- fast_method: If True, it uses the fast method. Otherwise, it uses the traditional one.
338- Yields:
339- module objects
340- """
341- if fast_method :
342- module_address_alignment = cls ._get_module_address_alignment (
343- context , vmlinux_module_name
344- )
345- if cls ._validate_alignment_patterns (
346- known_module_addresses , module_address_alignment
347- ):
348- scan_method = cls ._get_hidden_modules_fast
349- else :
350- vollog .warning (
351- f"Module addresses aren't aligned to { module_address_alignment } bytes. "
352- "Switching to the traditional scan method."
353- )
354- scan_method = cls ._get_hidden_modules_vol2
355- else :
356- scan_method = cls ._get_hidden_modules_vol2
357-
358- yield from scan_method (
359- context ,
360- vmlinux_module_name ,
361- known_module_addresses ,
362- modules_memory_boundaries ,
363- )
364-
365202 @classmethod
366203 def get_lsmod_module_addresses (
367204 cls ,
@@ -399,7 +236,6 @@ def _generator(self):
399236 vmlinux_module_name ,
400237 known_module_addresses ,
401238 modules_memory_boundaries ,
402- fast_method = self .config .get ("fast" ),
403239 ):
404240 module_addr = module .vol .offset
405241 module_name = module .get_name () or renderers .NotAvailableValue ()
0 commit comments