Если вы изучали микроконтроллеры, вы, вероятно, слышали о битах конфигурации. Для разных семейств они называются по-разному: в AVR это предохранители, а в PIC — слово конфигурации. Сегодня мы углубимся в них и рассмотрим их применение для защиты прошивки в контроллере. И покажем как обходить такую защиту. Погнали!
В семействе AVR для регулировки используются предохранители. Предохранители (от англ. Fuse — предохранитель) — это особые биты в микроконтроллере, которые, как и все биты, хранят информацию. Его основные особенности заключаются в следующем:
Лучше всего их можно объяснить на примере дозиметра РКСБ-104.
Дозиметр РКСБ-104
Его базовая настройка осуществляется одним переключателем на передней панели. Но для более точных настроек снятие защитной крышки с задней стенки и использование небольших переключателей (белые в центре).
Задняя панель со снятой крышкой
В AVR эти биты для удобства объединены в байты: старший, младший, защитный и дополнительный. Доступен каждый битовый байт → бит. Младший байт обычно отвечает за часы, а старший байт — за плюшки. Биты различаются от чипа к чипу, поэтому в идеале каждый чип следует рассматривать отдельно с использованием документации.
Значение битов этого семейства инвертировано: 1 означает, что бит был очищен, а 0 означает, что он установлен. Но программы для прошивки МК работают по разному. Для разных программ необходимо уточнить логику работы с предохранителями.
Что могут фьюзы в этом семействе МК:
Самые «популярные» биты:
CKSEL
— их четыре, и они отвечают за тактирование;SUT
— их два, и они управляют режимом запуска тактирования;CKOPT
— конфигурирует внутренний генератор;RSTDISBL
— режим работы ножки RESET МК;SPIEN
— разрешение SPI;EESAVE
— защита EEPROM;BOOTRST
— адрес, откуда начать исполнять код;BODEN
— контроль питания;SELFPRGEN
— разрешение записи в память изнутри;OCDEN
— вот он, бит, разрешающий чтение прошивки.Считывают фьюзы обычно не вручную, а с помощью специальных калькуляторов. Вот один из них — Fusecalc.
При работе с фьюзами будь предельно внимателен. Неправильно выставленный бит может превратить чип в «кирпич». Перед прошивкой уточняй логику работы с фьюзами в твоей программе.
Я обычно работал с программой avrdude. Приведу пару команд без дополнительных параметров (чип, программатор). Считывание прошивки из чипа в файл:
$
avrdude -U flash:r:flash_dump.hex:i
Считывание энергонезависимой памяти в файл:
$
avrdude -U eeprom:r:eeprom_dump.raw:r
Запись прошивки из файла в чип:
$
avrdude -U flash:w:flash_dump.hex
Запись энергонезависимой памяти из файла:
$
avrdude -U eeprom:w:eeprom_dump.raw
Запись фьюзов (0xc3
; 0x99
):
$
avrdude -U lfuse:w:0xc3:m -U hfuse:w:0x99:m
Чтение фьюзов в файлы:
$
avrdude -U hfuse:r:hfuse.txt:h -U lfuse:r:lfuse.txt:h
Есть дополнительные параметры -с
и -p
. Первый отвечает за программатор, а второй — за чип. В качестве примера — команда для прошивки контроллера ATmega328p с помощью USBASP:
$
avrdude -U flash:w:flash_dump.hex -c usbasp -p m328p
В командах есть странные строки вида flash:
. Это строки в специальном формате для avrdude
. Для чего такое решение — не знаю ни я, ни кто‑либо еще.
Части этих строк разделены двоеточиями:
flash
или lfuse
);w
— write или r
— read);r
— raw или i
— ihex, интеловский шестнадцатеричный).Более специфичные случаи применения этой строки выходят за рамки данной статьи.
Оконщики обычно пользуются программами с GUI. Например, AVRdude GUI.
Первая вкладка предназначена для загрузки прошивки. Мы видим и можем выбрать целевое устройство, формат файлов прошивки и пути к самим файлам. Один для программы, другой для энергонезависимой памяти.
Вторая вкладка конфигурирует программатор: какая используется модель и на каком порте она сидит.
Вкладка управления защитными битами.
А вот наконец и фьюзы. Задаются они как байты.
Как видишь, все просто, и использовать фьюзы можно, даже не открывая терминал!
На Arduino можно конфигурировать МК, не задумываясь о работе фьюзов. Этим занимается Arduino IDE в автоматическом режиме.
Семейство STM использует биты в специальных регистрах для конфигурации. Информацию об этих регистрах и их назначении ищите в документации. Можно и необходимо изменять значения этих регистров на лету, но, в отличие от AVR, здесь настраивается не только самый низкий уровень (например, часы), но и небольшие периферийные устройства.
Настраивать надо много, даже если проект в духе Hello world, поэтому обычно это делается не ручной записью регистров, а с помощью красивого и мощного софта.
STM32CubeMX — это официальное и бесплатное программное обеспечение, созданное в компании STMicroelectronics. У нее есть и другая и тоже бесплатная IDE для своих МК — Atollic TrueSTUDIO. Но начнем мы с «Кубика».
CubeMX
Разобраться с этим просто: вы создаете проект, выбираете контроллер — и вперед. Порты настраиваются прямо на интерактивном изображении, а периферийные устройства — в меню слева. Большинство опций подписаны: вам больше не нужно заходить в таблицу и разбираться с битами регистра. И в конце, нажав соответствующую кнопку, программа сгенерирует код на языке программирования в виде подключаемого файла.
Atollic TrueSTUDIO — это еще одна навороченная IDE для микроконтроллеров STM. В ней можно и код писать, и отлаживать. А еще она хорошо стыкуется с «Кубом».
Есть еще System Workbench for STM32 и, конечно, Arduino IDE с ее неисчислимыми модулями.
Если ты не хочешь использовать софт производителя МК, можно все сделать руками. Благо это относительно нетрудно. Приведу пример кода из одного своего проекта.
void init_uart()
{
UART1_CR2 |= UART_CR2_TEN; // Transmitter enable
UART1_CR2 |= UART_CR2_REN;
UART1_CR2 |= UART_CR2_RIEN;
UART1_CR3 &= ~(UART_CR3_STOP1 | UART_CR3_STOP2);
UART1_BRR2 = (F_CPU/UART_BAUD) & 0x000F;
UART1_BRR2 |= (F_CPU/UART_BAUD) >> 12;
UART1_BRR1 = ((F_CPU/UART_BAUD) >> 4) & 0x00FF;
}
Прошивки STM обычно пишутся с использованием специальных библиотек. Есть как официальные, так и кастомные (HAL и SPL). Проще говоря, это стандартный набор библиотек. Можно, конечно, и без них — мне даже больше нравится: ты лучше понимаешь, как работает твой код.
Приведу команды для компиляции и прошивки STM8 из упомянутого проекта.
$ sdcc --Werror --std-sdcc99 -mstm8 -DSTM8S103 -lstm8 -mstm8 --out-fmt-ihx ../devctrl.c
$ stm8flash -c stlinkv2 -p stm8s103f3 -w devctrl.ihx
Здесь мы видим две программы — stm8flash для прошивки и sdcc для компиляции. Может, кому‑то пригодится.
-с
для указания программатора, в моем случае st-linkv2
(программатор ST-Link, подробнее — в моей прошлой статье), -p
для указания целевого чипа (у меня это была платка с AliExpess с чипом STM8S103F3); -w
для направления работы (write, записать) и файл с прошивкой.--std-sdcc99
— это стандарт языка. Я использовал этот, потому что он ошибок не выдавал.В низкоуровневом программировании стандарты языка C очень важны, и код хорошо компилируется по одному стандарту и либо не компилируется вообще, либо не будет работать должным образом в соответствии с другим стандартом. Чтобы ответить на этот вопрос, начните с руководств, которые научили вас программировать. Обычно во введении указывается, какой стандарт будет включен в книгу.
Остальные аргументы, кроме файла кода, — это для какого МК компилировать код.
Здесь вместо предохранителей используется специальное конфигурационное слово из двух байтов. У этого слова есть адрес в памяти, который необходимо объяснить в документации. Там же вы можете найти структуру слова и назначение битов. Кстати, логика битов в этом семействе неоднозначная. Вы можете иметь в виду как «включено», так и «выключено». Пожалуйста, внимательно прочтите документацию.
Приведу вырезку из документации на чип PIC16F627A.
Вырезка из документации
Тут мы видим следующие настройки:
Слово конфигурации функционирует как статическая глобальная переменная на языке C. Существует фрагмент кода, который, когда он мигает, записывается непосредственно в область памяти, отвечающую за настройку микроконтроллера. Очевидно, вы не можете изменить это на ходу. Работа аналогична контроллерам AVR.
Здесь покажем лишь особенности при конфигурировании этих самых контроллеров.
Тут используется язык ассемблера, и мы видим строчку __CONFIG
. Возможно, это макрос или что‑то подобное, но нам важен смысл — это число записывается как конфигурационное слово и кодирует в себе настройки МК, в комментариях к коду они даже подписаны.
И вот еще один пример кода. Он уже из статьи на «Хабре» (кстати, настоятельно рекомендую с ней ознакомиться).
— This program assumes a 20 MHz resonator or crystal
-- is connected to pins OSC1 and OSC2.
pragma target clock 20_000_000 -- oscillator frequency
-- configuration memory settings (fuses)
pragma target OSC HS -- HS crystal or resonator
pragma target WDT disabled -- no watchdog
pragma target LVP disabled -- no Low Voltage Programming
pragma target MCLR external -- reset externally
Он написан на языке JAL, который был создан специально для программирования этого семейства МК. Этот код явно читабельнее ассемблера. Чего уж говорить — почти все читабельнее ассемблера! Хотя PIC традиционно программируются именно на нем.
Мы проанализировали теорию. Теперь поговорим о защите. Как вы понимаете, в семействе AVR бит предохранителя служит защитой. Если защита установлена, контроллер не позволит вам загрузить программное обеспечение. А если сбросить биты защиты, возможно ли это? Возможно, но даже здесь вас поджидает поросенок: при сбросе бита защиты МК очистит всю память.
Ну из-за софта не вышло — пройдемся по железу. Электроника не программирование — есть что потрогать. Итак, перейдем к истории: раньше были микросхемы памяти с УФ-стиранием.
Чип M27c256B — память с УФ‑стиранием
На корпусе чипа было специальное окошко, которое обычно чем-то заклеивалось. Вы записываете данные при программировании встроенными средствами, а стираете их с помощью специального устройства, похожего по конструкции на лампу для ногтей.
Лампа-коготь
Лампа для коготков
Открываешь окно, вставляешь микросхему в устройство — и через некоторое время забираешь чистую микросхему. С лампой все понятно — можно одолжить у жены. Главное — не замечать, иначе не объяснишь, что нужна лампа для стирания памяти через окошко.
А вот с окошком что делать? На современных чипах его нет. Если дырки нет — надо ее сделать! Я знаю три метода: механический, химический и лазерный.
Короче, будем считать, что окошко к подложке чипа ты проделал.
Получится что‑то похожее
Далее нужно понять, где та область, которую нужно защитить, а где — стереть. По сути, нам нужно облучить все, кроме Flash и EEPROM. Определять где что, придется интуитивно. Можно смотреть каналы Lisin YT и CuriousMarc — есть вскрытие и изучение фишек. Вы можете посмотреть типичные ошибки и технологию вскрытия фишек.
Итак, что защищать, мы придумали, и затем защищаем чем-то светорезистивным. Например, святая синяя изолента. Ну а после вставляем фишку в ластик и немного ждем.
Если что, про лампу для ногтей — это шутка. Нужна лампа с определенной длиной волны и мощностью.
Все, исхода два: либо все сделано правильно и аккуратно и защита снята, либо что‑то пошло не так и тебе придется искать, что именно.
PIC такие же, как AVR. Условия такие же, метод тот же.
С STM все несколько интереснее. Способы защиты описаны в документации. Короче говоря, они не запрещают считывать чип, и создают условия, чтобы это было невозможно.
Но, собирая информацию для этой статьи, я наткнулся на страницу с интересным названием — «Считывание защищенной прошивки из флеш‑памяти STM32F1xx с использованием ChipWhisperer». Смысл этого метода в программной атаке на прошивку. Этот метод ближе к тематике журнала.
Чтобы взломать сеть Wi-Fi с помощью Kali Linux, вам нужна беспроводная карта, поддерживающая режим мониторинга…
Работа с консолью считается более эффективной, чем работа с графическим интерфейсом по нескольким причинам.Во-первых, ввод…
Конечно, вы также можете приобрести подписку на соответствующую услугу, но наличие SSH-доступа к компьютеру с…
С тех пор как ChatGPT вышел на арену, возросла потребность в поддержке чата на базе…
Если вы когда-нибудь окажетесь в ситуации, когда вам нужно взглянуть на спектр беспроводной связи, будь…
Elastic Security стремится превзойти противников в инновациях и обеспечить защиту от новейших технологий злоумышленников. В…