Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions test/plugins/test_yarascan_options.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import logging
import pathlib

import pytest

import volatility3.plugins # noqa: F401 - registers the plugins namespace

yarascan = pytest.importorskip("volatility3.plugins.yarascan")


@pytest.fixture
def rule_file(tmp_path):
path = tmp_path / "rules.yar"
path.write_text('rule t { strings: $a = "abc" condition: $a }')
return pathlib.Path(path).as_uri()


def test_yara_string_builds_rules():
rules = yarascan.YaraScan.process_yara_options({"yara_string": "abc"})
assert rules is not None


def test_no_rule_source_returns_none(caplog):
with caplog.at_level(logging.ERROR):
rules = yarascan.YaraScan.process_yara_options({})
assert rules is None
assert "No yara rules" in caplog.text


def test_yara_file_builds_rules(rule_file):
rules = yarascan.YaraScan.process_yara_options({"yara_file": rule_file})
assert rules is not None


def test_multiple_sources_warns_and_prefers_string(caplog, rule_file):
with caplog.at_level(logging.WARNING):
rules = yarascan.YaraScan.process_yara_options(
{"yara_string": "abc", "yara_file": rule_file}
)
assert rules is not None
assert "Multiple yara rule sources" in caplog.text


def test_string_options_ignored_for_file_warns(caplog, rule_file):
with caplog.at_level(logging.WARNING):
rules = yarascan.YaraScan.process_yara_options(
{"yara_file": rule_file, "insensitive": True, "wide": True}
)
assert rules is not None
assert "insensitive, wide" in caplog.text


def test_file_without_string_options_does_not_warn(caplog, rule_file):
with caplog.at_level(logging.WARNING):
yarascan.YaraScan.process_yara_options({"yara_file": rule_file})
assert "only apply to yara_string" not in caplog.text


def test_string_with_options_does_not_warn(caplog):
with caplog.at_level(logging.WARNING):
yarascan.YaraScan.process_yara_options(
{"yara_string": "abc", "insensitive": True, "wide": True}
)
assert "only apply to yara_string" not in caplog.text
25 changes: 25 additions & 0 deletions volatility3/framework/plugins/yarascan.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,9 +175,32 @@ def get_yarascan_option_requirements(
def yara_returns_instances(cls) -> bool:
return not tuple(int(x) for x in yara.__version__.split(".")) < (4, 3)

@classmethod
def _warn_ignored_string_options(cls, config: Dict[str, Any]) -> None:
"""Warns when options that only affect yara_string rules are set at the
same time as a rules file, where they have no effect."""
ignored = [name for name in ("insensitive", "wide") if config.get(name, False)]
if ignored:
vollog.warning(
f"These options only apply to yara_string rules and are ignored when a rules file is supplied: {', '.join(ignored)}"
)

@classmethod
def process_yara_options(cls, config: Dict[str, Any]):
rules = None

# Only one rule source is ever used, so warn rather than silently pick one
# when the user supplies more than one.
rule_sources = [
name
for name in ("yara_string", "yara_file", "yara_compiled_file")
if config.get(name) is not None
]
if len(rule_sources) > 1:
vollog.warning(
f"Multiple yara rule sources were supplied ({', '.join(rule_sources)}); only {rule_sources[0]} will be used"
)

if config.get("yara_string") is not None:
rule = config["yara_string"]
if rule[0] not in ["{", "/"]:
Expand All @@ -188,9 +211,11 @@ def process_yara_options(cls, config: Dict[str, Any]):
rule += " wide ascii"
rules = YaraScanner.get_rule(rule)
elif config.get("yara_file") is not None:
cls._warn_ignored_string_options(config)
vollog.debug(f"Plain file: {config['yara_file']} - yara-x: {USE_YARA_X}")
rules = YaraScanner.from_file(config["yara_file"])
elif config.get("yara_compiled_file") is not None:
cls._warn_ignored_string_options(config)
vollog.debug(
f"Compiled file: {config['yara_compiled_file']} - yara-x: {USE_YARA_X}"
)
Expand Down