from common import RostTestClass
from pychrysalide.analysis.contents import MemoryContent


class TestRostScanningBinary(RostTestClass):
    """TestCases for the bytes section syntax (binary)."""

    def testLonelyPatterns(self):
        """Evaluate the most simple patterns."""

        cnt = MemoryContent(b'Abcdef')

        rule = '''
rule test {

   bytes:
      $a = { 41 }

   condition:
      #a == 1 and @a[0] == 0

}
'''

        self.check_rule_success(rule, content=cnt)


        cnt = MemoryContent(b'Abcdef')

        rule = '''
rule test {

   bytes:
      $a = { 62 }

   condition:
      #a == 1 and @a[0] == 1

}
'''

        self.check_rule_success(rule, content=cnt)


        cnt = MemoryContent(b'Abcdef')

        rule = '''
rule test {

   bytes:
      $a = { 66 }

   condition:
      #a == 1 and @a[0] == 5

}
'''

        self.check_rule_success(rule, content=cnt)


        cnt = MemoryContent(b'Abcdef')

        rule = '''
rule test {

   bytes:
      $a = { ?1 }

   condition:
      #a == 1 and @a[0] == 0

}
'''

        self.check_rule_success(rule, content=cnt)


        cnt = MemoryContent(b'Abcdef')

        rule = '''
rule test {

   bytes:
      $a = { ?2 }

   condition:
      #a == 1 and @a[0] == 1

}
'''

        self.check_rule_success(rule, content=cnt)


        cnt = MemoryContent(b'Abcdef')

        rule = '''
rule test {

   bytes:
      $a = { ?6 }

   condition:
      #a == 1 and @a[0] == 5

}
'''

        self.check_rule_success(rule, content=cnt)


    def ___testLonelyPatternsNot(self):
        """Evaluate the most simple patterns (not version)."""

        cnt = MemoryContent(b'Abcdef')

        rule = '''
rule test {

   bytes:
      $a = { ~41 }

   condition:
      #a == 5 and @a[0] == 1

}
'''

        self.check_rule_success(rule, content=cnt)


        cnt = MemoryContent(b'Abcdef')

        rule = '''
rule test {

   bytes:
      $a = { ~62 }

   condition:
      #a == 5 and @a[0] == 0

}
'''

        self.check_rule_success(rule, content=cnt)


        cnt = MemoryContent(b'Abcdef')

        rule = '''
rule test {

   bytes:
      $a = { ~66 }

   condition:
      #a == 5 and @a[4] == 4

}
'''

        self.check_rule_success(rule, content=cnt)


        cnt = MemoryContent(b'Abcdef')

        rule = '''
rule test {

   bytes:
      $a = { ~?1 }

   condition:
      #a == 5 and @a[0] == 1

}
'''

        self.check_rule_success(rule, content=cnt)


        cnt = MemoryContent(b'Abcdef')

        rule = '''
rule test {

   bytes:
      $a = { ~?2 }

   condition:
      #a == 5 and @a[0] == 0

}
'''

        self.check_rule_success(rule, content=cnt)


        cnt = MemoryContent(b'Abcdef')

        rule = '''
rule test {

   bytes:
      $a = { ~?6 }

   condition:
      #a == 5 and @a[4] == 4

}
'''

        self.check_rule_success(rule, content=cnt)


    def testSimpleHexPattern(self):
        """Test a simple hex pattern."""

        cnt = MemoryContent(b'123-Abc-456')

        rule = '''
rule test {

   bytes:
      $a = { 41 62 63 }

   condition:
      #a == 1 and @a[0] == 4

}
'''

        self.check_rule_success(rule, content=cnt)


        cnt = MemoryContent(b'123-Abc-456')

        rule = '''
rule test {

   bytes:
      $a = { 2d 41 62 63 }

   condition:
      #a == 1 and @a[0] == 3

}
'''

        self.check_rule_success(rule, content=cnt)


    def testSimpleMaskedHexPattern(self):
        """Test a simple masked hex pattern."""

        cnt = MemoryContent(b'123-Abc-456')

        rule = '''
rule test {

   bytes:
      $a = { ?1 6? ?3 }

   condition:
      #a == 1 and @a[0] == 4

}
'''

        self.check_rule_success(rule, content=cnt)


    def testHexPatternWithPlainAndMasked(self):
        """Test hex patterns with plain and masked bytes."""

        cnt = MemoryContent(b'123-Abc-456')

        rule = '''
rule test {

   bytes:
      $a = { 41 6? ?3 }

   condition:
      #a == 1 and @a[0] == 4

}
'''

        self.check_rule_success(rule, content=cnt)


        cnt = MemoryContent(b'123-Abc-456')

        rule = '''
rule test {

   bytes:
      $a = { 4? 62 ?3 }

   condition:
      #a == 1 and @a[0] == 4

}
'''

        self.check_rule_success(rule, content=cnt)


        cnt = MemoryContent(b'123-Abc-456')

        rule = '''
rule test {

   bytes:
      $a = { 4? ?2 63 }

   condition:
      #a == 1 and @a[0] == 4

}
'''

        self.check_rule_success(rule, content=cnt)


        cnt = MemoryContent(b'123-Abc-456')

        rule = '''
rule test {

   bytes:
      $a = { 4? ?2 ?3 }

   condition:
      #a == 1 and @a[0] == 4

}
'''

        self.check_rule_success(rule, content=cnt)


        cnt = MemoryContent(b'123-Abc-456')

        rule = '''
rule test {

   bytes:
      $a = { 2d 4? ?2 63 }

   condition:
      #a == 1 and @a[0] == 3

}
'''

        self.check_rule_success(rule, content=cnt)


        cnt = MemoryContent(b'123-Abc-456')

        rule = '''
rule test {

   bytes:
      $a = { 2d 4? 62 ?3 2d }

   condition:
      #a == 1 and @a[0] == 3

}
'''

        self.check_rule_success(rule, content=cnt)


        cnt = MemoryContent(b'123-Abc-456')

        rule = '''
rule test {

   bytes:
      $a = { 2? 41 6? 63 ?d }

   condition:
      #a == 1 and @a[0] == 3

}
'''

        self.check_rule_success(rule, content=cnt)


    def testHexPatternWithPlainAndHoles(self):
        """Test hex patterns with plain bytes and holes."""

        cnt = MemoryContent(b'123-Abc-456')

        rule = '''
rule test {

   bytes:
      $a = { 33 ?? 41 ?? 63 ?? 34 }

   condition:
      #a == 1 and @a[0] == 2

}
'''

        self.check_rule_success(rule, content=cnt)


        cnt = MemoryContent(b'123-Abc-456')

        rule = '''
rule test {

   bytes:
      $a = { ?? 33 ?? 41 ?? 63 ?? 34 ?? }

   condition:
      #a == 1 and @a[0] == 1 and !a[0] == 9

}
'''

        self.check_rule_success(rule, content=cnt)


        cnt = MemoryContent(b'123-Abc-456')

        rule = '''
rule test {

   bytes:
      $a = { ?? 33 [1-5] 63 ?? 34 ?? }

   condition:
      #a == 1 and @a[0] == 1 and !a[0] == 9

}
'''

        self.check_rule_success(rule, content=cnt)


        cnt = MemoryContent(b'123-Abc-456')

        rule = '''
rule test {

   bytes:
      $a = { [3-4] 41 ?? 63 ?? 34 ?? }

   condition:
      #a == 1 and @a[0] == 1 and !a[0] == 9

}
'''

        self.check_rule_success(rule, content=cnt)


        cnt = MemoryContent(b'123-Abc-456')

        rule = '''
rule test {

   bytes:
      $a = { ?? 33 ?? 41 ?? 63 [3-] }

   condition:
      #a == 1 and @a[0] == 1 and !a[0] == 9

}
'''

        self.check_rule_success(rule, content=cnt)


    def testHexPatternWithMaskedAndHoles(self):
        """Test hex patterns with masked bytes and holes."""

        cnt = MemoryContent(b'123-Abc-456')

        rule = '''
rule test {

   bytes:
      $a = { ?3 ?? 4? ?? 6? ?? ?4 }

   condition:
      #a == 1 and @a[0] == 2

}
'''

        self.check_rule_success(rule, content=cnt)


        cnt = MemoryContent(b'123-Abc-456')

        rule = '''
rule test {

   bytes:
      $a = { ?? ?3 ?? 4? ?? 6? ?? ?4 ?? }

   condition:
      #a == 1 and @a[0] == 1 and !a[0] == 9

}
'''

        self.check_rule_success(rule, content=cnt)


        cnt = MemoryContent(b'123-Abc-456')

        rule = '''
rule test {

   bytes:
      $a = { ?? ?3 [1-5] ?3 ?? ?4 ?? }

   condition:
      #a == 1 and @a[0] == 1 and !a[0] == 9

}
'''

        self.check_rule_success(rule, content=cnt)


        cnt = MemoryContent(b'123-Abc-456')

        rule = '''
rule test {

   bytes:
      $a = { [3-4] ?1 ?? ?3 ?? ?4 ?? }

   condition:
      #a == 1 and @a[0] == 1 and !a[0] == 9

}
'''

        self.check_rule_success(rule, content=cnt)


        cnt = MemoryContent(b'123-Abc-456')

        rule = '''
rule test {

   bytes:
      $a = { ?? 3? ?? 4? ?? 6? [3-] }

   condition:
      #a == 1 and @a[0] == 1 and !a[0] == 9

}
'''

        self.check_rule_success(rule, content=cnt)


    def testPipedPlainHexPatterns(self):
        """Look for several patterns at once with piped definition."""

        cnt = MemoryContent(b'123-Abc-456')

        rule = '''
rule test {

   bytes:
      $a = { 41 62 ( 63 | 64 | 65 ) }

   condition:
      #a == 1 and @a[0] == 4 and !a[0] == 3

}
'''

        self.check_rule_success(rule, content=cnt)


        cnt = MemoryContent(b'123-Abc-456')

        rule = '''
rule test {

   bytes:
      $a = { ( 41 | f2 | f3 ) 62 63 }

   condition:
      #a == 1 and @a[0] == 4 and !a[0] == 3

}
'''

        self.check_rule_success(rule, content=cnt)


        cnt = MemoryContent(b'123-Abc-456')

        rule = '''
rule test {

   bytes:
      $a = { 41 ( 61 | 62 | 63 ) 63 }

   condition:
      #a == 1 and @a[0] == 4 and !a[0] == 3

}
'''

        self.check_rule_success(rule, content=cnt)


        cnt = MemoryContent(b'123-Abc-456')

        rule = '''
rule test {

   bytes:
      $a = { ( 41 62 63 | 42 62 63 | 43 62 63 ) }

   condition:
      #a == 1 and @a[0] == 4 and !a[0] == 3

}
'''

        self.check_rule_success(rule, content=cnt)


    def testPipedMaskedHexPatterns(self):
        """Look for several patterns at once with piped and masked definition."""

        cnt = MemoryContent(b'123-Abc-456')

        rule = '''
rule test {

   bytes:
      $a = { 4? 6? ( ?3 | ?4 | ?5 ) }

   condition:
      #a == 1 and @a[0] == 4 and !a[0] == 3

}
'''

        self.check_rule_success(rule, content=cnt)


        cnt = MemoryContent(b'123-Abc-456')

        rule = '''
rule test {

   bytes:
      $a = { ( ?1 | ?2 | ?3 ) 6? 6? }

   condition:
      #a == 1 and @a[0] == 4 and !a[0] == 3

}
'''

        self.check_rule_success(rule, content=cnt)


        cnt = MemoryContent(b'123-Abc-456')

        rule = '''
rule test {

   bytes:
      $a = { 4? ( ?1 | ?2 | ?3 ) 6? }

   condition:
      #a == 1 and @a[0] == 4 and !a[0] == 3

}
'''

        self.check_rule_success(rule, content=cnt)


    def testDuplicatedResultsFiltering(self):
        """Filter duplicated results."""

        cnt = MemoryContent(b'123-Abc-456')

        rule = '''
rule test {

   bytes:
      $a = { ( 4? ?2 ?3 | 4? 6? 6? | ?3 6? ?3 ) }

   condition:
      #a == 1 and @a[0] == 4 and !a[0] == 3

}
'''

        self.check_rule_success(rule, content=cnt)