22# which is available at https://www.volatilityfoundation.org/license/vsl-v1.0
33#
44
5+ import logging
56from typing import Iterable , List , Tuple
67
78from volatility3 .framework import interfaces , renderers
1011from volatility3 .plugins import yarascan
1112from volatility3 .plugins .linux import pslist
1213
14+ vollog = logging .getLogger (__name__ )
15+
1316
1417class VmaYaraScan (interfaces .plugins .PluginInterface ):
1518 """Scans all virtual memory areas for tasks using yara."""
1619
1720 _required_framework_version = (2 , 4 , 0 )
18- _version = (1 , 0 , 0 )
21+ _version = (1 , 0 , 2 )
1922
2023 @classmethod
2124 def get_requirements (cls ) -> List [interfaces .configuration .RequirementInterface ]:
@@ -33,6 +36,9 @@ def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]
3336 requirements .PluginRequirement (
3437 name = "yarascan" , plugin = yarascan .YaraScan , version = (2 , 0 , 0 )
3538 ),
39+ requirements .VersionRequirement (
40+ name = "yarascanner" , component = yarascan .YaraScanner , version = (2 , 0 , 0 )
41+ ),
3642 requirements .ModuleRequirement (
3743 name = "kernel" ,
3844 description = "Linux kernel" ,
@@ -50,6 +56,8 @@ def _generator(self):
5056 # use yarascan to parse the yara options provided and create the rules
5157 rules = yarascan .YaraScan .process_yara_options (dict (self .config ))
5258
59+ sanity_check = 1024 * 1024 * 1024 # 1 GB
60+
5361 # filter based on the pid option if provided
5462 filter_func = pslist .PsList .create_pid_filter (self .config .get ("pid" , None ))
5563 for task in pslist .PsList .list_tasks (
@@ -66,29 +74,36 @@ def _generator(self):
6674 # get the proc_layer object from the context
6775 proc_layer = self .context .layers [proc_layer_name ]
6876
69- for start , end in self .get_vma_maps (task ):
70- for match in rules .match (
71- data = proc_layer .read (start , end - start , True )
77+ max_vma_size = 0
78+ vma_maps_to_scan = []
79+ for start , size in self .get_vma_maps (task ):
80+ if size > sanity_check :
81+ vollog .debug (
82+ f"VMA at 0x{ start :x} over sanity-check size, not scanning"
83+ )
84+ continue
85+ max_vma_size = max (max_vma_size , size )
86+ vma_maps_to_scan .append ((start , size ))
87+
88+ if not vma_maps_to_scan :
89+ vollog .warning (f"No VMAs were found for task { task .tgid } , not scanning" )
90+ continue
91+
92+ scanner = yarascan .YaraScanner (rules = rules )
93+ scanner .chunk_size = max_vma_size
94+
95+ # scan the VMA data (in one contiguous block) with the yarascanner
96+ for start , size in vma_maps_to_scan :
97+ for offset , rule_name , name , value in scanner (
98+ proc_layer .read (start , size , pad = True ), start
7299 ):
73- if yarascan .YaraScan .yara_returns_instances ():
74- for match_string in match .strings :
75- for instance in match_string .instances :
76- yield 0 , (
77- format_hints .Hex (instance .offset + start ),
78- task .UniqueProcessId ,
79- match .rule ,
80- match_string .identifier ,
81- instance .matched_data ,
82- )
83- else :
84- for offset , name , value in match .strings :
85- yield 0 , (
86- format_hints .Hex (offset + start ),
87- task .tgid ,
88- match .rule ,
89- name ,
90- value ,
91- )
100+ yield 0 , (
101+ format_hints .Hex (offset ),
102+ task .tgid ,
103+ rule_name ,
104+ name ,
105+ value ,
106+ )
92107
93108 @staticmethod
94109 def get_vma_maps (
0 commit comments