Реверс-инжиниринг табло электронной очереди: когда 1 бит передаётся как байт, а контрольную сумму угадывает ИИ

Реверс-инжиниринг табло электронной очереди: когда 1 бит передаётся как байт, а контрольную сумму угадывает ИИ

Я работаю в компании, которая разрабатывает систему электронной очереди. Недавно написал веб-клиент — с SOAP, QR-талонами, веб-интерфейсом. Потом поступила задача: интегрировать физическое табло с вызовом клиентов в веб. Старое десктопное приложение умело зажигать на нём цифры — нужно было повторить это из браузера.

Поиск документации: провал

Обратился к команде, которая делала старое приложение.

День 1: «Да, конечно, поищем». День 3: «Нету, давно было, зайди позже». День 5: «А зачем тебе?» День 7: сеньор, не отрываясь от монитора: «Там где-то в коде зашито, долго искать».

В итоге — только старая утилита от монтажников, под Windows, без исходников. Вместо жалоб — решил разобраться сам. С помощью ИИ.

Анализ трафика через виртуальные COM-порты

Аппаратного анализатора нет, но есть com0com — виртуальная пара COM-портов. Старая утилита пишет в один, RealTerm читает из другого и показывает HEX.

Нажимаю кнопку — в терминал сыплются байты. И сразу бросается в глаза: каждый байт — либо 0x00, либо 0x7F. Никаких промежуточных значений.

Сначала подумал — помехи или битый поток. Потом понял.

BCD4: один бит — один байт

Это аппаратный костыль для устойчивой передачи по длинным линиям с помехами. Один бит данных передаётся как целый байт: 0x7F (семь единиц) — это логическая «1», 0x00 — «0».

Число от 0 до 15 раскладывается по 4 битам, каждый бит превращается в байт. Например:

  • 00 00 00 00 → 0
  • 7F 00 00 00 → 1
  • 00 7F 00 00 → 2
  • 7F 00 7F 00 → 5
  • 7F 00 00 7F → 9
  • 00 00 7F 7F → 12

Цена — 4 байта на цифру и скорость всего 1200 бод. Зато надёжно.

В Python кодирование выглядит просто:

Структура пакета

Пакет для вывода числа на окно состоит из 33 байт. Например, число 487 на окне 19: D1=7, D2=8, D3=4, W_lo=9, W_hi=1.

Полезные поля — цифры числа и номер окна — нашлись быстро. А вот последние 8 байт вели себя странно.

Контрольная сумма: головоломка с переносом

Простое сложение и XOR не работали. При числах вроде 80 или 90 контрольные байты резко менялись — явно был перенос между полями. На маленьких числах формулы работали, на больших — ломались.

Тогда я обратился к ИИ. Передал около 30 перехваченных пакетов, объяснил структуру, сформулировал гипотезу: «Два поля c1 и c2, судя по поведению, — это младшая и старшая части 8-битного значения с переносом. Найди зависимость от остальных полей».

Ключевым стало именно правильное описание механизма.

Несколько ночей экспериментов: неверные константы, ошибки в переносе, частичные совпадения. Иногда казалось, что логики нет — просто захардкоженная таблица.

Но в итоге удалось. Оказалось: два 4-битных контрольных поля — части одного 8-битного значения. При переполнении младшей части — единица переносится в старшую, как при сложении столбиком.

Перенос возникает не всегда — только при определённых комбинациях числа и номера окна. Поэтому на простых тестах формулы работали, а на реальных — нет.

Режим «все окна» (25 байт, без указания окна) оказался проще — контрольная сумма без переноса.

Режим программирования окна

Установка номера окна — отдельный режим. Другой заголовок, пакет той же длины (33 байта), но без полей числа. Формула сложнее: участвует умножение, магические константы и два независимых переноса для пар контрольных полей.

Когда ИИ вывел точную формулу и проверил её на всех 30 пакетах — это было торжество. Проверил на окнах 1, 19, 30 — всё сошлось до байта.

Сборка пакета

Когда все поля известны, формирование пакета занимает несколько строк:

Алгоритм прост: число и номер окна раскладываются на цифры, каждая кодируется через BCD4, добавляются контрольные поля — и пакет готов к отправке в COM-порт.

Финальная архитектура

Всё завернул в Python-сервер, который работает в трее и принимает HTTP-запросы. Веб-система вызывает клиент — на табло загорается номер. Точно как старое приложение, но без него.

HTTP-интерфейс намеренно простой:

Сервер разбирает запрос, формирует пакет, отправляет в COM-порт. Веб-клиент даже не знает, что где-то работает RS-232 на 1200 бод.

Для отказоустойчивости добавил heartbeat-поток: сервер периодически регистрируется на центральном сервере очереди. При обрыве связи — восстанавливает её автоматически, без перезапуска.

Задача решена за несколько бессонных ночей.

Выводы

Из практического: ИИ отлично ищет математические закономерности, если дать достаточно примеров и правильно сформулировать гипотезу. Важно не «найди формулу», а «вот механизм, который я подозреваю — проверь и уточни». Опишите структуру, предположение — и получите формулу с доказательством.

Из жизненного: иногда проще потратить два вечера на реверс-инжиниринг, чем неделю на переписку в корпоративном чате.

Читать оригинал