Хабрахабр

[Из песочницы] Реверс-инжиниринг электрокарниза AM82TV

Есть у меня пара электрокарнизов компании Akko — AM82TV. Модель эта выделяется из собратьев наиболее полным набором интерфейсов управления. Шторами можно управлять по радиоканалу, есть “сухие контакты”, пофазное управление (замыканием управляющих проводов с сетевыми). Есть интерфейс RS485 — это, если захочется подключить шторы к “умному дому”. Можно также открыть/закрыть шторы просто дернув их рукой в нужном направлении. “Из коробки” не хватает, пожалуй, только web-интерфейса, ну и MQTT.

Можно, конечно, подключить всё снаружи, но лучше если внешний вид останется прежним и всё будет спрятано внутри. Электрокарнизы у меня уже давно, работают надежно, но время от времени стало появляться желание их разобрать — из любопытства посмотреть что внутри и есть ли возможность засунуть туда ESP8266 (или ESP32) с тем, чтобы добавить недостающее.

Поначалу я пытался гнать от себя дурные идеи, но со временем зуд усиливался и вот, настал момент, когда с ним уже было невозможно бороться. Не чини того, что не сломано — это не про меня. Начальный осмотр должен был дать ответы на два вопроса: есть ли место для ESP8266 и можно ли использовать встроенный источник питания. Я снял мотор с электрокарниза и разобрал его. Достаточно открутить несколько винтов с торцов мотора. Разобралось все просто. После этого можно извлечь содержимое — коллекторный мотор в одном корпусе с редуктором и датчиком вала двигателя, блок питания на 24 вольта и плату управления.
Место под ESP’ху есть, блок питания рассчитан на мощный мотор и не заметит небольшой дополнительной нагрузки. Единственно — шлицы винтов сделаны не под отвертку, а под шестигранный ключ torx. Если бы на плате не было контактов для установки разъема ISP (интерфейс внутрисхемного программирования микроконтроллера) это бы уже меня не остановило, но они там были. Я стал рассматривать плату управления и мысли про ESP стали уходить на второй план — сердцем платы был микроконтроллер atmega168. У меня нет программатора и я не написал ни строчки кода для микроконтроллеров atmega. Чтобы вы поняли меня правильно — я вовсе не фанат avr. Чтобы не ждать до утра, я собрал программатор Громова. Срочно нужен был программатор, чтобы попытаться считать прошивку, но дело было вечером и купить что-то в магазине прямо сейчас уже не было возможности. Затем припаял разъем ISP на плате управления, подключил программатор и попытался считать прошивку — и она считалась.

Поэтому, по печатной плате я восстановил схему. Пытаться понять что-то в прошивке микроконтроллера не разобравшись в принципиальной схеме, невозможно. Чтобы не рисовать самому элементы, которые есть на плате, но нет в стандартной библиотеке, я нарисовал схему в easyeda. Мне не часто приходится рисовать схемы. Для понимания достаточно фрагмента: Да, получается не по ГОСТу (но микроконтроллер нарисован как в документации, что удобно).

Здесь и далее большинство картинок кликабельны.

Если есть желание, можно ознакомиться с полной схемой.

Просто перевести машинные коды в мнемоники ассемблера недостаточно для анализа. После этого я был готов к исследованию прошивки. К сожалению, отладка на самом микроконтроллере в случае atmega168 невозможна, но можно загрузить прошивку в симулятор. Нужно видеть состояние регистров и памяти в любой точке программы. Я не стал устанавливать Atmel Studio 7. Не слишком удобно, если хочется “почувствовать” реальное железо обвязки микроконтроллера, но обойдемся тем, что есть. В принципе, для анализа достаточно одной Studio, но есть возможность переложить часть рутинных операций на другое программное обеспечение. Решил, что будет достаточно более компактной AVR Studio 4. Мне нужен был повод, какая-нибудь практическая задача, чтобы с ним познакомится. В марте был опубликован инструмент для реверс-инжиниринга — Ghidra. Каждый инструмент по-отдельности — AVR Studio 4 и Ghidra у меня немного подглючивали. Вот как раз удобный случай. Ghidra иногда сбивалась в анализе индексной адресации. AVR Studio при нескольких вложенных переходах в подпрограммы могла вдруг перестать отображать правильные адреса переходов в командах (адрес становился нулевым). Но использование сразу обоих инструментов позволяло быстро выявлять причину этих странностей.

