From 304445ae3f7a159be55fa91b95428251ef8a362e Mon Sep 17 00:00:00 2001 From: Cyrille Bagard Date: Wed, 24 Jan 2018 18:50:40 +0100 Subject: Improved the support of some unusual endiannesses. --- ChangeLog | 12 +++ plugins/pychrysalide/arch/vmpa.c | 3 +- src/common/endianness.c | 212 +++++++++++++++++++++++--------------- src/common/endianness.h | 4 +- tests/analysis/contents/endian.py | 129 +++++++++++++++++++++++ 5 files changed, 274 insertions(+), 86 deletions(-) create mode 100644 tests/analysis/contents/endian.py diff --git a/ChangeLog b/ChangeLog index d80a44d..ced1ad5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,17 @@ 18-01-24 Cyrille Bagard + * plugins/pychrysalide/arch/vmpa.c: + Update code. + + * src/common/endianness.c: + * src/common/endianness.h: + Improve the support of some unusual endiannesses. + + * tests/analysis/contents/endian.py: + New entry: extend the test suite with some extra cases. + +18-01-24 Cyrille Bagard + * src/analysis/binary.c: Clean the content of loaded binaries. diff --git a/plugins/pychrysalide/arch/vmpa.c b/plugins/pychrysalide/arch/vmpa.c index 413d67b..41fb1ad 100644 --- a/plugins/pychrysalide/arch/vmpa.c +++ b/plugins/pychrysalide/arch/vmpa.c @@ -554,7 +554,8 @@ static bool py_vmpa_define_constants(PyTypeObject *obj_type) /* TODO : à bouger vers base ? */ result &= PyDict_AddIntMacro(obj_type, SRE_LITTLE); - result &= PyDict_AddIntMacro(obj_type, SRE_MIDDLE); + result &= PyDict_AddIntMacro(obj_type, SRE_LITTLE_WORD); + result &= PyDict_AddIntMacro(obj_type, SRE_BIG_WORD); result &= PyDict_AddIntMacro(obj_type, SRE_BIG); return result; diff --git a/src/common/endianness.c b/src/common/endianness.c index 4dcee22..3aeca00 100755 --- a/src/common/endianness.c +++ b/src/common/endianness.c @@ -24,11 +24,25 @@ #include "endianness.h" +#include #include #include +/** + * Mutualisation des aiguillages... + */ + +#if __BYTE_ORDER != __LITTLE_ENDIAN && __BYTE_ORDER != __BIG_ENDIAN + + /* __PDP_ENDIAN et Cie... */ +# error "Congratulations! Your byte order is not supported!" + +#endif + + + /* ---------------------------------------------------------------------------------- */ /* CONVERSION ENTRE BOUTISMES */ /* ---------------------------------------------------------------------------------- */ @@ -63,18 +77,10 @@ uint16_t swap_u16(const uint16_t *value, SourceEndian endian) result = ((*value >> 0) & 0xff) << 8 | ((*value >> 8) & 0xff) << 0; -#else - -# error "TODO : PDP !" - #endif break; - case SRE_MIDDLE: - /* TODO */ - break; - case SRE_BIG: #if __BYTE_ORDER == __LITTLE_ENDIAN @@ -85,14 +91,13 @@ uint16_t swap_u16(const uint16_t *value, SourceEndian endian) result = *value; -#else - -# error "TODO : PDP !" - #endif break; + default: + assert(false); + break; } @@ -131,18 +136,10 @@ uint32_t swap_u32(const uint32_t *value, SourceEndian endian) result = ((*value >> 0) & 0xff) << 24 | ((*value >> 8) & 0xff) << 16 | ((*value >> 16) & 0xff) << 8 | ((*value >> 24) & 0xff) << 0; -#else - -# error "TODO : PDP !" - #endif break; - case SRE_MIDDLE: - /* TODO */ - break; - case SRE_BIG: #if __BYTE_ORDER == __LITTLE_ENDIAN @@ -154,14 +151,13 @@ uint32_t swap_u32(const uint32_t *value, SourceEndian endian) result = *value; -#else - -# error "TODO : PDP !" - #endif break; + default: + assert(false); + break; } @@ -202,18 +198,10 @@ uint64_t swap_u64(const uint64_t *value, SourceEndian endian) | ((*value >> 32) & 0xff) << 24 | ((*value >> 40) & 0xff) << 16 | ((*value >> 48) & 0xff) << 8 | ((*value >> 56) & 0xff) << 0; -#else - -# error "TODO : PDP !" - #endif break; - case SRE_MIDDLE: - /* TODO */ - break; - case SRE_BIG: #if __BYTE_ORDER == __LITTLE_ENDIAN @@ -227,14 +215,13 @@ uint64_t swap_u64(const uint64_t *value, SourceEndian endian) result = *value; -#else - -# error "TODO : PDP !" - #endif break; + default: + assert(false); + break; } @@ -349,16 +336,36 @@ bool read_u16(uint16_t *target, const bin_t *data, phys_t *pos, phys_t end, Sour *target = data[*pos + 1] | (uint16_t)data[*pos] << 8; -#else +#endif + + break; + + case SRE_LITTLE_WORD: + +#if __BYTE_ORDER == __LITTLE_ENDIAN -# error "TODO : PDP !" + *target = data[*pos] << 8 | (uint16_t)data[*pos + 1]; + +#elif __BYTE_ORDER == __BIG_ENDIAN + + *target = data[*pos + 1] << 8 | (uint16_t)data[*pos]; #endif break; - case SRE_MIDDLE: - /* TODO */ + case SRE_BIG_WORD: + +#if __BYTE_ORDER == __LITTLE_ENDIAN + + *target = data[*pos + 1] << 8 | (uint16_t)data[*pos]; + +#elif __BYTE_ORDER == __BIG_ENDIAN + + *target = data[*pos] << 8 | (uint16_t)data[*pos + 1]; + +#endif + break; case SRE_BIG: @@ -371,14 +378,13 @@ bool read_u16(uint16_t *target, const bin_t *data, phys_t *pos, phys_t end, Sour *target = data[*pos] | (uint16_t)data[*pos + 1] << 8; -#else - -# error "TODO : PDP !" - #endif break; + default: + return false; + break; } @@ -424,16 +430,40 @@ bool read_u32(uint32_t *target, const bin_t *data, phys_t *pos, phys_t end, Sour *target = data[*pos + 3] | (uint32_t)data[*pos + 2] << 8; *target |= data[*pos + 1] << 16 | (uint32_t)data[*pos] << 24; -#else +#endif + + break; + + case SRE_LITTLE_WORD: -# error "TODO : PDP !" +#if __BYTE_ORDER == __LITTLE_ENDIAN + + *target = data[*pos] << 8 | (uint32_t)data[*pos + 1]; + *target |= data[*pos + 2] << 24 | (uint32_t)data[*pos + 3] << 16; + +#elif __BYTE_ORDER == __BIG_ENDIAN + + *target = data[*pos + 3] << 8 | (uint32_t)data[*pos + 2]; + *target |= data[*pos + 1] << 24 | (uint32_t)data[*pos] << 16; #endif break; - case SRE_MIDDLE: - /* TODO */ + case SRE_BIG_WORD: + +#if __BYTE_ORDER == __LITTLE_ENDIAN + + *target = data[*pos + 3] << 8 | (uint32_t)data[*pos + 2]; + *target |= data[*pos + 1] << 24 | (uint32_t)data[*pos] << 16; + +#elif __BYTE_ORDER == __BIG_ENDIAN + + *target = data[*pos] << 8 | (uint32_t)data[*pos + 1]; + *target |= data[*pos + 2] << 24 | (uint32_t)data[*pos + 3] << 16; + +#endif + break; case SRE_BIG: @@ -448,14 +478,13 @@ bool read_u32(uint32_t *target, const bin_t *data, phys_t *pos, phys_t end, Sour *target = data[*pos] | (uint32_t)data[*pos + 1] << 8; *target |= data[*pos + 2] << 16 | (uint32_t)data[*pos + 3] << 24; -#else - -# error "TODO : PDP !" - #endif break; + default: + return false; + break; } @@ -505,16 +534,48 @@ bool read_u64(uint64_t *target, const bin_t *data, phys_t *pos, phys_t end, Sour *target |= (uint64_t)data[*pos + 3] << 32 | (uint64_t)data[*pos + 2] << 40; *target |= (uint64_t)data[*pos + 1] << 48 | (uint64_t)data[*pos] << 56; -#else +#endif + + break; + + case SRE_LITTLE_WORD: + +#if __BYTE_ORDER == __LITTLE_ENDIAN -# error "TODO : PDP !" + *target = (uint64_t)data[*pos] << 8 | (uint64_t)data[*pos + 1]; + *target |= (uint64_t)data[*pos + 2] << 24 | (uint64_t)data[*pos + 3] << 16; + *target |= (uint64_t)data[*pos + 4] << 40 | (uint64_t)data[*pos + 5] << 32; + *target |= (uint64_t)data[*pos + 6] << 56 | (uint64_t)data[*pos + 7] << 48; + +#elif __BYTE_ORDER == __BIG_ENDIAN + + *target = (uint64_t)data[*pos + 7] << 8 | (uint64_t)data[*pos + 6]; + *target |= (uint64_t)data[*pos + 5] << 24 | (uint64_t)data[*pos + 4] << 16; + *target |= (uint64_t)data[*pos + 3] << 40 | (uint64_t)data[*pos + 2] << 32; + *target |= (uint64_t)data[*pos + 1] << 56 | (uint64_t)data[*pos] << 48; #endif break; - case SRE_MIDDLE: - /* TODO */ + case SRE_BIG_WORD: + +#if __BYTE_ORDER == __LITTLE_ENDIAN + + *target = (uint64_t)data[*pos + 7] << 8 | (uint64_t)data[*pos + 6]; + *target |= (uint64_t)data[*pos + 5] << 24 | (uint64_t)data[*pos + 4] << 16; + *target |= (uint64_t)data[*pos + 3] << 40 | (uint64_t)data[*pos + 2] << 32; + *target |= (uint64_t)data[*pos + 1] << 56 | (uint64_t)data[*pos] << 48; + +#elif __BYTE_ORDER == __BIG_ENDIAN + + *target = (uint64_t)data[*pos] << 8| (uint64_t)data[*pos + 1]; + *target |= (uint64_t)data[*pos + 2] << 24 | (uint64_t)data[*pos + 3] << 16; + *target |= (uint64_t)data[*pos + 4] << 40 | (uint64_t)data[*pos + 5] << 32; + *target |= (uint64_t)data[*pos + 6] << 56 | (uint64_t)data[*pos + 7] << 48; + +#endif + break; case SRE_BIG: @@ -533,14 +594,13 @@ bool read_u64(uint64_t *target, const bin_t *data, phys_t *pos, phys_t end, Sour *target |= (uint64_t)data[*pos + 4] << 32 | (uint64_t)data[*pos + 5] << 40; *target |= (uint64_t)data[*pos + 6] << 48 | (uint64_t)data[*pos + 7] << 56; -#else - -# error "TODO : PDP !" - #endif break; + default: + return false; + break; } @@ -589,18 +649,10 @@ bool _write_un(const bin_t *value, size_t size, bin_t *data, off_t *pos, off_t e for (i = 0; i < size; i++, (*pos)++) *(data + *pos) = *(value + size - i - 1); -#else - -# error "TODO : PDP !" - #endif break; - case SRE_MIDDLE: - return false; /* TODO ! */ - break; - case SRE_BIG: #if __BYTE_ORDER == __LITTLE_ENDIAN @@ -613,14 +665,14 @@ bool _write_un(const bin_t *value, size_t size, bin_t *data, off_t *pos, off_t e memcpy(&data[*pos], value, size); (*pos) += size; -#else - -# error "TODO : PDP !" - #endif break; + default: + return false; + break; + } return true; @@ -785,18 +837,10 @@ bool _strtoun(uint8_t n, const char *data, size_t *pos, size_t end, SourceEndian *target64 |= ((uint64_t)tmp) << (8 * (n - 1 - i)); -#else - -# error "TODO : PDP !" - #endif break; - case SRE_MIDDLE: - /* TODO */ - break; - case SRE_BIG: #if __BYTE_ORDER == __LITTLE_ENDIAN @@ -807,14 +851,14 @@ bool _strtoun(uint8_t n, const char *data, size_t *pos, size_t end, SourceEndian *target64 |= ((uint64_t)tmp) << (8 * i); -#else - -# error "TODO : PDP !" - #endif break; + default: + return false; + break; + } } diff --git a/src/common/endianness.h b/src/common/endianness.h index 5ceb2ee..625b7fd 100755 --- a/src/common/endianness.h +++ b/src/common/endianness.h @@ -37,12 +37,14 @@ typedef enum _SourceEndian { SRE_LITTLE, /* Petits boutistes */ - SRE_MIDDLE, /* Moyens boutistes */ + SRE_LITTLE_WORD, /* Moyens, façon Honeywell */ + SRE_BIG_WORD, /* Moyens, façon PDP-11 */ SRE_BIG /* Gros boutistes */ } SourceEndian; + /* --------------------------- CONVERSION ENTRE BOUTISMES --------------------------- */ diff --git a/tests/analysis/contents/endian.py b/tests/analysis/contents/endian.py new file mode 100644 index 0000000..209600a --- /dev/null +++ b/tests/analysis/contents/endian.py @@ -0,0 +1,129 @@ +#!/usr/bin/python3-dbg +# -*- coding: utf-8 -*- + + +# Tests minimalistes pour valider le boutisme des accès mémoire. + + +from chrysacase import ChrysalideTestCase +from pychrysalide.analysis.contents import FileContent, RestrictedContent +from pychrysalide.arch import vmpa +import tempfile + + +class TestEndianness(ChrysalideTestCase): + """TestCase for analysis.BinContent.""" + + @classmethod + def setUpClass(cls): + + super(TestEndianness, cls).setUpClass() + + cls._out = tempfile.NamedTemporaryFile() + + cls._out.write(b'\x01\x02\x03\x04') + cls._out.write(b'\x05\x06\x07\x08') + cls._out.write(b'\x11\x12\x13\x14') + cls._out.write(b'\x15\x16\x17\x18') + cls._out.write(b'\x21\x22\x23\x24') + cls._out.write(b'\x25\x26\x27\x28') + cls._out.write(b'\x31\x32\x33\x34') + cls._out.write(b'\x35\x36\x37\x38') + + cls._out.flush() + + cls.log('Using temporary file "%s"' % cls._out.name) + + + @classmethod + def tearDownClass(cls): + + super(TestEndianness, cls).tearDownClass() + + cls.log('Delete file "%s"' % cls._out.name) + + cls._out.close() + + + def testMiddleEndianness(self): + """Test some old endianness.""" + + fcnt = FileContent(self._out.name) + + # 16 bits + + start = vmpa(12, vmpa.VMPA_NO_VIRTUAL) + + val = fcnt.read_u16(start, vmpa.SRE_LITTLE_WORD) + self.assertEqual(val, 0x1516) + + start = vmpa(12, vmpa.VMPA_NO_VIRTUAL) + + val = fcnt.read_u16(start, vmpa.SRE_BIG_WORD) + self.assertEqual(val, 0x1615) + + # 32 bits + + start = vmpa(12, vmpa.VMPA_NO_VIRTUAL) + + val = fcnt.read_u32(start, vmpa.SRE_LITTLE_WORD) + self.assertEqual(val, 0x17181516) + + start = vmpa(12, vmpa.VMPA_NO_VIRTUAL) + + val = fcnt.read_u32(start, vmpa.SRE_BIG_WORD) + self.assertEqual(val, 0x16151817) + + # 64 bits + + start = vmpa(0, vmpa.VMPA_NO_VIRTUAL) + + val = fcnt.read_u64(start, vmpa.SRE_LITTLE_WORD) + self.assertEqual(val, 0x0708050603040102) + + start = vmpa(0, vmpa.VMPA_NO_VIRTUAL) + + val = fcnt.read_u64(start, vmpa.SRE_BIG_WORD) + self.assertEqual(val, 0x0201040306050807) + + + def testEndianness(self): + """Test usual endianness.""" + + fcnt = FileContent(self._out.name) + + # 16 bits + + start = vmpa(12, vmpa.VMPA_NO_VIRTUAL) + + val = fcnt.read_u16(start, vmpa.SRE_LITTLE) + self.assertEqual(val, 0x1615) + + start = vmpa(12, vmpa.VMPA_NO_VIRTUAL) + + val = fcnt.read_u16(start, vmpa.SRE_BIG) + self.assertEqual(val, 0x1516) + + # 32 bits + + start = vmpa(12, vmpa.VMPA_NO_VIRTUAL) + + val = fcnt.read_u32(start, vmpa.SRE_LITTLE) + self.assertEqual(val, 0x18171615) + + start = vmpa(12, vmpa.VMPA_NO_VIRTUAL) + + val = fcnt.read_u32(start, vmpa.SRE_BIG) + self.assertEqual(val, 0x15161718) + + # 64 bits + + start = vmpa(0, vmpa.VMPA_NO_VIRTUAL) + + val = fcnt.read_u64(start, vmpa.SRE_LITTLE) + self.assertEqual(val, 0x0807060504030201) + + start = vmpa(0, vmpa.VMPA_NO_VIRTUAL) + + val = fcnt.read_u64(start, vmpa.SRE_BIG) + self.assertEqual(val, 0x0102030405060708) -- cgit v0.11.2-87-g4458