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 class TestRostGrammar(ChrysalideTestCase): """TestCase for analysis.scan.ScanExpression.""" @classmethod def setUpClass(cls): super(TestRostGrammar, cls).setUpClass() cls._options = ScanOptions() cls._options.backend_for_data = AcismBackend def testComments(self): """Ensure comments do not bother rule definitions.""" cnt = MemoryContent(b'no_real_content') 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 test { condition: true or false } ''' scanner = ContentScanner(rule) ctx = scanner.analyze(self._options, cnt) self.assertTrue(not(ctx is None) and ctx.has_match_for_rule('test')) def testArithmeticOpeations(self): """Compute some arithmetic operations.""" cnt = MemoryContent(b'0123') rule = ''' rule test { condition: 1 + 4 * 3 + 2 == 15 } ''' 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: (1 + 4) * 3 + 2 == 17 } ''' 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: 1 + 4 * (3 + 2) == 21 } ''' 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: (1 + 4) * (3 + 2) == 25 } ''' 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.""" 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 test { condition: 2MB == 2 * 1024 * 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: 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 testNamespace(self): """Resolve main functions with the root scan namesapce.""" cnt = MemoryContent(b'\x01\x02\x03\x04') rule = ''' rule test { condition: datasize == 4 } ''' 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: uint16(0) == 0x201 and uint16(datasize - 2) == 0x0403 } ''' scanner = ContentScanner(rule) ctx = scanner.analyze(self._options, cnt) self.assertTrue(not(ctx is None) and ctx.has_match_for_rule('test'))