Skip to content

Commit bb4cfb6

Browse files
committed
Initial draft of complete-vad vadyarascan
1 parent 1d4a27e commit bb4cfb6

File tree

2 files changed

+46
-21
lines changed

2 files changed

+46
-21
lines changed

volatility3/framework/plugins/windows/vadyarascan.py

Lines changed: 34 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@
22
# which is available at https://www.volatilityfoundation.org/license/vsl-v1.0
33
#
44

5+
import io
56
import logging
67
from typing import Iterable, List, Tuple
78

8-
from volatility3.framework import interfaces, renderers
9+
from volatility3.framework import exceptions, interfaces, renderers
910
from volatility3.framework.configuration import requirements
1011
from volatility3.framework.renderers import format_hints
1112
from volatility3.plugins import yarascan
@@ -18,7 +19,7 @@ class VadYaraScan(interfaces.plugins.PluginInterface):
1819
"""Scans all the Virtual Address Descriptor memory maps using yara."""
1920

2021
_required_framework_version = (2, 4, 0)
21-
_version = (1, 0, 1)
22+
_version = (1, 1, 0)
2223

2324
@classmethod
2425
def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]:
@@ -32,11 +33,8 @@ def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]
3233
requirements.PluginRequirement(
3334
name="pslist", plugin=pslist.PsList, version=(2, 0, 0)
3435
),
35-
requirements.VersionRequirement(
36-
name="yarascanner", component=yarascan.YaraScanner, version=(2, 0, 0)
37-
),
3836
requirements.PluginRequirement(
39-
name="yarascan", plugin=yarascan.YaraScan, version=(1, 2, 0)
37+
name="yarascan", plugin=yarascan.YaraScan, version=(1, 3, 0)
4038
),
4139
requirements.ListRequirement(
4240
name="pid",
@@ -59,6 +57,8 @@ def _generator(self):
5957

6058
filter_func = pslist.PsList.create_pid_filter(self.config.get("pid", None))
6159

60+
sanity_check = 0x1000 * 0x1000 * 0x1000
61+
6262
for task in pslist.PsList.list_processes(
6363
context=self.context,
6464
layer_name=kernel.layer_name,
@@ -67,18 +67,34 @@ def _generator(self):
6767
):
6868
layer_name = task.add_process_layer()
6969
layer = self.context.layers[layer_name]
70-
for offset, rule_name, name, value in layer.scan(
71-
context=self.context,
72-
scanner=yarascan.YaraScanner(rules=rules),
73-
sections=self.get_vad_maps(task),
74-
):
75-
yield 0, (
76-
format_hints.Hex(offset),
77-
task.UniqueProcessId,
78-
rule_name,
79-
name,
80-
value,
81-
)
70+
for start, end in self.get_vad_maps(task):
71+
size = end - start
72+
if size > sanity_check:
73+
vollog.warn(
74+
f"VAD at 0x{start:x} over sanity-check size, not scanning"
75+
)
76+
continue
77+
78+
for match in rules.match(data=layer.read(start, end - start, True)):
79+
if yarascan.YaraScan.yara_returns_instances():
80+
for match_string in match.strings:
81+
for instance in match_string.instances:
82+
yield 0, (
83+
format_hints.Hex(instance.offset + start),
84+
task.UniqueProcessId,
85+
match.rule,
86+
match_string.identifier,
87+
instance.matched_data,
88+
)
89+
else:
90+
for offset, name, value in match.strings:
91+
yield 0, (
92+
format_hints.Hex(offset + start),
93+
task.UniqueProcessId,
94+
match.rule,
95+
name,
96+
value,
97+
)
8298

8399
@staticmethod
84100
def get_vad_maps(

volatility3/framework/plugins/yarascan.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@
22
# which is available at https://www.volatilityfoundation.org/license/vsl-v1.0
33
#
44

5+
import io
56
import logging
67
from typing import Any, Dict, Iterable, List, Tuple
78

8-
from volatility3.framework import interfaces, renderers
9+
from volatility3.framework import exceptions, interfaces, renderers
910
from volatility3.framework.configuration import requirements
1011
from volatility3.framework.interfaces import plugins
1112
from volatility3.framework.layers import resources
@@ -43,7 +44,7 @@ def __call__(
4344
self, data: bytes, data_offset: int
4445
) -> Iterable[Tuple[int, str, str, bytes]]:
4546
for match in self._rules.match(data=data):
46-
if self.st_object:
47+
if YaraScan.yara_returns_instances():
4748
for match_string in match.strings:
4849
for instance in match_string.instances:
4950
yield (
@@ -61,7 +62,7 @@ class YaraScan(plugins.PluginInterface):
6162
"""Scans kernel memory using yara rules (string or file)."""
6263

6364
_required_framework_version = (2, 0, 0)
64-
_version = (1, 2, 0)
65+
_version = (1, 3, 0)
6566

6667
# TODO: When the major version is bumped, take the opportunity to rename the yara_rules config to yara_string
6768
# or something that makes more sense
@@ -119,6 +120,14 @@ def get_yarascan_option_requirements(
119120
),
120121
]
121122

123+
@classmethod
124+
def yara_returns_instances(self) -> bool:
125+
st_object = not tuple([int(x) for x in yara.__version__.split(".")]) < (
126+
4,
127+
3,
128+
)
129+
return st_object
130+
122131
@classmethod
123132
def process_yara_options(cls, config: Dict[str, Any]):
124133
rules = None

0 commit comments

Comments
 (0)