Как стать автором
Обновить

Зачем программисту дизассемблер в 2025: отладка на слепую под редкие MCU

Уровень сложностиСложный
Время на прочтение3 мин
Количество просмотров1.3K

Даже в 2025 году, когда вокруг нейросети, автогенерация кода и IDE с предиктивным интеллектом, работа с редкими микроконтроллерами всё ещё может обернуться настоящим хардкором. Особенно, если речь идёт о «слепой» отладке без отладчика, когда в арсенале только прошивка, HEX-файл и пара байтов на выводе. В этой статье — личный опыт, много хардкора, дизассемблирование вручную и поиск глюка в 2 КБ бинаря.

Когда говорят «отладка», в 2025 году чаще всего имеют в виду жмяк на F5 в Visual Studio Code или лог с CI/CD. Но в embedded-мире, особенно если ты копаешься в системах с 8-битным контроллером 2006 года выпуска, это слово может означать кое-что пострашнее. Например — «прошивка вылетает на 4-й секунде, данных в UART нет, отладочного интерфейса нет, документации почти нет, а заказчик просит сделать "как раньше работало"». И вот тут начинается старый добрый reverse engineering.


Почему вообще это может понадобиться

Пример из жизни: заказ на перепрошивку блока управления освещением в промышленной установке. Контроллер — неизвестный китайский клон STM8, без отладочного вывода, с залоченной флеш-памятью. Из всей информации: одна прошивка в HEX-формате и данные с логического анализатора.

Никакого SDK, никакой IDE. Только бинарник и задача: понять, что делает устройство, и воспроизвести поведение на современном MCU. Тут и появляется дизассемблер. Не IDA и не Ghidra — они слишком тяжёлые, часто не поддерживают редкие или кастомные архитектуры. В ход идут простые тулзы и тонны ручного труда.


Что мы вообще можем получить из HEX-файла

Intel HEX — это просто текстовое представление бинарных данных. Конвертируем его в бинарник:

$ objcopy -I ihex firmware.hex -O binary firmware.bin

Затем — загоняем в дизассемблер. Например, для MSP430 можно использовать msp430-objdump:

$ msp430-objdump -D -m msp430 firmware.bin > firmware.asm

Но, конечно, всё не так просто. Бинарник может быть собран с учётом смещений, и без map-файла вы не узнаете, где начало main(), где стек и где таблица векторов. Придётся искать сигнатуры вручную. Пример — вот так может выглядеть обработчик reset в MSP430:

RESET:
    mov.w   #0x0280, SP       ; Инициализация стека
    call    #main
    jmp     $                  ; Бесконечный цикл

Если видим инициализацию SP и переход на main — можно считать, что стартовый адрес найден.


Поиск логики без дебаггера

Теперь начинается самое интересное: вручную отслеживаем, где в коде встречаются условные переходы, циклы, обращения к портам ввода-вывода. Если контроллер управляет, например, реле через порт P1.0, можно попробовать найти конструкции вроде:

    bis.b   #0x01, &0x0021     ; Установить бит в порту P1OUT

Находишь такие строчки — начинаешь строить карту работы прошивки. Можно вручную раскидать лейблы:

SET_RELAY:
    bis.b   #0x01, &0x0021
    ret

Анализ цикла с обработкой прерываний таймера

TIMER_ISR:
    push    r5
    inc.w   &cnt             ; Увеличить счётчик
    cmp.w   #0x0A, &cnt
    jne     SKIP_RESET
    clr.w   &cnt             ; Обнулить, если больше 10
    call    #TOGGLE_RELAY
SKIP_RESET:
    pop     r5
    reti

В этот момент понимаешь: реле переключается каждые 10 тиков таймера. Значит, частота мигания напрямую зависит от конфигурации таймера — ищем её дальше.


Восстановление логики main() с имитацией инициализации

main:
    mov.w   #0x0280, SP         ; Настройка стека
    call    #init_ports         ; Инициализация портов
    call    #init_timer         ; Настройка таймера
loop:
    call    #read_inputs        ; Опрос входов
    call    #process_logic      ; Обработка логики
    jmp     loop

init_ports:
    bis.b   #0x01, &0x0022      ; Установить выход P1.0
    ret

init_timer:
    mov.w   #0x0311, &TACTL     ; Настройка таймера: ACLK, UP
    mov.w   #0x0FFF, &TACCR0    ; Значение сравнения
    bis.w   #0x0010, &TACCTL0   ; Разрешить прерывания
    ret

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


Почему просто заменить MCU не получится

Проблема в том, что поведение микроконтроллера часто зависит от тонких нюансов: pull-up’ы, поведение пинов при ресете, тайминги. Всё это надо восстановить, иначе даже переписанная логика не заработает. Именно поэтому ручной дизассемблинг и трассировка — единственный способ понять, что на самом деле происходит.


Заключение

Зачем в 2025 году программисту дизассемблер? Затем, зачем и в 1985: чтобы понять, как работает чёрный ящик. Потому что иногда IDE нет, схемотехники нет, исходников нет, но есть задача и дедлайн. И в такие моменты весь цифровой лоск современности отлетает — и остаётся только ты, байткод и твой мозг.

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


P.S. Не забывайте: изучайте чужие прошивки только если вы имеете на это право. Эта статья — про анализ собственных или разрешённых бинарников. Нарушать NDA — себе дороже.

Теги:
Хабы:
+12
Комментарии5

Публикации

Работа

QT разработчик
8 вакансий
Программист C++
97 вакансий

Ближайшие события