diff --git a/capa/render/default.py b/capa/render/default.py index 6bdef70a..db8cb61e 100644 --- a/capa/render/default.py +++ b/capa/render/default.py @@ -47,8 +47,11 @@ def render_capabilities(doc, ostream): capability = "%s (%d matches)" % (rutils.bold(rule["meta"]["name"]), count) rows.append((capability, rule["meta"]["namespace"])) - ostream.write(tabulate.tabulate(rows, headers=[width("CAPABILITY", 50), width("NAMESPACE", 50)], tablefmt="psql")) - ostream.write("\n") + if rows: + ostream.write(tabulate.tabulate(rows, headers=[width("CAPABILITY", 50), width("NAMESPACE", 50)], tablefmt="psql")) + ostream.write("\n") + else: + ostream.writeln(rutils.bold("no capabilities found")) def render_attack(doc, ostream): @@ -95,10 +98,12 @@ def render_attack(doc, ostream): else: raise RuntimeError("unexpected ATT&CK spec format") rows.append((rutils.bold(tactic.upper()), "\n".join(inner_rows),)) - ostream.write( - tabulate.tabulate(rows, headers=[width("ATT&CK Tactic", 20), width("ATT&CK Technique", 80)], tablefmt="psql") - ) - ostream.write("\n") + + if rows: + ostream.write( + tabulate.tabulate(rows, headers=[width("ATT&CK Tactic", 20), width("ATT&CK Technique", 80)], tablefmt="psql") + ) + ostream.write("\n") def render_default(doc): diff --git a/capa/render/verbose.py b/capa/render/verbose.py index 99a78f23..c8742707 100644 --- a/capa/render/verbose.py +++ b/capa/render/verbose.py @@ -69,6 +69,7 @@ def render_rules(ostream, doc): matches 0x10003A13 0x10003797 """ + had_match = False for rule in rutils.capability_rules(doc): count = len(rule["matches"]) if count == 1: @@ -77,6 +78,7 @@ def render_rules(ostream, doc): capability = "%s (%d matches)" % (rutils.bold(rule["meta"]["name"]), count) ostream.writeln(capability) + had_match = True rows = [] for key in ("namespace", "description", "scope"): @@ -95,6 +97,9 @@ def render_rules(ostream, doc): ostream.writeln(tabulate.tabulate(rows, tablefmt="plain")) ostream.write("\n") + if not had_match: + ostream.writeln(rutils.bold("no capabilities found")) + def render_verbose(doc): ostream = rutils.StringIO() diff --git a/capa/render/vverbose.py b/capa/render/vverbose.py index 7a703e96..adf53dd8 100644 --- a/capa/render/vverbose.py +++ b/capa/render/vverbose.py @@ -158,6 +158,7 @@ def render_rules(ostream, doc): api: kernel32.GetLastError @ 0x10004A87 api: kernel32.OutputDebugString @ 0x10004767, 0x10004787, 0x10004816, 0x10004895 """ + had_match = False for rule in rutils.capability_rules(doc): count = len(rule["matches"]) if count == 1: @@ -166,6 +167,7 @@ def render_rules(ostream, doc): capability = "%s (%d matches)" % (rutils.bold(rule["meta"]["name"]), count) ostream.writeln(capability) + had_match = True rows = [] for key in capa.rules.META_KEYS: @@ -198,6 +200,9 @@ def render_rules(ostream, doc): render_match(ostream, match, indent=1) ostream.write("\n") + if not had_match: + ostream.writeln(rutils.bold("no capabilities found")) + def render_vverbose(doc): ostream = rutils.StringIO()