mirror of
https://github.com/mandiant/capa.git
synced 2026-02-04 11:07:53 -08:00
add perf counters in module capa.perf
This commit is contained in:
@@ -10,6 +10,7 @@ import copy
|
||||
import collections
|
||||
from typing import Set, Dict, List, Tuple, Union, Mapping, Iterable
|
||||
|
||||
import capa.perf
|
||||
import capa.rules
|
||||
import capa.features.common
|
||||
from capa.features.common import Feature
|
||||
@@ -125,6 +126,9 @@ class And(Statement):
|
||||
self.children = children
|
||||
|
||||
def evaluate(self, ctx):
|
||||
capa.perf.counters["evaluate.feature"] += 1
|
||||
capa.perf.counters["evaluate.feature.and"] += 1
|
||||
|
||||
results = [child.evaluate(ctx) for child in self.children]
|
||||
success = all(results)
|
||||
return Result(success, self, results)
|
||||
@@ -138,6 +142,9 @@ class Or(Statement):
|
||||
self.children = children
|
||||
|
||||
def evaluate(self, ctx):
|
||||
capa.perf.counters["evaluate.feature"] += 1
|
||||
capa.perf.counters["evaluate.feature.or"] += 1
|
||||
|
||||
results = [child.evaluate(ctx) for child in self.children]
|
||||
success = any(results)
|
||||
return Result(success, self, results)
|
||||
@@ -151,6 +158,9 @@ class Not(Statement):
|
||||
self.child = child
|
||||
|
||||
def evaluate(self, ctx):
|
||||
capa.perf.counters["evaluate.feature"] += 1
|
||||
capa.perf.counters["evaluate.feature.not"] += 1
|
||||
|
||||
results = [self.child.evaluate(ctx)]
|
||||
success = not results[0]
|
||||
return Result(success, self, results)
|
||||
@@ -165,6 +175,9 @@ class Some(Statement):
|
||||
self.children = children
|
||||
|
||||
def evaluate(self, ctx):
|
||||
capa.perf.counters["evaluate.feature"] += 1
|
||||
capa.perf.counters["evaluate.feature.some"] += 1
|
||||
|
||||
results = [child.evaluate(ctx) for child in self.children]
|
||||
# note that here we cast the child result as a bool
|
||||
# because we've overridden `__bool__` above.
|
||||
@@ -184,6 +197,9 @@ class Range(Statement):
|
||||
self.max = max if max is not None else (1 << 64 - 1)
|
||||
|
||||
def evaluate(self, ctx):
|
||||
capa.perf.counters["evaluate.feature"] += 1
|
||||
capa.perf.counters["evaluate.feature.range"] += 1
|
||||
|
||||
count = len(ctx.get(self.child, []))
|
||||
if self.min == 0 and count == 0:
|
||||
return Result(True, self, [])
|
||||
|
||||
@@ -12,6 +12,7 @@ import logging
|
||||
import collections
|
||||
from typing import Set, Dict, Union
|
||||
|
||||
import capa.perf
|
||||
import capa.engine
|
||||
import capa.features
|
||||
import capa.features.extractors.elf
|
||||
@@ -97,6 +98,8 @@ class Feature:
|
||||
return str(self)
|
||||
|
||||
def evaluate(self, ctx: Dict["Feature", Set[int]]) -> "capa.engine.Result":
|
||||
capa.perf.counters["evaluate.feature"] += 1
|
||||
capa.perf.counters["evaluate.feature." + self.name] += 1
|
||||
return capa.engine.Result(self in ctx, self, [], locations=ctx.get(self, []))
|
||||
|
||||
def freeze_serialize(self):
|
||||
@@ -141,6 +144,9 @@ class Substring(String):
|
||||
self.value = value
|
||||
|
||||
def evaluate(self, ctx):
|
||||
capa.perf.counters["evaluate.feature"] += 1
|
||||
capa.perf.counters["evaluate.feature.substring"] += 1
|
||||
|
||||
# mapping from string value to list of locations.
|
||||
# will unique the locations later on.
|
||||
matches = collections.defaultdict(list)
|
||||
@@ -226,6 +232,9 @@ class Regex(String):
|
||||
)
|
||||
|
||||
def evaluate(self, ctx):
|
||||
capa.perf.counters["evaluate.feature"] += 1
|
||||
capa.perf.counters["evaluate.feature.regex"] += 1
|
||||
|
||||
# mapping from string value to list of locations.
|
||||
# will unique the locations later on.
|
||||
matches = collections.defaultdict(list)
|
||||
@@ -309,6 +318,9 @@ class Bytes(Feature):
|
||||
self.value = value
|
||||
|
||||
def evaluate(self, ctx):
|
||||
capa.perf.counters["evaluate.feature"] += 1
|
||||
capa.perf.counters["evaluate.feature.bytes"] += 1
|
||||
|
||||
for feature, locations in ctx.items():
|
||||
if not isinstance(feature, (Bytes,)):
|
||||
continue
|
||||
|
||||
@@ -28,6 +28,7 @@ import colorama
|
||||
from pefile import PEFormatError
|
||||
from elftools.common.exceptions import ELFError
|
||||
|
||||
import capa.perf
|
||||
import capa.rules
|
||||
import capa.engine
|
||||
import capa.version
|
||||
@@ -1024,6 +1025,9 @@ def main(argv=None):
|
||||
meta["analysis"].update(counts)
|
||||
meta["analysis"]["layout"] = compute_layout(rules, extractor, capabilities)
|
||||
|
||||
for (counter, count) in capa.perf.counters.most_common():
|
||||
logger.debug("perf: counter: %s: %d", counter, count)
|
||||
|
||||
if has_file_limitation(rules, capabilities):
|
||||
# bail if capa encountered file limitation e.g. a packed binary
|
||||
# do show the output in verbose mode, though.
|
||||
|
||||
3
capa/perf.py
Normal file
3
capa/perf.py
Normal file
@@ -0,0 +1,3 @@
|
||||
import collections
|
||||
|
||||
counters = collections.Counter()
|
||||
@@ -27,6 +27,7 @@ from typing import Any, Dict, List, Union, Iterator
|
||||
import yaml
|
||||
import ruamel.yaml
|
||||
|
||||
import capa.perf
|
||||
import capa.engine as ceng
|
||||
import capa.features
|
||||
import capa.features.file
|
||||
@@ -620,6 +621,8 @@ class Rule:
|
||||
yield new_rule
|
||||
|
||||
def evaluate(self, features: FeatureSet):
|
||||
capa.perf.counters["evaluate.feature"] += 1
|
||||
capa.perf.counters["evaluate.feature.rule"] += 1
|
||||
return self.statement.evaluate(features)
|
||||
|
||||
@classmethod
|
||||
|
||||
Reference in New Issue
Block a user