From 7591f34e7e9d5dd0f20d242394628ab4bcd0a430 Mon Sep 17 00:00:00 2001 From: Cyrille Bagard Date: Sun, 12 Nov 2017 21:49:22 +0100 Subject: Improved the type of data read from loaded contents. --- ChangeLog | 8 ++++ plugins/pychrysa/analysis/content.c | 62 ++++++++++++++++++++++-- tests/analysis/contents/restricted.py | 88 +++++++++++++++++++++++++++++++---- 3 files changed, 144 insertions(+), 14 deletions(-) diff --git a/ChangeLog b/ChangeLog index aa699e0..3424bbf 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,13 @@ 17-11-12 Cyrille Bagard + * plugins/pychrysa/analysis/content.c: + Improve the type of data read from loaded contents. + + * tests/analysis/contents/restricted.py: + Update and extend the test suite. + +17-11-12 Cyrille Bagard + * plugins/pychrysa/analysis/binary.c: Update the Python API. diff --git a/plugins/pychrysa/analysis/content.c b/plugins/pychrysa/analysis/content.c index 5565129..95f88f6 100644 --- a/plugins/pychrysa/analysis/content.c +++ b/plugins/pychrysa/analysis/content.c @@ -46,6 +46,9 @@ static PyObject *py_binary_content_get_checksum(PyObject *, PyObject *); /* Détermine le nombre d'octets lisibles. */ static PyObject *py_binary_content_compute_size(PyObject *, PyObject *); +/* Fournit une portion des données représentées. */ +static PyObject *py_binary_content_read_raw(PyObject *, PyObject *); + /* Lit un nombre non signé sur un octet. */ static PyObject *py_binary_content_read_u8(PyObject *, PyObject *); @@ -125,6 +128,52 @@ static PyObject *py_binary_content_compute_size(PyObject *self, PyObject *args) * Paramètres : self = contenu binaire à manipuler. * * args = non utilisé ici. * * * +* Description : Fournit une portion des données représentées. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_binary_content_read_raw(PyObject *self, PyObject *args) +{ + PyObject *result; /* Instance à retourner */ + GBinContent *content; /* Version GLib du format */ + PyObject *addr_obj; /* Objet pour une position */ + vmpa2t *addr; /* Position interne associée */ + unsigned long long length; /* Quantité de données à lire */ + int ret; /* Bilan de lecture des args. */ + const bin_t *val; /* Valeur lue à faire suivre */ + + content = G_BIN_CONTENT(pygobject_get(self)); + assert(content != NULL); + + ret = PyArg_ParseTuple(args, "OK", &addr_obj, &length); + if (!ret) return NULL; + + addr = get_internal_vmpa(addr_obj); + assert(addr != NULL); + + val = g_binary_content_get_raw_access(content, addr, length); + if (val == NULL) + { + PyErr_SetString(PyExc_Exception, _("Invalid read access.")); + return NULL; + } + + result = PyBytes_FromStringAndSize((char *)val, length); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = contenu binaire à manipuler. * +* args = non utilisé ici. * +* * * Description : Lit un nombre non signé sur un octet. * * * * Retour : Bilan de l'opération. * @@ -159,7 +208,7 @@ static PyObject *py_binary_content_read_u8(PyObject *self, PyObject *args) return NULL; } - result = PyBytes_FromStringAndSize((char *)&val, 1); + result = PyLong_FromUnsignedLong(val); return result; @@ -206,7 +255,7 @@ static PyObject *py_binary_content_read_u16(PyObject *self, PyObject *args) return NULL; } - result = PyBytes_FromStringAndSize((char *)&val, 2); + result = PyLong_FromUnsignedLong(val); return result; @@ -253,7 +302,7 @@ static PyObject *py_binary_content_read_u32(PyObject *self, PyObject *args) return NULL; } - result = PyBytes_FromStringAndSize((char *)&val, 4); + result = PyLong_FromUnsignedLong(val); return result; @@ -299,7 +348,7 @@ static PyObject *py_binary_content_read_u64(PyObject *self, PyObject *args) return NULL; } - result = PyBytes_FromStringAndSize((char *)&val, 8); + result = PyLong_FromUnsignedLongLong(val); return result; @@ -332,6 +381,11 @@ PyTypeObject *get_python_binary_content_type(void) "compute_size($self, /)\n--\n\nCompute the quantity of readable bytes." }, { + "read_raw", py_binary_content_read_raw, + METH_VARARGS, + "read_raw($self, addr, length, /)\n--\n\nRead bytes from a given position." + }, + { "read_u8", py_binary_content_read_u8, METH_VARARGS, "read_u8($self, addr, /)\n--\n\nRead an unsigned byte from a given position." diff --git a/tests/analysis/contents/restricted.py b/tests/analysis/contents/restricted.py index e8d3e07..6484299 100644 --- a/tests/analysis/contents/restricted.py +++ b/tests/analysis/contents/restricted.py @@ -58,15 +58,39 @@ class TestRestrictedContent(ChrysalideTestCase): self.assertIsNotNone(rcnt) val = rcnt.read_u8(start) - self.assertEqual(val, b'\x15') + self.assertEqual(val, 0x15) val = rcnt.read_u8(start) - self.assertEqual(val, b'\x16') + self.assertEqual(val, 0x16) val = rcnt.read_u16(start, vmpa.SRE_LITTLE) - self.assertEqual(val, b'\x17\x18') + self.assertEqual(val, 0x1817) val = rcnt.read_u32(start, vmpa.SRE_LITTLE) + self.assertEqual(val, 0x24232221) + + + def testReadRawAccess(self): + """Check valid raw accesses to restricted content.""" + + fcnt = FileContent(self._out.name) + + start = vmpa(12, vmpa.VMPA_NO_VIRTUAL) + covered = mrange(start, 12) # 0x15 ... 0x28 + + rcnt = RestrictedContent(fcnt, covered) + self.assertIsNotNone(rcnt) + + val = rcnt.read_raw(start, 1) + self.assertEqual(val, b'\x15') + + val = rcnt.read_raw(start, 1) + self.assertEqual(val, b'\x16') + + val = rcnt.read_raw(start, 2) + self.assertEqual(val, b'\x17\x18') + + val = rcnt.read_raw(start, 4) self.assertEqual(val, b'\x21\x22\x23\x24') @@ -83,34 +107,78 @@ class TestRestrictedContent(ChrysalideTestCase): start = vmpa(12, vmpa.VMPA_NO_VIRTUAL) val = rcnt.read_u8(start) - self.assertEqual(val, b'\x15') + self.assertEqual(val, 0x15) start = vmpa(12, vmpa.VMPA_NO_VIRTUAL) val = rcnt.read_u16(start, vmpa.SRE_LITTLE) - self.assertEqual(val, b'\x15\x16') + self.assertEqual(val, 0x1615) start = vmpa(12, vmpa.VMPA_NO_VIRTUAL) val = rcnt.read_u32(start, vmpa.SRE_LITTLE) - self.assertEqual(val, b'\x15\x16\x17\x18') + self.assertEqual(val, 0x18171615) start = vmpa(12, vmpa.VMPA_NO_VIRTUAL) val = rcnt.read_u64(start, vmpa.SRE_LITTLE) - self.assertEqual(val, b'\x15\x16\x17\x18\x21\x22\x23\x24') + self.assertEqual(val, 0x2423222118171615) start = vmpa(23, vmpa.VMPA_NO_VIRTUAL) val = rcnt.read_u8(start) - self.assertEqual(val, b'\x28') + self.assertEqual(val, 0x28) start = vmpa(22, vmpa.VMPA_NO_VIRTUAL) val = rcnt.read_u16(start, vmpa.SRE_LITTLE) - self.assertEqual(val, b'\x27\x28') + self.assertEqual(val, 0x2827) start = vmpa(20, vmpa.VMPA_NO_VIRTUAL) val = rcnt.read_u32(start, vmpa.SRE_LITTLE) - self.assertEqual(val, b'\x25\x26\x27\x28') + self.assertEqual(val, 0x28272625) start = vmpa(16, vmpa.VMPA_NO_VIRTUAL) val = rcnt.read_u64(start, vmpa.SRE_LITTLE) + self.assertEqual(val, 0x2827262524232221) + + + def testBorderLineRawAccess(self): + """Check valid border line raw accesses to restricted content.""" + + fcnt = FileContent(self._out.name) + + start = vmpa(12, vmpa.VMPA_NO_VIRTUAL) + covered = mrange(start, 12) # 0x15 ... 0x28 + + rcnt = RestrictedContent(fcnt, covered) + self.assertIsNotNone(rcnt) + + start = vmpa(12, vmpa.VMPA_NO_VIRTUAL) + val = rcnt.read_raw(start, 1) + self.assertEqual(val, b'\x15') + + start = vmpa(12, vmpa.VMPA_NO_VIRTUAL) + val = rcnt.read_raw(start, 2) + self.assertEqual(val, b'\x15\x16') + + start = vmpa(12, vmpa.VMPA_NO_VIRTUAL) + val = rcnt.read_raw(start, 4) + self.assertEqual(val, b'\x15\x16\x17\x18') + + start = vmpa(12, vmpa.VMPA_NO_VIRTUAL) + val = rcnt.read_raw(start, 8) + self.assertEqual(val, b'\x15\x16\x17\x18\x21\x22\x23\x24') + + start = vmpa(23, vmpa.VMPA_NO_VIRTUAL) + val = rcnt.read_raw(start, 1) + self.assertEqual(val, b'\x28') + + start = vmpa(22, vmpa.VMPA_NO_VIRTUAL) + val = rcnt.read_raw(start, 2) + self.assertEqual(val, b'\x27\x28') + + start = vmpa(20, vmpa.VMPA_NO_VIRTUAL) + val = rcnt.read_raw(start, 4) + self.assertEqual(val, b'\x25\x26\x27\x28') + + start = vmpa(16, vmpa.VMPA_NO_VIRTUAL) + val = rcnt.read_raw(start, 8) self.assertEqual(val, b'\x21\x22\x23\x24\x25\x26\x27\x28') -- cgit v0.11.2-87-g4458