summaryrefslogtreecommitdiff
path: root/tests/analysis/contents/custom.py
blob: 21539679149f6cce2e83316d042e43589677931c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134

from chrysacase import ChrysalideTestCase
from pychrysalide import SourceEndian
from pychrysalide.analysis import BinContent
from pychrysalide.arch import vmpa


class CustomContent(BinContent):

    def __init__(self, size):
        super(CustomContent, self).__init__()
        self._start = 10
        self._size = size * 8

    def _describe(self, full):
        return 'my_desc' + ('_full' if full else '')

    def _compute_checksum(self, checksum):
        checksum.update(b'xxxxx')

    def _compute_size(self):
        return int(self._size / 8)

    def _compute_start_pos(self):
        return vmpa(self._start, vmpa.VmpaSpecialValue.NO_VIRTUAL)

    def _compute_end_pos(self):
        return vmpa(self._start + self._size, vmpa.VmpaSpecialValue.NO_VIRTUAL)

    def _seek(self, addr, length):
        addr += length
        return True

    def _read_uxxx(self, addr, sizeof):

        assert(addr >= self.start_pos and addr < self.end_pos)

        val = int((addr - self.start_pos).phys / sizeof)

        addr += sizeof

        return val

    def _read_u8(self, addr):
        return self._read_uxxx(addr, 1)

    def _read_u16(self, addr, endian):
        return self._read_uxxx(addr, 2)

    def _read_u32(self, addr, endian):
        return self._read_uxxx(addr, 4)

    def _read_u64(self, addr, endian):
        return self._read_uxxx(addr, 8)

    def _read_uleb128(self, addr):
        return 128

    def _read_leb128(self, addr):
        return -128


class TestCustomContent(ChrysalideTestCase):
    """TestCase for custom implementation of analysis.BinContent."""

    def testBasicImplementations(self):
        """Involve all implemented basic wrappers for a custom content."""

        cnt = CustomContent(1)

        self.assertEqual(cnt._describe(False), 'my_desc')

        self.assertEqual(cnt._describe(True), 'my_desc_full')

        # $ echo -n 'xxxxx' | sha256sum
        # eaf16bc07968e013f3f94ab1342472434a39fc3475f11cf341a6c3965974f8e9  -

        expected = 'eaf16bc07968e013f3f94ab1342472434a39fc3475f11cf341a6c3965974f8e9'

        self.assertEqual(cnt.checksum, expected)

        self.assertEqual(cnt.size, 1)

        addr = cnt.start_pos
        offset = 13

        cnt.seek(addr, offset)

        self.assertEqual(addr.phys, cnt.start_pos.phys + offset)


    def testReadImplementations(self):
        """Involve main implemented read wrappers for a custom content."""

        cnt = CustomContent(8)

        def _run_check_read_implem(fn, args):

            last = None

            pos = cnt.start_pos

            while pos < cnt.end_pos:

                val = fn(pos, *args)

                if not(last is None):
                    self.assertEqual(last + 1, val)
                else:
                    self.assertEqual(val, 0)

                last = val

        checks = [
            [ cnt.read_u8, [] ],
            [ cnt.read_u16, [ SourceEndian.LITTLE ] ],
            [ cnt.read_u32, [ SourceEndian.LITTLE ] ],
            [ cnt.read_u64, [ SourceEndian.LITTLE ] ],
        ]

        for f, a in checks:
            _run_check_read_implem(f, a)


    def testLEB128Implementations(self):
        """Involve [U]LEB128 implemented wrappers for a custom content."""

        cnt = CustomContent(1)

        addr = cnt.start_pos

        self.assertEqual(cnt.read_uleb128(addr), 128)

        self.assertEqual(cnt.read_leb128(addr), -128)