Merge pull request #1193 from volatilityfoundation/issues/issue1155

Initial draft of complete-vad vadyarascan
This commit is contained in:
ikelos
2024-07-14 15:16:35 +01:00
committed by GitHub
2 changed files with 42 additions and 19 deletions
@@ -18,7 +18,7 @@ class VadYaraScan(interfaces.plugins.PluginInterface):
"""Scans all the Virtual Address Descriptor memory maps using yara."""
_required_framework_version = (2, 4, 0)
_version = (1, 0, 1)
_version = (1, 1, 0)
@classmethod
def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]:
@@ -32,11 +32,8 @@ class VadYaraScan(interfaces.plugins.PluginInterface):
requirements.PluginRequirement(
name="pslist", plugin=pslist.PsList, version=(2, 0, 0)
),
requirements.VersionRequirement(
name="yarascanner", component=yarascan.YaraScanner, version=(2, 0, 0)
),
requirements.PluginRequirement(
name="yarascan", plugin=yarascan.YaraScan, version=(1, 2, 0)
name="yarascan", plugin=yarascan.YaraScan, version=(1, 3, 0)
),
requirements.ListRequirement(
name="pid",
@@ -59,6 +56,8 @@ class VadYaraScan(interfaces.plugins.PluginInterface):
filter_func = pslist.PsList.create_pid_filter(self.config.get("pid", None))
sanity_check = 0x1000 * 0x1000 * 0x1000
for task in pslist.PsList.list_processes(
context=self.context,
layer_name=kernel.layer_name,
@@ -67,18 +66,34 @@ class VadYaraScan(interfaces.plugins.PluginInterface):
):
layer_name = task.add_process_layer()
layer = self.context.layers[layer_name]
for offset, rule_name, name, value in layer.scan(
context=self.context,
scanner=yarascan.YaraScanner(rules=rules),
sections=self.get_vad_maps(task),
):
yield 0, (
format_hints.Hex(offset),
task.UniqueProcessId,
rule_name,
name,
value,
)
for start, end in self.get_vad_maps(task):
size = end - start
if size > sanity_check:
vollog.warn(
f"VAD at 0x{start:x} over sanity-check size, not scanning"
)
continue
for match in rules.match(data=layer.read(start, end - start, True)):
if yarascan.YaraScan.yara_returns_instances():
for match_string in match.strings:
for instance in match_string.instances:
yield 0, (
format_hints.Hex(instance.offset + start),
task.UniqueProcessId,
match.rule,
match_string.identifier,
instance.matched_data,
)
else:
for offset, name, value in match.strings:
yield 0, (
format_hints.Hex(offset + start),
task.UniqueProcessId,
match.rule,
name,
value,
)
@staticmethod
def get_vad_maps(
+10 -2
View File
@@ -43,7 +43,7 @@ class YaraScanner(interfaces.layers.ScannerInterface):
self, data: bytes, data_offset: int
) -> Iterable[Tuple[int, str, str, bytes]]:
for match in self._rules.match(data=data):
if self.st_object:
if YaraScan.yara_returns_instances():
for match_string in match.strings:
for instance in match_string.instances:
yield (
@@ -61,7 +61,7 @@ class YaraScan(plugins.PluginInterface):
"""Scans kernel memory using yara rules (string or file)."""
_required_framework_version = (2, 0, 0)
_version = (1, 2, 0)
_version = (1, 3, 0)
# TODO: When the major version is bumped, take the opportunity to rename the yara_rules config to yara_string
# or something that makes more sense
@@ -119,6 +119,14 @@ class YaraScan(plugins.PluginInterface):
),
]
@classmethod
def yara_returns_instances(cls) -> bool:
st_object = not tuple([int(x) for x in yara.__version__.split(".")]) < (
4,
3,
)
return st_object
@classmethod
def process_yara_options(cls, config: Dict[str, Any]):
rules = None