mirror of
https://github.com/mandiant/capa.git
synced 2025-12-21 23:00:29 -08:00
@@ -154,10 +154,14 @@ class Range(Statement):
|
|||||||
self.max = max if max is not None else (1 << 64 - 1)
|
self.max = max if max is not None else (1 << 64 - 1)
|
||||||
|
|
||||||
def evaluate(self, ctx):
|
def evaluate(self, ctx):
|
||||||
if self.child not in ctx:
|
count = len(ctx.get(self.child, []))
|
||||||
|
if self.min == 0:
|
||||||
|
if count == 0:
|
||||||
|
return Result(True, self, [])
|
||||||
|
elif self.child not in ctx:
|
||||||
|
# self.min > 0 so there needs to be more than zero matches
|
||||||
return Result(False, self, [])
|
return Result(False, self, [])
|
||||||
|
|
||||||
count = len(ctx[self.child])
|
|
||||||
return Result(self.min <= count <= self.max, self, [], locations=ctx[self.child])
|
return Result(self.min <= count <= self.max, self, [], locations=ctx[self.child])
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
|||||||
@@ -65,7 +65,8 @@ def test_complex():
|
|||||||
|
|
||||||
def test_range():
|
def test_range():
|
||||||
# unbounded range, but no matching feature
|
# unbounded range, but no matching feature
|
||||||
assert Range(Number(1)).evaluate({Number(2): {}}) == False
|
# since the lower bound is zero, and there are zero matches, ok
|
||||||
|
assert Range(Number(1)).evaluate({Number(2): {}}) == True
|
||||||
|
|
||||||
# unbounded range with matching feature should always match
|
# unbounded range with matching feature should always match
|
||||||
assert Range(Number(1)).evaluate({Number(1): {}}) == True
|
assert Range(Number(1)).evaluate({Number(1): {}}) == True
|
||||||
@@ -96,6 +97,103 @@ def test_range():
|
|||||||
assert Range(Number(1), min=1, max=3).evaluate({Number(1): {1, 2, 3, 4}}) == False
|
assert Range(Number(1), min=1, max=3).evaluate({Number(1): {1, 2, 3, 4}}) == False
|
||||||
|
|
||||||
|
|
||||||
|
def test_range_exact():
|
||||||
|
rule = textwrap.dedent('''
|
||||||
|
rule:
|
||||||
|
meta:
|
||||||
|
name: test rule
|
||||||
|
features:
|
||||||
|
- count(number(100)): 2
|
||||||
|
''')
|
||||||
|
r = capa.rules.Rule.from_yaml(rule)
|
||||||
|
|
||||||
|
# just enough matches
|
||||||
|
features, matches = capa.engine.match([r], {capa.features.insn.Number(100): {1, 2}}, 0x0)
|
||||||
|
assert 'test rule' in matches
|
||||||
|
|
||||||
|
# not enough matches
|
||||||
|
features, matches = capa.engine.match([r], {capa.features.insn.Number(100): {1}}, 0x0)
|
||||||
|
assert 'test rule' not in matches
|
||||||
|
|
||||||
|
# too many matches
|
||||||
|
features, matches = capa.engine.match([r], {capa.features.insn.Number(100): {1, 2, 3}}, 0x0)
|
||||||
|
assert 'test rule' not in matches
|
||||||
|
|
||||||
|
|
||||||
|
def test_range_range():
|
||||||
|
rule = textwrap.dedent('''
|
||||||
|
rule:
|
||||||
|
meta:
|
||||||
|
name: test rule
|
||||||
|
features:
|
||||||
|
- count(number(100)): (2, 3)
|
||||||
|
''')
|
||||||
|
r = capa.rules.Rule.from_yaml(rule)
|
||||||
|
|
||||||
|
# just enough matches
|
||||||
|
features, matches = capa.engine.match([r], {capa.features.insn.Number(100): {1, 2}}, 0x0)
|
||||||
|
assert 'test rule' in matches
|
||||||
|
|
||||||
|
# enough matches
|
||||||
|
features, matches = capa.engine.match([r], {capa.features.insn.Number(100): {1, 2, 3}}, 0x0)
|
||||||
|
assert 'test rule' in matches
|
||||||
|
|
||||||
|
# not enough matches
|
||||||
|
features, matches = capa.engine.match([r], {capa.features.insn.Number(100): {1}}, 0x0)
|
||||||
|
assert 'test rule' not in matches
|
||||||
|
|
||||||
|
# too many matches
|
||||||
|
features, matches = capa.engine.match([r], {capa.features.insn.Number(100): {1, 2, 3, 4}}, 0x0)
|
||||||
|
assert 'test rule' not in matches
|
||||||
|
|
||||||
|
|
||||||
|
def test_range_exact_zero():
|
||||||
|
rule = textwrap.dedent('''
|
||||||
|
rule:
|
||||||
|
meta:
|
||||||
|
name: test rule
|
||||||
|
features:
|
||||||
|
- count(number(100)): 0
|
||||||
|
''')
|
||||||
|
r = capa.rules.Rule.from_yaml(rule)
|
||||||
|
|
||||||
|
# feature isn't indexed - good.
|
||||||
|
features, matches = capa.engine.match([r], {}, 0x0)
|
||||||
|
assert 'test rule' in matches
|
||||||
|
|
||||||
|
# feature is indexed, but no matches.
|
||||||
|
# i don't think we should ever really have this case, but good to check anyways.
|
||||||
|
features, matches = capa.engine.match([r], {capa.features.insn.Number(100): {}}, 0x0)
|
||||||
|
assert 'test rule' in matches
|
||||||
|
|
||||||
|
# too many matches
|
||||||
|
features, matches = capa.engine.match([r], {capa.features.insn.Number(100): {1}}, 0x0)
|
||||||
|
assert 'test rule' not in matches
|
||||||
|
|
||||||
|
|
||||||
|
def test_range_with_zero():
|
||||||
|
rule = textwrap.dedent('''
|
||||||
|
rule:
|
||||||
|
meta:
|
||||||
|
name: test rule
|
||||||
|
features:
|
||||||
|
- count(number(100)): (0, 1)
|
||||||
|
''')
|
||||||
|
r = capa.rules.Rule.from_yaml(rule)
|
||||||
|
|
||||||
|
# ok
|
||||||
|
features, matches = capa.engine.match([r], {}, 0x0)
|
||||||
|
assert 'test rule' in matches
|
||||||
|
features, matches = capa.engine.match([r], {capa.features.insn.Number(100): {}}, 0x0)
|
||||||
|
assert 'test rule' in matches
|
||||||
|
features, matches = capa.engine.match([r], {capa.features.insn.Number(100): {1}}, 0x0)
|
||||||
|
assert 'test rule' in matches
|
||||||
|
|
||||||
|
# too many matches
|
||||||
|
features, matches = capa.engine.match([r], {capa.features.insn.Number(100): {1, 2}}, 0x0)
|
||||||
|
assert 'test rule' not in matches
|
||||||
|
|
||||||
|
|
||||||
def test_match_adds_matched_rule_feature():
|
def test_match_adds_matched_rule_feature():
|
||||||
'''show that using `match` adds a feature for matched rules.'''
|
'''show that using `match` adds a feature for matched rules.'''
|
||||||
rule = textwrap.dedent('''
|
rule = textwrap.dedent('''
|
||||||
|
|||||||
Reference in New Issue
Block a user