Час первый: звонок и опись того, что осталось
Инцидент начинается одинаково. Устройство работает и продолжает продаваться, нужно поменять мелочь — порог срабатывания, адрес сервера, текст на экране, поддержку нового датчика. Выясняется, что менять некому и нечем: разработчик прошивки недоступен, репозиторий был на его стороне, а на руках у компании — только готовые платы и файл с расширением .hex или .bin, который кто-то когда-то получил для прошивки на производстве. Или даже этого файла нет.
Первое действие — не техническое, а бухгалтерское: перечислить, что вообще есть. От этой описи зависит и стоимость работы, и то, возможна ли она в принципе.
- •Живой экземпляр устройства — желательно не один, а несколько из разных партий,
- •Файл прошивки в любом виде: на производстве, в программаторе на линии, в сервисной утилите обновления, на сервере обновлений,
- •Схема платы и перечень элементов — хотя бы черновой, хотя бы в переписке,
- •Отладочный разъём на плате и сведения о том, закрыт ли контроллер на чтение,
- •Техническое задание, протокол обмена, инструкция пользователя — то, что описывает требуемое поведение словами,
- •Договор с подрядчиком: кому принадлежат права на программу и обязан ли он был передать исходники.
Разница между «исходников нет» и «не осталось ничего» — это разница между обозримой доработкой и полной разработкой с нуля. Опись делают до того, как называют сроки и цену, а не после.
День первый: снять дамп, пока устройство живо
Пока плата рабочая, главная задача — вынести из неё образ памяти. Штатные пути одинаковы для большинства микроконтроллеров: отладочный интерфейс на плате, встроенный загрузчик через последовательный порт, выпаянная микросхема памяти на программаторе, если память внешняя. Считанный образ сразу проверяют: снимают дамп с нескольких экземпляров и сверяют контрольные суммы. Совпало — читается стабильно, и можно работать. Разошлось — либо ошибка чтения, либо в памяти есть области, индивидуальные для каждого устройства: калибровки, серийный номер, ключи. Такие области отмечают отдельно, их нельзя затирать при обновлении.
Развилка: память закрыта на чтение
Здесь инцидент делится надвое. Если подрядчик включил защиту от считывания, штатными средствами дампа не получить — это не недоработка инструментов, а работающая по назначению функция. Тогда возвращаются к описи и ищут копию бинарника там, где её обычно забывают: на производственной площадке, шившей платы, в дистрибутиве сервисной утилиты, в архиве обновлений, в почтовой переписке трёхлетней давности. Обойти эти места стоит прежде, чем обсуждать разработку заново: найденная копия снимает самую рискованную часть работы.
Если не нашлась — остаётся описать устройство снаружи: снять обмен на шине логическим анализатором, перебрать реакции на входные сигналы, собрать требования из документации и инструкции. Прошивка потом пишется заново, но не вслепую, а под задокументированное поведение. Это дороже разбора дампа, и такой вариант нужно называть заказчику до начала работ, а не после того, как деньги потрачены на попытки прочитать закрытый чип.
Неделя первая: что вытаскивают из бинарника
Дамп — это не текст программы, а поток машинных инструкций и данных вперемешку. Разбор идёт от опорных точек к смыслу: сначала определяют ядро и модель контроллера, затем находят таблицу векторов прерываний и точку входа, дальше — обращения к адресам регистров периферии, а по ним восстанавливают, какие выводы и интерфейсы задействованы.
| Что ищут | Как находят | Что это даёт |
|---|---|---|
| Ядро и модель контроллера | маркировка на корпусе, карта адресов, таблица векторов | выбор дизассемблера и карты периферии |
| Текстовые строки и константы | поиск читаемых последовательностей в образе | меню, коды ошибок, версия, имена узлов |
| Работа с периферией | обращения к адресам регистров портов и интерфейсов | распиновка, внешние шины, состав обвязки |
| Протокол обмена | сопоставление кода с реальным трафиком на шине | формат кадров, адреса, набор команд |
| Индивидуальные области | сравнение дампов разных экземпляров между собой | что нельзя перезаписывать при обновлении |
| Ключи и сертификаты | участки высокой энтропии рядом с сетевым кодом | что считать секретом и что менять после инцидента |
Разбирают не всю прошивку — это редко имеет экономический смысл. Разбирают участок вокруг того, что нужно изменить, плюс всё, что с ним связано по данным. Остальной код может остаться чёрным ящиком, если он продолжает работать.
Вторая развилка: пропатчить или написать заново
После разбора появляется выбор, и он экономический, а не технический.
| Путь | Когда оправдан | Чем платите |
|---|---|---|
| Правка прямо в бинарнике | нужно поменять константу, строку, адрес, порог — один раз | исходников по-прежнему нет; следующая правка начнётся с нуля |
| Восстановление исходника нужного модуля | менять придётся регулярно, устройство ещё выпускается | дольше и дороже, зато появляется сопровождаемый проект |
| Полная переработка по описанному поведению | дампа нет или код безнадёжно устарел | фактически новая разработка со стендовой приёмкой |
Ошибка на этой развилке стоит дорого в обе стороны. Заказать полное восстановление ради одной строки — переплата. Сэкономить на патче, когда впереди ещё несколько доработок, — значит оплачивать разбор заново каждый раз и накапливать заплатки, в которых через год не разберётся никто.
Приёмка: чем доказывают, что стало не хуже
Восстановленную прошивку нельзя принимать по принципу «включилось и мигает». Старая работала годами и обросла поведением, которого нет ни в одном документе. Приёмка строится на сравнении со старой версией, а не на проверке новой самой по себе.
- •Стенд с двумя экземплярами: один со старой прошивкой как эталон, второй с новой,
- •Одинаковые входные воздействия на оба и сравнение реакции, а не «выглядит правильно»,
- •Сравнение трафика на шине по записям с анализатора — кадр в кадр, а не на глаз,
- •Проверка поведения на границах: обрыв связи, пропадание питания, некорректные данные на входе,
- •Сохранение индивидуальных областей памяти — калибровки и серийники после обновления на месте,
- •Обновление сначала на небольшой партии, и только потом на остальном парке,
- •Записанная процедура отката к сохранённому оригинальному дампу.
Разбор причин: это отказ договора, а не отказ техники
Технически инцидент решаем почти всегда. Возникает он по одной и той же организационной причине: передача исходных материалов не была условием оплаты. Прошивку принимали по факту работающего устройства, репозиторий жил у подрядчика, ключи и сертификаты выпускал он же, а доступы после завершения работ никто не отзывал. Ровно та же логика, что и с уходящим сотрудником, который уносит с собой то, что должно было остаться в компании — этот сценарий разобран в статье утечка данных перед увольнением, и с внешним подрядчиком он отличается только тем, что доступы у него, как правило, шире и контролируются хуже.
Что имеет смысл записать в договор на разработку электроники и прошивки:
- •Передача исходников, файлов проекта и схем — условие подписания акта, а не жест доброй воли,
- •Инструкция по сборке с версиями инструментария; условие проверяется делом — заказчик собирает бинарник сам и сверяет с прошитым,
- •Репозиторий на стороне заказчика с первого дня работ, а не выгрузка архива в конце,
- •Ключи, сертификаты и учётные записи облака выпускаются и хранятся у заказчика,
- •Порядок отзыва доступов в день завершения работ — с фиксацией, что именно отозвано.
Отдельный вопрос — где лежит копия исходников на случай, если подрядчик перестанет отвечать. Фиксация авторства и хранение копии у независимой стороны — две разные процедуры, они разобраны в статье депонирование исходного кода. А если исполнитель уже пропал и дело не только в прошивке, порядок сбора доступов и остатков проекта описан в статье что делать, если подрядчик пропал с проектом.
Пункт про отзыв доступов касается не только подрядчиков по железу. Для удалённых исполнителей вообще нужна внятная граница между рабочим доступом и контролем — как её выстроить без превращения в слежку, разобрано в статье контроль удалённых сотрудников.
Хроника целиком, шагами
- •Шаг 1 — опись остатков: экземпляры устройства, любые копии бинарника, схема, договор с подрядчиком,
- •Шаг 2 — снять дамп с живого устройства, сверить образы между экземплярами и убрать копию в надёжное место,
- •Шаг 3 — если память закрыта, искать копию бинарника у смежников, а не ломать защиту вслепую,
- •Шаг 4 — разобрать бинарник вокруг того участка, который придётся менять, и восстановить протокол и карту периферии,
- •Шаг 5 — выбрать между патчем и восстановлением исходника, исходя из числа будущих правок, а не из цены первой,
- •Шаг 6 — принять работу сравнением со старой версией на стенде и закрыть организационную дыру в договоре.
Чем мы можем помочь
Чужое оборудование без документации — одно из направлений, за которые мы готовы взяться: снятие дампа, разбор бинарника, восстановление протокола и сопровождаемого исходника, стендовая приёмка со сравнением со старой версией. Это относится и к случаю, когда дампа получить не удалось, — но тогда мы говорим об этом прямо и считаем работу как разработку заново. Что мы делаем и что после сдачи остаётся у вас — на странице направлений работ.
Частые вопросы
Можно ли просто «декомпилировать» прошивку обратно в исходный код?
Нет. Дизассемблер восстанавливает машинные инструкции, но не имена переменных, не комментарии и не структуру проекта — компилятор их выбросил, и обратно они не появляются. Из бинарника восстанавливают поведение конкретного участка, а затем пишут новый исходный код, который это поведение воспроизводит. Ожидание «получить исходники обратно нажатием кнопки» — частая причина сорванных сроков в таких работах.
Что делать, если чтение памяти микроконтроллера заблокировано?
Сначала искать копию бинарника там, где её обычно забывают: у производственной площадки, которая шила плату, в программаторе на линии, в сервисной утилите обновления, на сервере обновлений «по воздуху», в архивах переписки с подрядчиком. Если копии нет, остаётся путь чёрного ящика: поведение устройства описывают снаружи — по протоколу на шине, по реакции на входы, по документации на схему — и пишут прошивку заново. Это дороже разбора дампа и честно должно быть названо до старта, а не после.
Дамп прошивки — это конфиденциальные данные?
Как правило, да. В образе памяти обычно лежат ключи и сертификаты для связи с облаком, пароли к беспроводной сети, токены доступа к API, иногда серийные номера и калибровки. Дамп нельзя загружать в публичные онлайн-дизассемблеры и пересылать в мессенджерах: одна такая пересылка компрометирует весь парк устройств, а не одну плату. Хранить — в шифрованном хранилище, с ограниченным списком тех, у кого есть доступ.
Дешевле пропатчить бинарник или писать исходники заново?
Разовая правка одной константы или строки дешевле патчем — это заметно меньший объём работы. Но патч не возвращает проект: следующая правка начнётся с той же точки, а наложенные заплатки усложняют разбор для того, кто придёт после вас. Если менять придётся не один раз или устройство ещё выпускается, разумнее один раз оплатить восстановление сопровождаемого исходника.
Насколько это законно?
Вопрос решается договором с подрядчиком и тем, кому принадлежат исключительные права на программу, а не техническими соображениями. Если устройство разрабатывалось для вас по договору, начинать нужно с того, что в нём написано про права на результат и передачу исходных материалов. Юридическую оценку конкретной ситуации должен давать юрист — мы её не заменяем и в подобных работах просим подтвердить основание до начала.
Как не попасть в эту ситуацию второй раз?
Сделать передачу исходников, файлов проекта и инструкции по сборке условием подписания акта, а не устной договорённостью. Проверять условие делом: заказчик собирает бинарник у себя и сверяет его с тем, что прошито в устройстве. Репозиторий держать на своей стороне с первого дня работ, ключи и сертификаты — в своём хранилище, а доступы подрядчика отзывать в день завершения работ.