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')) |