From a387030f10fa02816d94835dfcc67d0b3a197775 Mon Sep 17 00:00:00 2001 From: Willi Ballenthin Date: Mon, 20 Jan 2025 13:20:26 +0000 Subject: [PATCH] vverbose: fix rendering of span-of-calls summaries https://github.com/mandiant/capa/pull/2532#discussion_r1920711965 --- capa/render/vverbose.py | 36 +++++++++++++++--------------------- 1 file changed, 15 insertions(+), 21 deletions(-) diff --git a/capa/render/vverbose.py b/capa/render/vverbose.py index 6779200ffa..6b9fe481d9 100644 --- a/capa/render/vverbose.py +++ b/capa/render/vverbose.py @@ -320,33 +320,27 @@ def collect_span_of_calls_locations( Find all the call locations used in a given span-of-calls match, recursively. Useful to collect the events used to match a span-of-calls scoped rule. """ - if isinstance(match.node, rd.StatementNode): - if ( - isinstance(match.node.statement, rd.CompoundStatement) - and match.node.statement.type == rd.CompoundStatementType.NOT - ): - child_mode = MODE_FAILURE if mode == MODE_SUCCESS else MODE_SUCCESS - for child in match.children: - yield from collect_span_of_calls_locations(child, child_mode) - elif isinstance(match.node.statement, rd.RangeStatement): - for location in match.locations: - if location.type not in (frz.AddressType.CALL,): - continue - if mode == MODE_FAILURE: - continue - yield location - else: - for child in match.children: - yield from collect_span_of_calls_locations(child, mode) - elif isinstance(match.node, rd.FeatureNode): + if not match.success: + return + + if isinstance(match.node, rd.FeatureNode) or isinstance(match.node.statement, rd.RangeStatement): for location in match.locations: - if location.type not in (frz.AddressType.CALL,): + if location.type != frz.AddressType.CALL: continue + if mode == MODE_FAILURE: + # only collect positive evidence, + # not things that filter out branches. continue + yield location else: - raise ValueError("unexpected node type") + child_mode = mode + if match.node.statement.type == rd.CompoundStatementType.NOT: + child_mode = MODE_FAILURE if mode == MODE_SUCCESS else MODE_SUCCESS + + for child in match.children: + yield from collect_span_of_calls_locations(child, child_mode) def render_rules(console: Console, doc: rd.ResultDocument):