Лучше, если будет какая-то конкретная задача. Бесцельно копаться в прошивке не слишком интересно. Я решил покопаться в радиопротоколе. На вскидку, любопытными могут быть анализ протокола обмена по RS485 и протокол управления по радиоканалу.

Когда-то давно, я уже снял сигнал, передаваемый радиопультом и проанализировал его.

Мотор способен только принимать сигнал и никак не подтверждает получение команды. Радиоканал односторонний. На физическом уровне есть только приемник радиосигнала. Опросить состояние электрокарниза по радиоканалу нельзя. Сигнал передаётся радиопультом на частоте 433. Передатчика в моторе нет. Кодируется амплитудной манипуляцией. 92 МГц. Графически весь сигнал можно представить так: Команда состоит из стартового бита особой формы, адреса+канала и непосредственно команды.

Если передать команду на нулевом канале ее выполнят все устройства с заданным адресом, но разными каналами. Канал можно рассматривать как часть адреса. Удобно, если нужно передать команду сразу группе электрокарнизов.

Подробнее о радиопротоколе.

Не слишком много, если сравнивать с возможностями управления электрокарнизом по RS485. Анализируя как передает команды радиопульт, я уже знал коды четырех команд. Хотелось убедиться в том, что выявлены все команды и нет “пасхальных яиц” или сервисных команд.

По принципиальной схеме видно к каким портам микроконтроллера подключены физические устройства. Подход при анализе простой. Это удобно — много рутинных операций выполняется в автоматическом режиме. Файл прошивки анализируется в Ghidra. Дальше фрагменты кода и скриншоты я буду приводить именно из Ghidra. После анализа работы конкретного фрагмента кода или подпрограммы ему присваивается осмысленное название. В особо запутанных ситуациях придется рисовать картинки. При затупах запускаем код в симуляторе.

По-хорошему нужно было бы создать файл с другим названием, но мне этот файл в исходном виде был не нужен и я исправил тот, что был.
Прошивка начинается с векторов прерываний. Для того, чтобы названия регистров периферии atmega168 корректно отображались при дизассемблировании, я поправил файл avr8.pspec. Выглядит вот так: Первым идет вектор перехода на начало программы.

Если по каким-то причинам такое прерывание произойдет, сразу же будет выполнена команда возврата. Большинство прерываний не используется. Обмен по RS485 сейчас нас не интересует, а вот переполнение таймера нужно просмотреть. Кроме обработки прерывания по reset’у еще обрабатываются прерывания по переполнению Таймера 0, завершению приема и готовности передачи следующего байта данных в USART.

Искать в дезассемблированном коде место, где происходит инициализация я не стал. Разумеется, прежде чем будет разрешено прерывание по таймеру, сам таймер должен быть настроен. Запустил программу, получил выброс и просто посмотрел что записано в регистры. В симуляторе поставил точку останова на адрес 0x1fc — это адрес записанный в обработчике прерывания. При кварце на плате 8 МГц на таймер поступают импульсы с частотой 1 МГц. Сlock select для timr0 установлен в clk/8.

Начало обработчика прерывания:

Граф функций обработчика прерываний “с высоты птичьего полета”

image

