Защита прошивки от считывания.

Небольшой туториал по защите прошивки микроконтроллера stm32 от считывания

Cover Image

Для защиты прошивки можно применять несколько способов:

  • установка битов соответствующих регистров
  • и совсем варварский способ - оторвать ноги JTAG :)

Я предпочитаю исключительно первый способ.

Простейший вариант это подключить контроллер и с помощью утилиты ST-Link Utility изменить настройки Option Bytes, установив Read Out Protection в значение Enable.

Всё, контроллер больше не поддаётся ни отладке, ни считыванию прошивки. И самое прекрасное, что при снятии этого флага память программы очищается.

Для автоматизации можно конечно написать скрипт, который будет сразу заливать прошивку и выставлять нужный нам бит, благо утилита имеет консольную версию.

Но всё можно сделать на много проще.

В библиотеке StdPeriph в файле stm32f10x_flash.h имеется определение функции:

FLASH_Status FLASH_ReadOutProtection(FunctionalState NewState);

Принимающая на вход значение ENABLE или DISABLE, соответственно включить защиту и выключить.

Получается что для защиты нам необходимо только выполнить эту функцию со значением ENABLE. Но нужно ещё разблокировать запись во флэш. То есть код будет выглядеть следующим образом.

FLASH_Unlock();
FLASH_ReadOutProtection(ENABLE);
FLASH_Lock();

Делаем всё выше сказанное перед (можно после) инициализации всей периферии в процедуре main. Но теперь возникает вопрос - мы будет каждый раз переписывать значение при включении нашего устройства? Нет, для этого необходимо каким-то образом узнать, установлена ли уже защита, на помощь приходит функция из того же файла stm32f10x_flash.h и код уже будет выглядеть следующим образом:

#include "main.h"
#include "stm32f10x_flash.h" // Хедер драйвер для флэша

#define NDEBUG // макрос для разрешения и запрещения отладки

int main(void)
{
    #ifdef NDEBUG
        #warning "FLASH Read OUT Protection ON. DEBUG is OFF."

        // Проверяем установлена или сброшена защита
        if (FLASH_GetReadOutProtectionStatus() == RESET)
        {
            // если защиты нет

            FLASH_Unlock();                  // Разрешаем запись в память
            FLASH_ReadOutProtection(ENABLE); // Защищаемся от считывания прошивки
            FLASH_Lock();                    // Запрещаем запись в память
        }
    #endif

    init(); // Инициализация

    while (1)
    {
        // Здесь будет ваша программа
    }
}

Если же использовать для разработки и прошивки KEIL, то можно просто в настройках проекта установить флаг Execute-only Code и среда всё сделает за вас.