diff options
Diffstat (limited to 'tests/analysis/scan/grammar.py')
| -rw-r--r-- | tests/analysis/scan/grammar.py | 327 | 
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')) | 
