summaryrefslogtreecommitdiff
path: root/tests/analysis/scan/grammar.py
diff options
context:
space:
mode:
Diffstat (limited to 'tests/analysis/scan/grammar.py')
-rw-r--r--tests/analysis/scan/grammar.py327
1 files changed, 116 insertions, 211 deletions
diff --git a/tests/analysis/scan/grammar.py b/tests/analysis/scan/grammar.py
index 5a2e1d5..8b18f81 100644
--- a/tests/analysis/scan/grammar.py
+++ b/tests/analysis/scan/grammar.py
@@ -1,286 +1,191 @@
-from chrysacase import ChrysalideTestCase
-from pychrysalide.analysis.contents import MemoryContent
-from pychrysalide.analysis.scan import ContentScanner
-from pychrysalide.analysis.scan import ScanOptions
-from pychrysalide.analysis.scan.patterns.backends import AcismBackend
+from common import RostTestClass
-class TestRostGrammar(ChrysalideTestCase):
- """TestCase for analysis.scan.ScanExpression."""
+class TestRostGrammar(RostTestClass):
+ """TestCases for the ROST grammar."""
- @classmethod
- def setUpClass(cls):
+ def testRelationalExpressions(self):
+ """Build expressions with relational comparisons."""
- super(TestRostGrammar, cls).setUpClass()
+ cases = [
- cls._options = ScanOptions()
- cls._options.backend_for_data = AcismBackend
+ # Regular
+ [ '-1', '<=', '2', True ],
+ [ '-1', '<=', '2', True ],
+ [ '"aaa"', '==', '"aaa"', True ],
+ [ '"aaa"', '<', '"aaaa"', True ],
+ [ '""', '<', '"aaaa"', True ],
+ # Cast
+ [ 'false', '==', '0', True ],
+ [ 'false', '==', '1', False ],
+ [ 'true', '!=', '0', True ],
+ [ '1', '==', 'true', True ],
+ [ 'false', '==', '()', True ],
+ [ 'true', '==', '(0,)', True ],
- def testComments(self):
- """Ensure comments do not bother rule definitions."""
+ ]
- cnt = MemoryContent(b'no_real_content')
+ for op1, kwd, op2, expected in cases:
- rule = '''
-/*
- Multi-line header...
-*/
-
-rule test { // comment
-
- /*
- * Some context
- */
-
- condition: /* List of condition(s) */
- true // Dummy condition
-
-}
-'''
-
- scanner = ContentScanner(rule)
- ctx = scanner.analyze(self._options, cnt)
-
- self.assertTrue(not(ctx is None) and ctx.has_match_for_rule('test'))
-
-
- def testUintCast(self):
- """Process nested integer values from binary content."""
-
- cnt = MemoryContent(b'\x4d\x5a\x00\x00' + b'\x50\x45\x00\x00' + 52 * b'\x00' + b'\x04\x00\x00\x00')
-
- rule = '''
-rule IsPE {
-
- condition:
-
- // MZ signature at offset 0 and ...
-
- uint16(0) == 0x5a4d and
-
- // ... PE signature at offset stored in the MZ header at offset 0x3c
-
- uint32(uint32(0x3c)) == 0x00004550
-
-}
-'''
-
- scanner = ContentScanner(rule)
- ctx = scanner.analyze(self._options, cnt)
-
- self.assertTrue(not(ctx is None) and ctx.has_match_for_rule('IsPE'))
-
-
- def testBasicBooleanConditions(self):
- """Evaluate basic boolean conditions."""
-
- cnt = MemoryContent(b'0123')
-
- rule = '''
-rule test {
-
- condition:
- true and false
-
-}
-'''
-
- scanner = ContentScanner(rule)
-
- ctx = scanner.analyze(self._options, cnt)
-
- self.assertTrue(not(ctx is None))
- self.assertFalse(ctx.has_match_for_rule('test'))
-
- rule = '''
+ rule = '''
rule test {
condition:
- true or false
+ %s %s %s
}
-'''
+''' % (op1, kwd, op2)
- scanner = ContentScanner(rule)
+ if expected:
+ self.check_rule_success(rule)
+ else:
+ self.check_rule_failure(rule)
- ctx = scanner.analyze(self._options, cnt)
- self.assertTrue(not(ctx is None) and ctx.has_match_for_rule('test'))
+ def testLogicalOperations(self):
+ """Evaluate some logical operations."""
+ cases = [
+ [ 'true and false', False ],
+ [ 'false or false', False ],
+ [ 'true and true or false', True ],
+ [ 'false or true and false', False ],
+ [ '1 or false', True ],
+ ]
- def testArithmeticOpeations(self):
- """Compute some arithmetic operations."""
+ for cond, expected in cases:
- cnt = MemoryContent(b'0123')
-
- rule = '''
+ rule = '''
rule test {
condition:
- 1 + 4 * 3 + 2 == 15
+ %s
}
-'''
-
- scanner = ContentScanner(rule)
-
- ctx = scanner.analyze(self._options, cnt)
+''' % (cond)
- self.assertTrue(not(ctx is None) and ctx.has_match_for_rule('test'))
+ if expected:
+ self.check_rule_success(rule)
+ else:
+ self.check_rule_failure(rule)
- rule = '''
-rule test {
+ def testArithmeticOperations(self):
+ """Evaluate some arithmetic operations."""
- condition:
- (1 + 4) * 3 + 2 == 17
+ cases = [
-}
-'''
+ # Clever
+ '1 + 2 == 3',
+ '10 + -3 == 7',
+ '-3 + 10 == 7',
+ '-10 - 1 < 0',
+ '-10 - 1 == -11',
+ '(-10 - 1) == -11',
+ '(-1 - -10) == 9',
+ '-2 * -3 == 6',
+ '-2 * 3 == -6',
- scanner = ContentScanner(rule)
+ # Legacy
+ '1 + 4 * 3 + 2 == 15',
+ '(1 + 4) * 3 + 2 == 17',
+ '1 + 4 * (3 + 2) == 21',
+ '(1 + 4) * (3 + 2) == 25',
- ctx = scanner.analyze(self._options, cnt)
+ ]
- self.assertTrue(not(ctx is None) and ctx.has_match_for_rule('test'))
+ for c in cases:
-
- rule = '''
+ rule = '''
rule test {
condition:
- 1 + 4 * (3 + 2) == 21
+ %s
}
-'''
+''' % (c)
- scanner = ContentScanner(rule)
+ self.check_rule_success(rule)
- ctx = scanner.analyze(self._options, cnt)
- self.assertTrue(not(ctx is None) and ctx.has_match_for_rule('test'))
+ def testBasicStringsOperations(self):
+ """Build expressions with basic strings operations."""
+ cases = [
- rule = '''
-rule test {
+ # Clever
+ [ '123---456', 'contains', '---', True ],
+ [ '123---456', 'contains', 'xxx', False ],
+ [ '---123---456', 'startswith', '---', True ],
+ [ '---123---456', 'startswith', 'xxx', False ],
+ [ '123---456---', 'endswith', '---', True ],
+ [ '123---456---', 'endswith', 'xxx', False ],
+ [ 'AAA---BBB', 'icontains', 'aaa', True ],
+ [ 'AAA---BBB', 'icontains', 'xxx', False ],
+ [ 'AAA---BBB', 'istartswith', 'aAa', True ],
+ [ 'AAA---BBB', 'istartswith', 'xxx', False ],
+ [ 'AAA---BBB', 'iendswith', 'bBb', True ],
+ [ 'AAA---BBB', 'iendswith', 'xxx', False ],
+ [ 'AzertY', 'iequals', 'AZERTY', True ],
+ [ 'AzertY', 'iequals', 'AZERTY-', False ],
- condition:
- (1 + 4) * (3 + 2) == 25
-
-}
-'''
+ # Legacy
+ [ '123\t456', 'contains', '\t', True ],
+ [ '123-456', 'startswith', '1', True ],
+ [ '123-456', 'startswith', '1234', False ],
+ [ '123-456', 'endswith', '6', True ],
+ [ '123-456', 'endswith', '3456', False ],
- scanner = ContentScanner(rule)
+ ]
- ctx = scanner.analyze(self._options, cnt)
+ for op1, kwd, op2, expected in cases:
- self.assertTrue(not(ctx is None) and ctx.has_match_for_rule('test'))
-
-
- def testSizeUnits(self):
- """Evaluate size units."""
-
- cnt = MemoryContent(b'0123')
-
-
- rule = '''
-rule test {
-
- condition:
- 1KB == 1024
-
-}
-'''
-
- scanner = ContentScanner(rule)
-
- ctx = scanner.analyze(self._options, cnt)
-
- self.assertTrue(not(ctx is None) and ctx.has_match_for_rule('test'))
-
-
- rule = '''
+ rule = '''
rule test {
condition:
- 2MB == 2 * 1024 * 1024
+ "%s" %s "%s"
}
-'''
+''' % (op1, kwd, op2)
- scanner = ContentScanner(rule)
+ if expected:
+ self.check_rule_success(rule)
+ else:
+ self.check_rule_failure(rule)
- ctx = scanner.analyze(self._options, cnt)
-
- self.assertTrue(not(ctx is None) and ctx.has_match_for_rule('test'))
-
-
- rule = '''
-rule test {
-
- condition:
- 4Kb == (4 * 1024)
-
-}
-'''
-
- scanner = ContentScanner(rule)
-
- ctx = scanner.analyze(self._options, cnt)
-
- self.assertTrue(not(ctx is None) and ctx.has_match_for_rule('test'))
-
-
- rule = '''
-rule test {
-
- condition:
- 1KB <= 1024 and 1024 < 1MB
-
-}
-'''
-
- scanner = ContentScanner(rule)
-
- ctx = scanner.analyze(self._options, cnt)
-
- self.assertTrue(not(ctx is None) and ctx.has_match_for_rule('test'))
+ def testSizeUnits(self):
+ """Evaluate size units."""
- def testNamespace(self):
- """Resolve main functions with the root scan namesapce."""
+ cases = [
+ '1KB == 1024',
+ '2MB == 2 * 1024 * 1024',
+ '4Kb == (4 * 1024)',
+ '1KB <= 1024 and 1024 < 1MB',
+ ]
- cnt = MemoryContent(b'\x01\x02\x03\x04')
+ for c in cases:
- rule = '''
+ rule = '''
rule test {
condition:
- datasize == 4
+ %s
}
-'''
+''' % (c)
- scanner = ContentScanner(rule)
+ self.check_rule_success(rule)
- ctx = scanner.analyze(self._options, cnt)
- self.assertTrue(not(ctx is None) and ctx.has_match_for_rule('test'))
- rule = '''
-rule test {
- condition:
- uint16(0) == 0x201 and uint16(datasize - 2) == 0x0403
-}
-'''
+# TODO : test <haystack> matches <regex>
- scanner = ContentScanner(rule)
- ctx = scanner.analyze(self._options, cnt)
- self.assertTrue(not(ctx is None) and ctx.has_match_for_rule('test'))