Если ты занимался микроконтроллерами, то, конечно, слышал о битах конфигурации. Для разных семейств они называются по‑разному: в AVR это фьюзы, а в PIC — конфигурационное слово. Сегодня мы разберемся с ними поподробнее, а еще рассмотрим их применение для защиты прошивки в контроллере.
Рекомендую ознакомиться с моей прошлой статьей «Какой микроконтроллер выбрать», в которой более подробно описаны микроконтроллеры, о которых говорится ниже.
AVR
В семействе AVR для настройки применяются фьюзы. Фьюзы (от англ. fuse — предохранитель) — это особые биты в микроконтроллере, которые, как и все биты, хранят информацию. Их основные особенности следующие:
- они хранятся и прошиваются отдельно от остальной памяти;
- изменяются только извне;
- управляют работой микроконтроллера на самом низком уровне.
Лучше всего их можно объяснить на примере дозиметра РКСБ-104.
Основная настройка его выполнялась одним переключателем на передней панели. А вот более тонкие настройки требовали снять защитную крышку с задней стенки и воспользоваться маленькими переключателями (белые посередине).
В AVR эти биты для удобства соединяются в байты: старший, младший, защитный и дополнительный. К каждому биту можно получить доступ по принципу байт → бит. Младший байт обычно отвечает за тактирование, а старший — за плюшки. Биты отличаются от чипа к чипу, поэтому с каждым чипом в идеале стоит разбираться отдельно с помощью документации.
Значение битов в этом семействе инвертировано: 1 значит, что бит стерт, а 0 — что установлен. Но вот программы для прошивки МК работают по‑разному. Для разных программ нужно уточнять логику работы с фьюзами.
Что могут фьюзы в этом семействе МК:
-
- управление тактированием (частота генератора, внешний или внутренний генератор);
- разрешение на чтение прошивки микроконтроллера (самое интересное, но об этом позже);
- управление таймерами;
- защита EEPROM;
- более специфичные функции, их надо уточнять к конкретному чипу.
Самые «популярные» биты:
- CKSEL — их четыре, и они отвечают за тактирование;
- SUT — их два, и они управляют режимом запуска тактирования;
- CKOPT — конфигурирует внутренний генератор;
- RSTDISBL — режим работы ножки RESET МК;
- SPIEN — разрешение SPI;
- EESAVE — защита EEPROM;
- BOOTRST — адрес, откуда начать исполнять код;
- BODEN — контроль питания;
- SELFPRGEN — разрешение записи в память изнутри;
- OCDEN — вот он, бит, разрешающий чтение прошивки.
Считывают фьюзы обычно не вручную, а с помощью специальных калькуляторов. Вот один из них — Fusecalc.
Софт
При работе с фьюзами будь предельно внимателен. Неправильно выставленный бит может превратить чип в «кирпич». Перед прошивкой уточняй логику работы с фьюзами в твоей программе.
Linux
Я обычно работал с программой avrdude. Приведу пару команд без дополнительных параметров (чип, программатор). Считывание прошивки из чипа в файл:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
$ 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 -> lfuse; 0x99 -> hfuse): $ 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:
1 2 |
$ avrdude -U flash:w:flash_dump.hex -c usbasp -p m328p |
В командах есть странные строки вида flash:<wbr />w:<wbr />flash_dump.<wbr />hex. Это строки в специальном формате для avrdude. Для чего такое решение — не знаю ни я, ни кто‑либо еще.
Части этих строк разделены двоеточиями:
- первая часть — область памяти в МК (например flash или lfuse);
- вторая — направление ( w — write или r — read);
- третья — файл на локальном устройстве (например файл с прошивкой);
- последняя (опциональная) — формат файла (например r — raw или i — ihex, интеловский шестнадцатеричный).
Более специфичные случаи применения этой строки выходят за рамки данной статьи.
Windows
Оконщики обычно пользуются программами с GUI. Например, AVRdude GUI.
Первая вкладка предназначена для загрузки прошивки. Мы видим и можем выбрать целевое устройство, формат файлов прошивки и пути к самим файлам. Один предназначен для программы, другой — для энергонезависимой памяти.
Вторая вкладка конфигурирует программатор: какая используется модель и на каком порте она сидит.
Вкладка управления защитными битами.
А вот наконец и фьюзы. Задаются они как байты.
Как видишь, все просто, и использовать фьюзы можно, даже не открывая терминал!
На Arduino можно конфигурировать МК, не задумываясь о работе фьюзов. Этим занимается Arduino IDE в автоматическом режиме.
STM
В семействе STM для задания конфигурации используются биты в специальных регистрах. Информацию об этих регистрах и их назначении ищи в документации. Менять значения этих регистров можно и нужно на ходу, но, в отличие от AVR, конфигурируется тут не только самое низкоуровневое (тактирование, например), но и всякая мелкая периферия.
РЕКОМЕНДУЕМ:
Как разогнать микроконтроллер
Настраивать надо много, даже если проект в духе Hello world, поэтому обычно это делается не ручной записью регистров, а с помощью красивого и мощного софта.
Софт
STM32CubeMX — это официальное и бесплатное программное обеспечение, созданное в компании STMicroelectronics. У нее есть и другая и тоже бесплатная IDE для своих МК — Atollic TrueSTUDIO. Но начнем мы с «Кубика».
Разобраться с ним просто: создаешь проект, выбираешь контроллер – и погнали. Порты настраиваются прямо на интерактивной картинке, а периферия — с помощью меню слева. Большинство опций подписано: не надо больше лазить в даташит и разбираться с битами регистров. А в конце, по нажатию на соответствующую кнопку, программа сгенерирует код на языке программирования в виде подключаемого файла.
Atollic TrueSTUDIO — это еще одна навороченная IDE для микроконтроллеров STM. В ней можно и код писать, и отлаживать. А еще она хорошо стыкуется с «Кубом».
Есть еще System Workbench for STM32 и, конечно, Arduino IDE с ее неисчислимыми модулями.
Посторонним вход запрещен!
Если ты не хочешь использовать софт производителя МК, можно все сделать руками. Благо это относительно нетрудно. Приведу пример кода из одного своего проекта.
1 2 3 4 5 6 7 8 9 10 |
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; } |
Эта функция отвечает за конфигурацию UART. Как видишь, можно обойтись и без всяких кубов (хотя на самом деле CubeMX на мой ноут просто не установился из‑за слабых характеристик).
Библиотеки
Прошивки для STM, как правило, пишутся с помощью специальных библиотек. Есть как официальные, так и кастомные (HAL и SPL). Проще говоря, это стандартный набор библиотек. Можно, конечно, и без них — мне так даже больше нравится: лучше понимаешь, как работает твой код.
Приведу команды для компиляции и прошивки STM8 из упомянутого проекта.
1 2 3 |
$ sdcc --Werror --std-sdcc99 -mstm8 -DSTM8S103 -lstm8 -mstm8 --out-fmt-ihx ../devctrl.c $ stm8flash -c stlinkv2 -p stm8s103f3 -w devctrl.ihx |
Здесь мы видим две программы — stm8flash для прошивки и sdcc для компиляции. Может, кому‑то пригодится.
- stm8flash — это программа c GitHub. По назначению — тот же AVRdude, только для STM8. Я использовал три аргумента: -с для указания программатора, в моем случае st-linkv2 (программатор ST-Link, подробнее — в моей прошлой статье), -p для указания целевого чипа (у меня это была платка с AliExpess с чипом STM8S103F3); -w для направления работы (write, записать) и файл с прошивкой.
- sdcc (small device C compiler) — компилятор языка C для «маленьких» устройств, то есть для микроконтроллеров. Это аналог GCC, но для МК.
- —Werror — считать все предупреждения ошибками. Странно, наверное, ведь обычно программисты забивают на предупреждения, а тут такое. Еще есть --std-sdcc99 — это стандарт языка. Я использовал этот, потому что он ошибок не выдавал.
При низкоуровневом программировании стандарты языка С очень существенны и код может прекрасно компилироваться на одном и либо вообще не скомпилироваться, либо работать неправильно на другом стандарте. В этом вопросе отталкивайся от учебников, по которым ты учился программировать. Как правило, во вступлении написано, какой стандарт будет рассмотрен в книге.
Остальные аргументы, кроме файла кода, — это для какого МК компилировать код.
PIC
Тут уже вместо фьюзов используется особое конфигурационное слово длиной два байта. Это слово имеет адрес в памяти, который нужно уточнять в документации. Там же можно найти структуру этого слова и назначение битов. Кстати, логика битов в этом семействе смешанная. Единица может значить как и «включено», так и «выключено». Повторюсь, внимательно читай документацию.
Приведу вырезку из документации на чип PIC16F627A.
Тут мы видим следующие настройки:
- CP — защита flash-памяти, то есть прошивки;
- CPD — защита области с данными;
- LVP — низковольтная прошивка;
- и так далее.
Работает конфигурационное слово как статическая глобальная переменная в языке С. Есть участок кода, который при прошивке записывается прямо на область памяти, отвечающей за конфигурацию микроконтроллера. Менять его на ходу, конечно, нельзя. Работа схожа с AVR-контроллерами.
Софт
Софт я уже описывал в моей прошлой статье, поэтому покажу лишь особенности при конфигурировании этих самых контроллеров.
Тут используется язык ассемблера, и мы видим строчку __CONFIG <wbr />03FF4H. Возможно, это макрос или что‑то подобное, но нам важен смысл — это число записывается как конфигурационное слово и кодирует в себе настройки МК, в комментариях к коду они даже подписаны.
И вот еще один пример кода.
1 2 3 4 5 6 7 8 9 |
-- 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 защитой служит значение фьюза бита. Если защита установлена, контроллер не даст скачать прошивку. А если сбросить биты защиты, это же возможно? Возможно, но и тут тебя ждет небольшая свинья: при сбросе бита защиты МК чистит всю память.
Что же, через софт не получилось — пойдем через железо. Электроника не программирование — тут есть что пощупать. Итак, обратимся к истории: когда‑то давно существовали чипы памяти с УФ‑стиранием.
На корпусе чипа было специальное окошко, которое обычно чем‑нибудь заклеивалось. Записываешь данные при программировании встроенными средствами, а вот стираешь с помощью специального устройства, по конструкции схожего с лампой для ноготочков.
Открываешь окошко, кладешь в прибор микросхему — и через некоторое время забираешь чистый чип. С лампой‑то все понятно — можно у жены одолжить. Главное, чтобы не заметила, а то потом не объяснишь, что тебе лампа нужна через окошко память стирать.
А вот с окошком что делать? На современных чипах его нет. Если дырки нет — надо ее сделать! Я знаю три метода: механический, химический и лазерный.
- При механическом методе, как выразился польский блогер, szlifierka precyzyjna — прецизионной шлифмашинкой, то есть дремелем, надо твердосплавной насадкой прогрызть дырочку в корпусе.
- При химическом методе применяется смесь кислот (царская водка, если я не ошибаюсь), и ей протравливается все то же отверстие. Но раздобыть азотную кислоту проблематично: ее оборот под контролем, поскольку она используется при производстве взрывоопасных веществ, так что придется поискать другой способ. Если, конечно, у тебя не завалялась баночка азотной кислоты.
- Последний метод использует лазер. Им просто прожигается окошко. Лазер можно найти на ЧПУ‑граверах, но хватит ли их мощности — я не знаю.
Короче, будем считать, что окошко к подложке чипа ты проделал.
Дальше нужно понять, где область, которую надо защитить, а где — которую стереть. По сути, нам надо облучить все, кроме Flash и EEPROM. Определять, где что, тебе придется интуитивно. Можно посмотреть каналы Lisin YT и CuriousMarc — там есть вскрытие и изучение чипов. Можно посмотреть на типичные ошибки и технологию вскрытия чипов.
Итак, что защитить, мы разобрались, дальше защищаем чем‑нибудь светорезистивным. Например, святой синей изолентой. Ну а после суем чип в стиратель и ждем немного.
Если что, про лампу для ногтей — это шутка. Нужна лампа с определенной длиной волны и мощностью.
Все, исхода два: либо все сделано правильно и аккуратно и защита снята, либо что‑то пошло не так и тебе придется искать, что именно.
PIC и STM
У контроллеров PIC все так же, как и у AVR. Условия те же, метод тот же.
У STM все несколько интереснее. О методах защиты написано в документации. Если вкратце, они не запрещают считывать чип, а создают условия, чтобы сделать это было невозможно.
Вместо напутствия
Прежде чем ты побежишь красть прошивки, предупрежу: даже если ты ее скачаешь, она будет в виде бинарного кода, который еще надо дизассемблировать, изучить и восстановить логику работы, а это ой как непросто. Поэтому, на мой взгляд, легче взломать компьютер программиста, который писал прошивку, и скачать исходники с него. Но это уже тема не моей статьи!