Изучение протокола обмена данными в диагностическом ПО с помощью ILdasm
В статье описывается случай изучения протокола передачи данных по IL-коду диагностического ПО,
написанного под .NET Framework. Производитель оборудования и ПО здесь указываться не будет,
как и не будет раскрыто каких-либо секретов. Усложнить чтение IL-кода производитель мог, но это не было сделано.
Знание протокола дает возможность создания своего ПО с нужным функционалом,
а также создать приложение для смартфона, поскольку подключение к оборудованию происходит по Bluetooth.
Рисунок 1 - Связь хоста и диагностиуемой системы
Оборудование (система накопления электроэнергии из 160 ячеек типа LiFeYPO4) имеет в своем составе блок,
который формирует пакеты данных с информацией о напряжении и температуре всех ячеек
и отправляет их с периодом около 3 секунд на верхний уровень по RS-485 и параллельно по Bluetooth на хост с диагностическим ПО.
Задача автора состоит в определении алгоритма кодирования этих пакетов.
Для получения и сохранения передаваемых данных использован терминал HTerm,
подключенный к оборудованию вместо диагностической программы.
Подключение производится как к виртуальному COM-порту, который был присвоен диагностируемому устройству при сопряжении по Bluetooth.
После подключения к системе, она по-умолчанию находится в режиме периодической трансляции пакетов данных
и не требует каких-либо запросов от хоста, поэтому данные остается только принять.
Рисунок 2 - Один из пакетов данных (1280 байт), получаемый от диагностируемой системы каждые 3 секунды
В данном случае достаточно одного пакета данных, поэтому, получив пакет данных (рис. 2),
не дожидаемся поступления следующего через 3 секунды, а отключаемся от порта и сохраняем полученные данные файл (в HTerm формат "RAW").
В полученных данных наблюдается повторение определенной последовательности каждые 8 байт.
Поэтому для удобства, в HTerm установлен перенос строки через каждые 8 байт (Newline every...characters).
После разбиения, число таких строк получилось равным числу ячеек (160), что может указывать на то,
что одна строка содержит информацию об одной ячейке.
Рисунок 3 - Вид данных с переносом строк через каждые 8 байт
Чтобы понять, как должна выглядеть отображаемая информация из сохраненного пакета данных,
передадим его с помощью HTerm диагностической программе, как данные от оборудования.
Для связи двух программ между собой по COM-портам, использован драйвер com0com,
с помощью которого создана связка из двух виртуальных COM-портов.
К одному порту (COM101) подключается HTerm, а ко второму (COM100) диагностическая программа.
Из терминала отправляем ранее сохраненный файл (кнопка Send File), результат на рисунке 4.
Рисунок 4 - Информация, отображаемая в диагностическом ПО после получения пакета данных
Рисунок 5 - Выборка из 3 строк соответствия отображаемой информации и принимаемых данных
Далее можно приступить к поиску алгоритма кодирования в коде программы.
Исходный код автору недоступен, но, ПО написано на базе .NET Framework,
что позволяет получить код программы уже не на ассемблере,
а на более высокоуровневом языке IL (Intermediate language), что упрощает изучение алгоритма.
Для дизассемблирования используется утилита ILdasm. Ниже представлено дерево
объектов, полученное после загрузки сборки в ILdasm.
Рисунок 6 - Дерево объектов в ILdasm
Поскольку разработчики специально не занимались запутыванием,
имена (объектов, методов, переменных и т.д.) сохранились в исходном виде,
что значительно упрощает задачу.
После непродолжительного анализа полученного кода, найдены искомые участки.
Один массив байтов uint8 PacketData[] должен содержать одну строку полученных байтов с информацией о ячейках.
Рисунок 7 - Отдельные байты из PacketData[] по таймеру передаются в функцию send_data_from_bat()
В обработчике события таймера (судя по дефолтному названию функции)
timerData_Tick() на участке с IL_0175 по IL_018c загружаются в стек байты 3, 4, 5 из PacketData[]
и передаются в send_data_from_bat(). Названия аргументов последней функции также дают подсказку: NbCMM, ValUBat, ValTmpBat.
Далее начат проект на C# с пробными пакетами и переменными, именованными в соответствии IL-кодом.
Рисунок 8 - Начало восстановления алгоритма на С# по коду IL
В функции send_data_from_bat() искомый алгоритм содежится между шаблоном строки (IL_003a)
и подстановкой в него обработанных данных (IL_0097).
На рисунке ниже приведен разбор кода с пояснениями.
Для понимания данного кода рекомендую источники [1] и [2].
Рисунок 9 - Разбор кода IL
На рисунке ниже представлен получившийся код на C# и результат обработки им пробного пакета в переменных r4v, i2t (окно Watch).
Рисунок 10 - Алгоритм на C#, восстановленный по коду на IL (в окне Watch результат декодирования пробного пакета)
Позже был разобран алгоритм проверки целостности данных.
Его суть заключается в применении между всеми проверяемыми байтами операции исключающего ИЛИ
и сравнения результирующего байта с ожидаемым, переданным в этом же пакете.
Рисунок 11 - Алгоритм поверки целостности
Источники информации:
- CLR via C#. Джеффри Рихтер
- ECMA-335 - Common Language Infrastructure (CLI)
Комментарии
|