Таймер переполняется каждые 107 мкс. Кроме прочего, в обработчике прерывания обрабатывается сигнал с выхода приемника радиосигнала. Если сигнал успешно проходит проверку, полученные данные записываются в буфер по адресу 0x4af. Размер буфера 6 байт. Это на один байт больше, чем необходимо для приёма четырех байт адреса+канала и байта команды. Возможно, шестой байт радиопротокола был предназначен для контрольной суммы, но атрофировался. Иногда такое бывает. Возможно, предназначен для данных, дополняющих какую-то из команд. В протоколе управления электрокарнизом по RS485 есть команда частичного закрытия штор. При этом дополнительно передается байт с данными о величине закрытия в процентах. Подобная команда могла бы существовать и в радиопротоколе. Основной программе сообщается о готовности данных установкой флага — по адресу 0x4bd записывается единица.

На этом анализ прерываний заканчиваем и переходим к основной программе.

Граф функций при переходе по адресу 0x1304 лаконичен и прост:

image

Мы уже проанализировали прерывания и понимаем, что если по каким-то причинам мы вдруг вернемся из main и попадем в “go_to_sleep”, то сон этот окажется летаргическим — электрокарниз перестанет делать что-то полезное. Нам нужно в “main”. Вероятно, при написании прошивки, использовался готовый шаблон и артефакты остались после него.

Искать долго не придется. В main нам нужно найти место, где происходит обращение к буферу 0x4af. Буквально через несколько команд происходит вызов подпрограммы, начинающейся с адреса 0x11b3, где этот буфер копируется и обрабатывается.

Граф функций процедуры rf_signal_buffer_processing (0x11b3):

Чтобы разобраться я стал рисовать картинки. Это точно то место, которое нам нужно, но выглядит чуть сложновато. Что-то вроде блок-схемы.

Первое, что тут происходит — данные из буфера 0x4af копируются по новому адресу — 0x49f и сбрасывается флаг 0x4bd:

Следующий фрагмент самый интересный:

Пока это не очевидно, но дальнейший анализ показал, что переход на следующие ветки — это обработка следующих радиокоманд в случае, если перед этим была получена команда 0xcc — переход в режим настроек. Фактически это вся проверка полученной по радиоканалу команды. Есть ли что-то, кроме кодов команд 0x11, 0x33, 0x55 и 0xcc. Меня интересовали именно новые коды самих команд.

На рисунке он перечеркнут красным. Ни здесь, ни дальше мне не удалось найти обработку последнего — шестого байта команды. По крайней мере в прошивке AM82TV. Так что все команды состоят из пяти байт.

Вот, кажется, нашлись новые коды команд — 0xad и 0xda. Первое, что мы видим — это проверка пятого байта буфера — кода самой команды. Команда из буфера успешно проходит проверку в случае, если поле адреса совпало с одним из адресов, уже записанных в eeprom, или если код команды 0xad, или 0xda и поле адреса == 0xaaaaaaaa.

Оставшиеся картинки

Хорошо, будем считать, что очередную проверку мы успешно прошли. Теперь код команды находится по адресу 0x4bf. Нужно найти то, как обрабатывается содержимое этого байта. Сделать это можно несколькими способами. Самый простой — текстовым поиском по дизассемблированному коду в Ghidra. Останется просмотреть где именно происходит чтение содержимого этого байта. Это не гарантированный способ найти все обращения, но в этом, конкретном, случае сработает. Так, вначале, мы увидим чтение байта в процедуре, начинающейся по адресу 0x1262:

image

Обращение к которой происходит из единственного места — командой, расположенной по адресу 0x5e0.

Граф функций:

image

Даже найденные на предыдущем шаге коды 0xad и 0xda. Жаль, но все коды команд, кроме уже известных: 0x11, 0x33, 0x55 и 0xcc отбрасываются в этой процедуре. По крайней мере мне не удалось найти в прошивке электрокарниза AM82TV новых кодов радиокоманд.

Или даже что-то добавить. Тем не менее к прошивке есть доступ, ее можно дизассемблировать, посмотреть как реализованы конкретные функции и изменить что-то под себя.

Прошивка и измененный под atmega168 файл avr8.pspec выложен на GitHub.

Теги
Показать больше

Похожие статьи

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»
Закрыть