render: dont display rules that are also matched as subrule matches

closes #224
This commit is contained in:
William Ballenthin
2020-09-02 10:20:54 -06:00
parent ba47455a0c
commit a25a86e2d6
2 changed files with 62 additions and 0 deletions

View File

@@ -36,6 +36,34 @@ def render_meta(doc, ostream):
ostream.write("\n") ostream.write("\n")
def find_subrule_matches(doc):
"""
collect the rule names that have been matched as a subrule match.
this way we can avoid displaying entries for things that are too specific.
"""
matches = set([])
def rec(node):
if not node["success"]:
# there's probably a bug here for rules that do `not: match: ...`
# but we don't have any examples of this yet
return
elif node["node"]["type"] == "statement":
for child in node["children"]:
rec(child)
elif node["node"]["type"] == "feature":
if node["node"]["feature"]["type"] == "match":
matches.add(node["node"]["feature"]["match"])
for rule in rutils.capability_rules(doc):
for node in rule["matches"].values():
rec(node)
return matches
def render_capabilities(doc, ostream): def render_capabilities(doc, ostream):
""" """
example:: example::
@@ -48,8 +76,16 @@ def render_capabilities(doc, ostream):
| ... | ... | | ... | ... |
+-------------------------------------------------------+-------------------------------------------------+ +-------------------------------------------------------+-------------------------------------------------+
""" """
subrule_matches = find_subrule_matches(doc)
rows = [] rows = []
for rule in rutils.capability_rules(doc): for rule in rutils.capability_rules(doc):
if rule["meta"]["name"] in subrule_matches:
# rules that are also matched by other rules should not get rendered by default.
# this cuts down on the amount of output while giving approx the same detail.
# see #224
continue
count = len(rule["matches"]) count = len(rule["matches"])
if count == 1: if count == 1:
capability = rutils.bold(rule["meta"]["name"]) capability = rutils.bold(rule["meta"]["name"])

View File

@@ -320,3 +320,29 @@ def test_fix262(pma16_01_extractor, capsys):
std = capsys.readouterr() std = capsys.readouterr()
assert "HTTP/1.0" in std.out assert "HTTP/1.0" in std.out
assert "www.practicalmalwareanalysis.com" not in std.out assert "www.practicalmalwareanalysis.com" not in std.out
@pytest.mark.xfail(sys.version_info >= (3, 0), reason="vivsect only works on py2")
def test_not_render_rules_also_matched(z9324d_extractor, capsys):
# rules that are also matched by other rules should not get rendered by default.
# this cuts down on the amount of output while giving approx the same detail.
# see #224
path = z9324d_extractor.path
# `act as TCP client` matches on
# `connect TCP client` matches on
# `create TCP socket`
#
# so only `act as TCP client` should be displayed
assert capa.main.main([path]) == 0
std = capsys.readouterr()
assert "act as TCP client" in std.out
assert "connect TCP socket" not in std.out
assert "create TCP socket" not in std.out
# this strategy only applies to the default renderer, not any verbose renderer
assert capa.main.main([path, "-v"]) == 0
std = capsys.readouterr()
assert "act as TCP client" in std.out
assert "connect TCP socket" in std.out
assert "create TCP socket" in std.out