From 72ed953e6bf4c93057aadac5bb49d7633658273b Mon Sep 17 00:00:00 2001 From: Cyrille Bagard Date: Wed, 13 Nov 2019 00:10:19 +0100 Subject: Created a small Python GUI plugin to inspect data. --- configure.ac | 1 + plugins/python/liveconv/Makefile.am | 10 + plugins/python/liveconv/__init__.py | 2 + plugins/python/liveconv/converters.py | 160 +++++++++ plugins/python/liveconv/panel.py | 80 +++++ plugins/python/liveconv/panel.ui | 622 ++++++++++++++++++++++++++++++++++ plugins/python/liveconv/plugin.py | 29 ++ 7 files changed, 904 insertions(+) create mode 100644 plugins/python/liveconv/Makefile.am create mode 100644 plugins/python/liveconv/__init__.py create mode 100644 plugins/python/liveconv/converters.py create mode 100644 plugins/python/liveconv/panel.py create mode 100644 plugins/python/liveconv/panel.ui create mode 100644 plugins/python/liveconv/plugin.py diff --git a/configure.ac b/configure.ac index e0e3042..3991e72 100644 --- a/configure.ac +++ b/configure.ac @@ -461,6 +461,7 @@ AC_CONFIG_FILES([Makefile plugins/python/abackup/Makefile plugins/python/apkfiles/Makefile plugins/python/checksec/Makefile + plugins/python/liveconv/Makefile plugins/readdex/Makefile plugins/readelf/Makefile plugins/readmc/Makefile diff --git a/plugins/python/liveconv/Makefile.am b/plugins/python/liveconv/Makefile.am new file mode 100644 index 0000000..bd04b81 --- /dev/null +++ b/plugins/python/liveconv/Makefile.am @@ -0,0 +1,10 @@ + +liveconvdir = $(pluginsdatadir)/python/liveconv + +liveconv_DATA = \ + __init__.py \ + converters.py \ + panel.py \ + plugin.py + +EXTRA_DIST = $(liveconv_DATA) diff --git a/plugins/python/liveconv/__init__.py b/plugins/python/liveconv/__init__.py new file mode 100644 index 0000000..541efdd --- /dev/null +++ b/plugins/python/liveconv/__init__.py @@ -0,0 +1,2 @@ + +from liveconv.plugin import LiveConverter as AutoLoad diff --git a/plugins/python/liveconv/converters.py b/plugins/python/liveconv/converters.py new file mode 100644 index 0000000..ef35f59 --- /dev/null +++ b/plugins/python/liveconv/converters.py @@ -0,0 +1,160 @@ + +from datetime import datetime, timedelta +from pychrysalide.arch import vmpa +import string +import struct + + +def data_to_number(content, addr, order, fmt): + """Convert to a number, if possible.""" + + size = struct.calcsize(order + fmt) + + data = content.read_raw(addr, size) + + value = struct.unpack(order + fmt, data)[0] + + return str(value) + + +def data_to_time(content, addr, order, fmt): + """Convert to a number, if possible.""" + + size = struct.calcsize(order + fmt) + + data = content.read_raw(addr, size) + + value = struct.unpack(order + fmt, data)[0] + + return str(datetime(1970, 1, 1) + timedelta(seconds=value)) + + +# Cf. FILETIME structure +# https://docs.microsoft.com/fr-fr/windows/win32/api/minwinbase/ns-minwinbase-filetime + +def data_to_filetime(content, addr, order): + """Convert to a Windows FILETIME, if possible.""" + + data = content.read_raw(addr, 8) + + value = struct.unpack(order + 'Q', data)[0] + + us = value / 10. + + return str(datetime(1601, 1, 1) + timedelta(microseconds=us)) + + +# Cf. DosDateTimeToFileTime() +# https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-dosdatetimetofiletime + +def data_to_dos_time(content, addr, order): + """Convert to a MS-DOS time, if possible.""" + + data = content.read_raw(addr, 2) + + value = struct.unpack(order + 'H', data)[0] + + seconds = (value & 0x1f) * 2 + minutes = (value & 0x7e0) >> 5 + hours = (value & 0xf800) >> 11 + + return '%02u:%02u:%02u' % (hours, minutes, seconds) + +def data_to_dos_date(content, addr, order): + """Convert to a MS-DOS date, if possible.""" + + data = content.read_raw(addr, 2) + + value = struct.unpack(order + 'H', data)[0] + + day = (value & 0x1f) + month = (value & 0x1e0) >> 5 + year = ((value & 0xfe00) >> 9) + 1980 + + return '%u/%u/%u' % (month, day, year) + + +def data_to_char(content, addr, order): + """Convert to a character, if possible.""" + + data = content.read_raw(addr, 1) + + value = struct.unpack(order + 'c', data)[0] + + ch = chr(value[0]) + + return ch if ch in string.printable else '-' + + +def data_to_ansi(content, addr, order): + """Convert to an ANSI string, if possible.""" + + result = None + + while True: + + try: + + data = content.read_raw(addr, 1) + + value = struct.unpack(order + 'c', data)[0] + + ch = chr(value[0]) + + if not(ch in string.printable): + break + + if result: + result += ch + else: + result = ch + + except: + pass + + return result if result else '-' + + +def _data_to_utf(content, addr, utf): + """Convert to an UTF-X string, if possible.""" + + result = None + + length = 0 + + while True: + + try: + + start = vmpa(addr.phys, 0) + data = content.read_raw(start, length + 1) + + result = data.decode(utf) + + length += 1 + + except Exception as e: + break + + if length > 0: + + data = content.read_raw(addr, length) + + result = data.decode('utf-8') + + else: + result = '-' + + return result + + +def data_to_utf8(content, addr, order): + """Convert to an UTF-8 string, if possible.""" + + return _data_to_utf(content, addr, 'utf-8') + + +def data_to_utf16(content, addr, order): + """Convert to an UTF-16 string, if possible.""" + + return _data_to_utf(content, addr, 'utf-16') diff --git a/plugins/python/liveconv/panel.py b/plugins/python/liveconv/panel.py new file mode 100644 index 0000000..614940f --- /dev/null +++ b/plugins/python/liveconv/panel.py @@ -0,0 +1,80 @@ + +import os +from gi.repository import Gtk +from pychrysalide.analysis import LoadedBinary +from pychrysalide.gui import core +from pychrysalide.gui import PanelItem + +from .converters import * + + +class ConvPanel(PanelItem): + + def __init__(self): + """Initialize the GUI panel.""" + + directory = os.path.dirname(os.path.realpath(__file__)) + + self._builder = Gtk.Builder() + self._builder.add_from_file(os.path.join(directory, 'panel.ui')) + + params = { + + 'name' : 'Converter', + 'widget' : self._builder.get_object('content'), + + 'personality' : PanelItem.PIP_SINGLETON, + 'lname' : 'Data live converter', + 'dock' : True, + 'path' : 'MES' + + } + + super(ConvPanel, self).__init__(**params) + + self._conversions = { + + 'int8': lambda c, a, o: data_to_number(c, a, o, 'b'), + 'uint8': lambda c, a, o: data_to_number(c, a, o, 'B'), + 'int16': lambda c, a, o: data_to_number(c, a, o, 'h'), + 'uint16': lambda c, a, o: data_to_number(c, a, o, 'H'), + 'int32': lambda c, a, o: data_to_number(c, a, o, 'l'), + 'uint32': lambda c, a, o: data_to_number(c, a, o, 'L'), + 'int64': lambda c, a, o: data_to_number(c, a, o, 'q'), + 'uint64': lambda c, a, o: data_to_number(c, a, o, 'Q'), + 'half_float': lambda c, a, o: data_to_number(c, a, o, 'e'), + 'float': lambda c, a, o: data_to_number(c, a, o, 'f'), + 'double': lambda c, a, o: data_to_number(c, a, o, 'd'), + + 'time': lambda c, a, o: data_to_time(c, a, o, 'L'), + 'time64': lambda c, a, o: data_to_time(c, a, o, 'Q'), + 'filetime': data_to_filetime, + 'dostime': data_to_dos_time, + 'dosdate': data_to_dos_date, + + 'char': data_to_char, + 'ansi': data_to_ansi, + 'utf8': data_to_utf8, + 'utf16': data_to_utf16, + + } + + self._order = '@' + + + def _track_cursor(self, source, cursor): + """Track moves from the current cursor.""" + + loaded = core.get_current_content() + assert(loaded) + + for kind, func in self._conversions.items(): + + label = self._builder.get_object('%s_value' % kind) + + try: + addr = cursor.retrieve() + label.set_text(func(loaded.content, addr, self._order)) + + except Exception as e: + label.set_text('-') diff --git a/plugins/python/liveconv/panel.ui b/plugins/python/liveconv/panel.ui new file mode 100644 index 0000000..6c3d05a --- /dev/null +++ b/plugins/python/liveconv/panel.ui @@ -0,0 +1,622 @@ + + + + + + True + True + in + + + True + False + + + True + False + vertical + + + True + True + 8 + 8 + 8 + 8 + True + + + True + False + 8 + 8 + 4 + 8 + + + True + False + int8_t: + 0 + + + 0 + 0 + + + + + True + False + label + True + 0 + + + 1 + 0 + + + + + True + False + uint8_t: + 0 + + + 0 + 1 + + + + + True + False + label + True + 0 + + + 1 + 1 + + + + + True + False + int16_t: + 0 + + + 0 + 2 + + + + + True + False + label + True + 0 + + + 1 + 2 + + + + + True + False + uint16_t: + 0 + + + 0 + 3 + + + + + True + False + label + True + 0 + + + 1 + 3 + + + + + True + False + int32_t: + 0 + + + 0 + 4 + + + + + True + False + label + True + 0 + + + 1 + 4 + + + + + True + False + uint32_t: + 0 + + + 0 + 5 + + + + + True + False + label + True + 0 + + + 1 + 5 + + + + + True + False + int64_t: + 0 + + + 0 + 6 + + + + + True + False + label + True + 0 + + + 1 + 6 + + + + + True + False + uint64_t: + 0 + + + 0 + 7 + + + + + True + False + label + True + 0 + + + 1 + 7 + + + + + True + False + half-precision float: + 0 + + + 0 + 8 + + + + + True + False + label + True + 0 + + + 1 + 8 + + + + + True + False + float: + 0 + + + 0 + 9 + + + + + True + False + label + True + 0 + + + 1 + 9 + + + + + True + False + double: + 0 + + + 0 + 10 + + + + + True + False + label + True + 0 + + + 1 + 10 + + + + + + + True + False + Numbers + + + + + False + True + 0 + + + + + True + True + 8 + 8 + 8 + 8 + True + + + True + False + 8 + 8 + 4 + 8 + + + True + False + time_t: + 0 + + + 0 + 0 + + + + + True + False + label + True + 0 + + + 1 + 0 + + + + + True + False + time64_t: + 0 + + + 0 + 1 + + + + + True + False + label + True + 0 + + + 1 + 1 + + + + + True + False + FILETIME: + 0 + + + 0 + 2 + + + + + True + False + label + True + 0 + + + 1 + 2 + + + + + True + False + MS-DOS time: + 0 + + + 0 + 3 + + + + + True + False + label + True + 0 + + + 1 + 3 + + + + + True + False + MS-DOS date: + 0 + + + 0 + 4 + + + + + True + False + label + True + 0 + + + 1 + 4 + + + + + + + True + False + Timestamps + + + + + False + True + 1 + + + + + True + True + 8 + 8 + 8 + 8 + True + + + True + False + 8 + 8 + 4 + 8 + + + True + False + char: + 0 + + + 0 + 0 + + + + + True + False + label + True + 0 + + + 1 + 0 + + + + + True + False + ANSI: + 0 + + + 0 + 1 + + + + + True + False + label + True + 0 + + + 1 + 1 + + + + + True + False + UTF-8: + 0 + + + 0 + 2 + + + + + True + False + label + True + 0 + + + 1 + 2 + + + + + True + False + UTF-16: + 0 + + + 0 + 3 + + + + + True + False + label + True + 0 + + + 1 + 3 + + + + + + + True + False + Strings + + + + + False + True + 2 + + + + + + + + diff --git a/plugins/python/liveconv/plugin.py b/plugins/python/liveconv/plugin.py new file mode 100644 index 0000000..a1a182e --- /dev/null +++ b/plugins/python/liveconv/plugin.py @@ -0,0 +1,29 @@ + +from pychrysalide import PluginModule +from pychrysalide.gui import core + +from .panel import ConvPanel + + +class LiveConverter(PluginModule): + """Convert raw values into interpreted values.""" + + + def __init__(self): + """Initialize the plugin for Chrysalide.""" + + interface = { + + 'name' : 'LiveConverter', + 'desc' : 'Convert raw values into interprered values', + 'version' : '0.1', + + 'actions' : ( ) + + } + + super(LiveConverter, self).__init__(**interface) + + p = ConvPanel() + + core.register_panel(p) -- cgit v0.11.2-87-g4458