Реверс-инжиниринг прошивки устройства на примере мигающего «носорога». Часть 1

в 14:24, , рубрики: ida pro, Блог компании ИНФОРИОН, реверс-инжиниринг
Реверс-инжиниринг прошивки устройства на примере мигающего «носорога». Часть 1 - 1

26 апреля 2018 года компания ИНФОРИОН провела конференцию для студентов МГТУ им. Баумана SMARTRHINO-2018. Специально для конференции было подготовлено небольшое устройство на базе микроконтроллера STM32F042.

Этот носорожек стал подопытным главным героем мастер-класса по реверсу прошивки. К сожалению, за время, отведенное на мастер-класс, не представлялось возможным провести полное исследование прошивки, поэтому мы решили восполнить это подробным разбором в формате статьи. Надеемся, информация будет полезна не только участникам конференции, но также всем начинающим кодокопателям.

Первая часть статьи составлена по мотивам проведённого мастер-класса и рассчитана на начинающих — уделяется внимание базовым подходам к реверсу прошивок и особенностям работы с дизассемблером IDA. Вторая часть немного сложнее, в ней уделяется внимание особенностям работы устройств на базе операционных систем реального времени.

Осторожно, под катом мигающий носорог и его прошивка!

Легенда

Участникам семинара была предложена следующая легенда.

Вам досталось устройство и небольшая инструкция к нему.

Прибор осветительный «Носорог»

Инструкция по эксплуатации

Прибор осветительный «Носорог» предназначен для освещения помещений небольшой площади. Прибор совмещает в себе стильный компактный дизайн, яркие светодиоды с низким потреблением тока и USB-интерфейс для подключения питания.

Устройство оснащено Bluetooth-модулем для удаленного управления. Предоставляются широкие возможности для контроля освещенности, позволяющие задавать оттенок и насыщенность для каждого светодиода в отдельности.

Управление устройством осуществляется через специальное программное обеспечение «Синезубик».

Приятного использования!

Упомянутого программного обеспечения для управления устройством у вас нет и необходимо написать его с нуля. Помимо этого необходимо удостовериться в безопасности использования данного устройства.

То есть всё, что есть у исследователя — устройство, которое можно включить. Если есть устройство, то можно попытаться получить его прошивку, вычитав её из flash-накопителя микроконтроллера. Этот этап был пропущен для упрощения и ускорения мастер-класса — участники получили готовый образ прошивки в виде бинарного файла rhino_fw42k6.bin (как если бы они получили прошивку, например, из обновлений).

Заинтересованный читатель также может скачать прошивку для самостоятельного исследования.

Мастер-класс проходил в интерактивном режиме – с возможностью спрашивать, предлагать свои пути решения. Для участников было доступно 4 рабочих «Носорога».

Внешний осмотр

Кратко: на этом этапе производится внешний осмотр устройства с целью поиска маркировок, доступных разъемов.

В начале семинара был сделан акцент на то, чтобы сначала внешне изучить устройство, потом уже приступать к реверсу прошивки.
Реверс-инжиниринг прошивки устройства на примере мигающего «носорога». Часть 1 - 2
В первую очередь, интересует микроконтроллер, потом периферийные устройства и разъёмы.

Внешний осмотр устройства позволил установить следующее:

  • Микроконтроллер STM32F042 – тут сразу стоит обратиться к документации на микроконтроллер (если такая есть), откуда можно узнать архитектуру, разрядность микроконтроллера и много чего полезного (для нашего случая – 32 разрядный микроконтроллер на архитектуре ARM);

    Реверс-инжиниринг прошивки устройства на примере мигающего «носорога». Часть 1 - 3

  • На тыльной стороне имеется разъем без обозначений – те, кто работал с микроконтроллерами, могут сделать верное предположение, что это разъем для прошивки устройства (во-первых, он не промаркирован; во-вторых, он имеет 5 контактов, что соответствует необходимому количеству контактов для перешивки микроконтроллера);

    Реверс-инжиниринг прошивки устройства на примере мигающего «носорога». Часть 1 - 4

  • Контакты GND, TX;
  • USB-разъем для питания устройства (об этом говорится и в «Инструкции»);
  • Неизвестный разъем XP2 на лицевой стороне устройства;

    Реверс-инжиниринг прошивки устройства на примере мигающего «носорога». Часть 1 - 5

  • Непонятная желтая блямба на ноге носорога – вероятно, сенсорная кнопка.

    Реверс-инжиниринг прошивки устройства на примере мигающего «носорога». Часть 1 - 6

Самые шустрые участники сразу же подключили питание устройствам и увидели следующее:

Реверс-инжиниринг прошивки устройства на примере мигающего «носорога». Часть 1 - 7

Также было обнаружено, что появились доступные Bluetooth-устройства c именами RHINOCEROS-220x, при подключении к которым в системе создаётся виртуальный COM-порт. Оказалось удобным подключаться к устройству по Bluetooth со смартфона и взаимодействовать через мобильное приложение «Serial Bluetooth Terminal» или аналогичное.

Было установлено, что при отправке в COM-порт произвольного текста устройство возвращает ответ Unknown command.

Начальное исследование прошивки

Кратко: на этом этапе выполняется предварительный анализ прошивки. Просмотр строк. Загрузка прошивки в IDA Pro.

Перед разбором кода прошивки имеет смысл проверить, не упакован ли код. Тут могут быть разные подходы, в простом случае достаточно воспользоваться утилитой strings, чтобы получить строки бинарного файла (приводятся в сокращении):

../Drivers/STM32F0xx_HAL_Driver/Src/stm32f0xx_hal_cortex.c
../Drivers/STM32F0xx_HAL_Driver/Src/stm32f0xx_hal_dma.c
…
Hardware init done... Starting FreeRTOS
sendMsg error %s
TSC %d
SET AUTH %d
cmd[%d] %s
UART task
Bluetooth task
AT+AB ShowConnection
…
AT-AB -BypassMode-
state bypass
ERROR: Wrong header length
cmd: %s
led idx %d hue %d sat %d val %d
msg %s
addr=%x, size=%x
User auth pass %s
Congrats amigo!
Wrong won't give up!
ERROR: Unk cmd
I've got a super power and now I'm seeing invisible tactical combatant nano-ants everywhere
…
uartRxTask
watchdogTask
sensorTask
bluetoothTask
ledsTask

Строк нашлось много – можно сделать предположение, что прошивка не сжата и не зашифрована. Уже на этом этапе можно обратить внимание на некоторые примечательные строки, например, форматные строки, строки с описанием ошибок и указанием операционной системы (а вы их увидели?). Наличие осмысленных строк, по большому счёту, можно считать половиной успешного реверса.

Что ж, попробуем загрузить прошивку в самый популярный дизассемблер. Будем использовать IDA версии 6.9 для 32-битного кода (так как микроконтроллер 32-разрядный).

При открытии файла прошивки IDA не может автоматически определить архитектуру и точку входа – необходимо ей помочь.

На этом этапе необходимо снова обратиться к документации на микроконтроллер STM32F042x4 STM32F042x6 и посмотреть раздел 5 «Memory mapping»:

Реверс-инжиниринг прошивки устройства на примере мигающего «носорога». Часть 1 - 8

В качестве Processor Type выбираем ARM Little endian, ставим галку Manual load, нажимаем OK:

Реверс-инжиниринг прошивки устройства на примере мигающего «носорога». Часть 1 - 9

В окне «Do you want to change the processor type» нажимаем Yes, после этого IDA предлагает нам создать сегменты ОЗУ (RAM) и ПЗУ (ROM), ставим галку ROM.

Теперь мы должны указать адрес начала ROM. На схеме нужно смотреть секцию Flash – это адреса 0x08000000 – 0x08008000. Также укажем, что именно в этот же адрес мы хотим загрузить файл прошивки: Loading address = 0x08000000.

Реверс-инжиниринг прошивки устройства на примере мигающего «носорога». Часть 1 - 10

В окне "ARM and Thumb mode switching instructions" нажимаем OK.

Далее IDA говорит, что ничего не знает о произвольных двоичных файлах и точку входа – функцию main — вы должны определить самостоятельно. Нажимаем OK.

Загрузка произведена. Можно изучать прошивку.

Откроем окно строк (Shift + F12). Можно обратить внимание на то, что не все строки совпадают с результатами из утилиты strings – IDA распознала не всё, к сожалению. Немного погодя мы ей поможем…

Примечание для начинающих

  • Любая программа/прошивка представляет собой набор двоичных данных. IDA Pro может по-разному интерпретировать эти данные исходного файла (представлять данные в виде команд или данных в том или ином формате). При этом тут нет кнопки «Назад» (Ctrl+Z), чтобы отменить выбранное отображение — нужно знать, как переключаться между разными режимами отображения. (Шпаргалка по горячим клавишам IDA Pro)
  • Реверс-инженер из кажущегося хаоса двоичных данных восстанавливает логику, структуру и читаемость.
  • Строки – важная информация при реверсе! Так как, по сути, среди всего набора двоичных данных являются наиболее просто и быстро воспринимаются человеком. Строки позволяют делать выводы о назначении функций, переменных и блоков кода.
  • Именуй просмотренные функции! По умолчанию, IDA даёт функциям имена по их стартовым адресам. При анализе держать в голове эти адреса весьма сложно, гораздо проще пользоваться осмысленными именами. Для того, чтобы поименовать функцию достаточно хотя бы её беглого анализа – это уже будет важным подспорьем для дальнейшего анализа.
  • Именуй распознанные переменные! Для того чтобы эффективнее проводить анализ блоков кода и функций, имеет смысл именовать переменные, которые распознала IDA, в соответствии с их назначением (всё, как в лучших практиках программирования).
  • Оставляй комментарии, чтобы не забыть важное. По аналогии с программированием, комментарии при реверсе позволяют дополнительно пояснять логику работы программы или отдельных её участков.
  • По возможности создавай структуры! IDA в своём арсенале имеет средство работы со структурами, имеет смысл освоить это средство и применять его при необходимости. При наличии структур исследуемый код станет еще проще для восприятия.

Анализ строк

Кратко: Анализ строк может помочь составить примерный план исследования двоичного файла.

Итак, строки.

Hardware init done... Starting FreeRTOS
sendMsg error %s
…
cmd[%d] %s
rsp[%d] %s
UART task
Bluetooth task
…
AT+AB SPPDisconnect
AT+AB DefaultLocalName RHINOCEROS-2205
…

Лишь только на основании строк уже можно получить много информации:

  • Операционная система – FreeRTOS;
  • Наличие форматных строк – скорее всего используются printf-подобные функции, можно будет установить назначение регистров/переменных;
  • Названия задач (тасков) – можно предположить назначение этих самых тасков и связанных с ними функций;
  • Использование AT-команд – предположительно так строится взаимодействие микроконтроллера и Bluetooth-модуля.

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

Идентификация стандартных функций

Кратко: на данном этапе необходимо удостовериться, что строки действительно распознались, после чего предстоит идентифицировать некоторые стандартные функции языка C.

После загрузки прошивки и автоматического анализа IDA распознала тела функций (не всех, кстати), но среди имён функций нет ни одного «нормального» (только автоматические имена от IDA), что может быть небольшой сложностью в сравнении с реверсом ELF- или PE-файла.

Реверс-инжиниринг прошивки устройства на примере мигающего «носорога». Часть 1 - 11

Таким образом, в ходе исследования нужно определить назначение не только специфических функций конкретной прошивки, но и идентифицировать стандартные C-функции. Может возникнуть разумный вопрос — где гарантия, что такие функции есть в прошивке и что они стандартные? Здесь стоит сказать, что обычно при создании программного обеспечения (в том числе прошивок), в 9 случаях из 10 не заморачиваются созданием своей уникальной libc-библиотеки, а пользуются тем, что уже написано и проверено временем. Именно поэтому в 90% случаев можно выдвигать предположение о наличии стандартных С-функций.

Поскольку Hex-Rays Decompiler умеет превращать ARM-ассемблер в С-код, воспользуемся этой приятной возможностью. Стоит обратить внимание, что наличие декомпилированного листинга не отменяет необходимости понимать ассемблер, тем более, декомпил существует далеко не для всех платформ.

Откроем окно строк в IDA (Shift+F12).

Реверс-инжиниринг прошивки устройства на примере мигающего «носорога». Часть 1 - 12

Выберем строку sendMsg error %s, откроем ссылки на эту строку (клавиша X – Xrefs — Cross References) — IDA распознала ссылки на строку, это хорошо:

Реверс-инжиниринг прошивки устройства на примере мигающего «носорога». Часть 1 - 13

Однако среди строк, выделенных зелёным в дизассемблере, есть просто байты, выделенные красным. При этом некоторые строки явно распознаны не полностью. Так, например, если установить курсор на адрес 0x080074E6 и нажать клавишу A (потом согласиться с предложением «Directly convert to string?»), то получится строка «No device connected». Таким же образом можно пройтись по всем строко-подобным данным и превратить их в строки (или, например, написать Python-скрипт, который пробежится по указанному диапазону адресов и создаст строки).

Следующее препятствие, которое может возникнуть – нераспознанные ссылки на строки (даже если строка распозналась). Попробуйте пройтись по строкам, нажимая клавишу X. Так, например, в моем случае не найдена ссылка на строку «recvMsg error». Ссылка на объект может быть не найдена по двум очевидным причинам:

  • нет кода, который ссылается на текущий объект;
  • IDA не распознала ссылку.

Постараемся исключить первую из них, выполнив двоичный поиск по прошивке. Открываем окно двоичного поиска (Alt + B), вводим адрес строки, не забываем поставить галочку «Find all occurrences»:

Реверс-инжиниринг прошивки устройства на примере мигающего «носорога». Часть 1 - 14

Получили одно вхождение:

Реверс-инжиниринг прошивки устройства на примере мигающего «носорога». Часть 1 - 15

Перейдём к нему (адрес 0x08007433):

Реверс-инжиниринг прошивки устройства на примере мигающего «носорога». Часть 1 - 16

Превратим DWORD-число в offset, нажатием клавиши O. Появилась ссылка на строку:

Реверс-инжиниринг прошивки устройства на примере мигающего «носорога». Часть 1 - 17

Почему созданы двойные ссылки на строки?

Это связано с особенностью архитектуры ARM – длина команды фиксирована и составляет 32 бита, следовательно, нет возможности в команде передать полный адрес объекта (также 32-битный). Поэтому в коде используется короткое смещение на адрес, расположенный рядом с функцией, где уже хранится полный 32-битный адрес объекта.

Установим курсор чуть выше — внутри функции sub_8005070 (диапазон 0x08005070-0x08005092). Переключимся к декомпилированному листингу нажатием Tab:

Реверс-инжиниринг прошивки устройства на примере мигающего «носорога». Часть 1 - 18

Обратим внимание на функцию sub_8006690. Если вернуться к строке «sendMsg error %s», то можно увидеть, что она также передается в функцию sub_8006690. Именно строки с символами форматирования могут привести к предположению о том, что функция sub_8006690 – это стандартный printf. Пусть сейчас на уровне предположения это будет printf (даже если наше предположение окажется неверным, то оно всё равно позволит нам продвинуться в исследовании).

Поставим курсор на имя sub_8006690, нажмём клавишу N, введём новое имя x_printf. Префикс «x_» добавим для удобства (от слова «eXecutable») – так можно будет отличить переименованные нами функции от функций, имена которым дала IDA автоматически.

Можно считать выполненной подготовительную часть, теперь перейдём к анализу таска, отвечающего за обработку Bluetooth-соединения. Выйти на него можно опять же через строки. Во многих окнах IDA можно выполнять поиск по Ctrl+F. Так, можно сразу выбрать строки со словом «bluetooth»:

Реверс-инжиниринг прошивки устройства на примере мигающего «носорога». Часть 1 - 19

Что такое таск?

Таск (task, задача) – понятие из мира операционных систем реального времени (RTOS). Если по-простому, то таск можно представлять как отдельный процесс. Подробнее можно почитать в цикле статей о FreeRTOS

Bluetooth-таск

Кратко: идентифицировать и проанализировать функцию обработки команд, передающихся по Bluetooth. Необходимо будет создать дополнительный сегмент памяти в IDA.

Строка «Bluetooth taskrn» не имеет кросс-ссылок — воспользуемся снова двоичным поиском, получим адрес, где она используется – 0x080058A0, перейдём туда и увидим список частично распознанных ссылок:

Реверс-инжиниринг прошивки устройства на примере мигающего «носорога». Часть 1 - 20

Создадим из них полноценные ссылки (проклацав клавишу O, или написав Python-скрипт для IDA).

Возможно, не везде создадутся ссылки (адреса, выделенные зелёным):

Реверс-инжиниринг прошивки устройства на примере мигающего «носорога». Часть 1 - 21

Перейдя по ссылкам, выделенным зеленым, увидим, что там не созданы строки. Исправляем — помогаем Иде.

Вернёмся к строке «Bluetooth taskrn». Теперь в коде по адресу 0x08005556 появилась ссылка на эту строку:

Реверс-инжиниринг прошивки устройства на примере мигающего «носорога». Часть 1 - 22

Здесь же видим, что эта строка передается аргументом в уже просмотренную нами функцию x_printf. Не забудем также дать говорящее название текущей функции «sub_8005554», например, «x_bluetooth_task».

Переключимся в декомпил и просмотрим функцию полностью. Обратим внимание на строку 132, где в функцию x_printf передаётся некое число. Если изменить отображение числа с десятичной системы счисления на шестнадцатеричную (клавиша H), то увидим число 0x8007651, которое очень похоже на адрес.

Реверс-инжиниринг прошивки устройства на примере мигающего «носорога». Часть 1 - 23

Уже знакомая ситуация – IDA не распознала ссылку. Помогаем ей, правда, для этого нужно переключиться из декомпила в дизассемблер (клавиша Tab): делаем offset, переходим по нему, создаём строку. Переходим обратно в декомпил, нажимаем F5 (обновить).

Радуемся улучшению кода:

Реверс-инжиниринг прошивки устройства на примере мигающего «носорога». Часть 1 - 24

Снова обратим внимание на строку 132. Явно, помимо форматной строки в x_printf должен передаваться еще список аргументов переменной длины (va_list), IDA этого не распознала… Ну вы поняли, да? Поможем ей.

Установим курсор на имя функции x_printf, нажмём Y – откроется окно изменения прототипа объекта. Впишем правильный прототип функции printf:

int x_printf( const char *format, ... )

Эмм, простите, у вас ошибка в прототипе printf...

Согласен, правильно будет

void x_printf( const char *format, ... )

. И чуть позже мы это исправим.

IDA отобразит аргументы для форматной строки:

Реверс-инжиниринг прошивки устройства на примере мигающего «носорога». Часть 1 - 25

Реверс-инжиниринг прошивки устройства на примере мигающего «носорога». Часть 1 - 26

Пришло время установить назначение (имена) переменных (снова строки нам помогают):

  • x_printf("recv %s state %drn", v0, v25);x_printf("recv %s state %drn", recv_data, state);
  • x_printf("cmd: %srn", v24);x_printf("cmd: %srn", cmd);
  • x_printf("addr=%x, size=%xrn", v14, v15);x_printf("addr=%x, size=%xrn", addr, size);

Другие имена уже не так очевидны, но и не супер-сложны для понимания.

Например, обратим внимание на участок кода:

Реверс-инжиниринг прошивки устройства на примере мигающего «носорога». Часть 1 - 27

Переменная v3 сравнивается с числом 3, потом фигурирует сообщение о неправильной длине заголовка. Логично переименовать:

  • переменную v3 в header_len;
  • функцию sub_80006C8 в x_strlen (можно зайти в эту функцию и проверить наше предположение).

Далее обращаем внимание на следующий блок кода:

Реверс-инжиниринг прошивки устройства на примере мигающего «носорога». Часть 1 - 28

Функция sub_80006B4 используется несколько раз. Внутри она выглядит так:

Реверс-инжиниринг прошивки устройства на примере мигающего «носорога». Часть 1 - 29

Узнали её?

strcmp. Переименовываем. Создаём из хаоса и разрозненности стройный читаемый код.

Теперь обратим внимание на переменные v20000624, v20000344, v20000348. IDA выделила их красным цветом. Всё потому, что они ссылаются на адреса, которые отсутствуют в текущей базе дизассемблера. Если снова обратиться к документации на микроконтроллер, то можно увидеть, что диапазон адресов 0x20000000-0x20001800 относится к RAM.

Почему 0x20001800?

0x1800 — это 6Kb RAM, а это указано в документации

Если переменная ссылается на несуществующую область памяти, для нее будут недоступны xref’ы – исследование будет вызывать дискомфорт… Для удобства и производительности имеет смысл создать дополнительный сегмент памяти. Открываем окно сегментов (Shift + F7), добавляем RAM-сегмент:

Реверс-инжиниринг прошивки устройства на примере мигающего «носорога». Часть 1 - 30

Обновляем декомпил. Обращаем внимание на переменную unk_20000344:

Реверс-инжиниринг прошивки устройства на примере мигающего «носорога». Часть 1 - 31

Очень похоже, что это некий auth_flag (флаг авторизации). Так и запишем, то есть назовем эту переменную. В моем случае кросс-ссылок не нашлось – используем двоичный поиск и создаём ссылки.

Проверка на устройстве

Кратко: проверим отдельные предположения на работающем устройстве

Статический анализ – классная штука, но еще лучше, если есть возможность исследовать код в динамике. Тут тоже простор для творчества, но если не усложнять, то самое простое – подключиться к устройству по Bluetooth, отправить какую-то команду и посмотреть на результат.

Так, например, при отправке строки «ZZZ» устройство ответит строкой ERROR: Wrong header lengthrn, при отправке «MEOW» (эта строка есть в исследуемом коде, передаётся в функцию strcmp) увидим mur-mur (>._.<)rn, а при отправке «ZZZZ» — ERROR: Unk cmd. Таким образом, функцию sub_8005234 можно переименовать в x_bluetooth_send.

Составлю список команд, которые возможно поддерживаются устройством, и сразу проверю их. Вот что получилось:

  • “ECH1” – возвращает «ОК», включает эхо-режим – команда дублируется отправителю;
  • “ECH0” – выключает эхо-режим;
  • “MEOW” – возвращает «mur-mur (>._.<)rn » — то ли пасхалка, то ли отладочная команда;
  • “LED “ — выключает один из ярких светодиодов;
  • “UART” – возвращает «ОК»;
  • “BLE “ — однократно мигает красным светодиодом;
  • “READ” – возвращает «ERROR: Not auth!»
  • “WRIT” – возвращает «ERROR: Not auth!»
  • “AUTP” – возвращает «ERROR: auth error!»
  • “SETP” – возвращает «ERROR: Not auth!»
  • “VIP “ — возвращает «Wrong won’t give up!»

Промежуточные выводы относительно протокола:

  • команда состоит минимум из 4 символов;
  • есть довольно странные команды, как-то связанные с авторизацией (зачем авторизация на осветительном приборе?).

Улучшение кода. Создание структуры

Кратко: при возможности имеет смысл создавать структуры данных — большое подспорье для анализа.

Идём дальше. Задача минимум для нас – научиться управлять светодиодами.

Эксперимент показал, что с большими светодиодами связана команда «LED » — по крайней мере, она позволила выключить один из четырех больших светодиодов. Посмотрим, что находится в этой ветке:

Реверс-инжиниринг прошивки устройства на примере мигающего «носорога». Часть 1 - 32

Здесь можно было бы переименовать переменные, смущают только конструкции вроде

*(_WORD *)(v6 + 4) = sub_8005338(v4);

В большинстве случаев переменная v6 является указателем на структуру. Для удобства также создадим эту структуру. Контекстное меню для переменной v6 – выбираем пункт «Create new struct type».

IDA предлагает следующее определение для структуры:

Реверс-инжиниринг прошивки устройства на примере мигающего «носорога». Часть 1 - 33

Здесь доверимся автоматике относительно типов полей структуры, но установим читабельные имена, основываясь на данных из форматной строки:

struct struct_LED
{
_DWORD idx;
_WORD hue;
_BYTE sat;
_BYTE val;
};

После создания структуры код стал ещё приятнее:

Реверс-инжиниринг прошивки устройства на примере мигающего «носорога». Часть 1 - 34

Переменная v6 по ходу дела была переименована в led. Дополнительные переменные v7 и v8 для удобства также были переименованы. Пусть Вас не смущает появление дополнительных переменных – компилятору виднее.

По сведениям из форматной строки можно сделать вывод, что цвет задаётся в формате HSV (Hue, Saturation, Value). Для перевода цвета из RGB можно воспользоваться таблицей.

Про переменную v4 пока сложно что-то сказать наверняка, кроме того, что она является структурой и создается в функции sub_8005298:

Реверс-инжиниринг прошивки устройства на примере мигающего «носорога». Часть 1 - 35

Реверс-инжиниринг прошивки устройства на примере мигающего «носорога». Часть 1 - 36

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

  • v4 — bt_args
  • sub_8005298 — x_get_bt_args

В декомпиле возможна потеря ранее распознанной информации

При манипулировании именами и типами данных в декомпиле могут пропадать или появляться аргументы функций. В этом случае нужно для таких функций явно указывать их прототип (клавиша Y на заголовке функции). Из-за того, что в ARM’е первые 4 аргумента передаются через регистры, IDA при декомпиле может эти аргументы «терять», в этом случае… спешим на помощь ИДЕ. Если по декомпилу непонятно, какие аргументы передаются в функцию, идём в дизассемблерный листинг и смотрим на регистры R0-R3 – не заносятся ли в них какие-то значения перед обращением к интересуемой функции. Если заносятся, то в 90% случаев – это аргументы функции, и нужно прописать эти аргументы в прототипе.

Реверс-инжиниринг прошивки устройства на примере мигающего «носорога». Часть 1 - 37

Команда “LED ”

Кратко: исследование LED-команды, продолжаем переименовывать функции и переменные.

Сделаем еще несколько переименований для удобства восприятия:

  • sub_8003B6E – x_create_struct
  • sub_800532C – x_get_value_1
  • sub_8005338 – x_get_value_2

Зайдём в функцию x_get_value_1:

Реверс-инжиниринг прошивки устройства на примере мигающего «носорога». Часть 1 - 38

Переименуем sub_800530C в x_get_value_3. А теперь сравним функции x_get_value_1 и x_get_value_2:

Реверс-инжиниринг прошивки устройства на примере мигающего «носорога». Часть 1 - 39
Реверс-инжиниринг прошивки устройства на примере мигающего «носорога». Часть 1 - 40

В них используется одна и та же функция x_get_value_3, но с отличающимся вторым аргументом (2 и 4). При этом x_get_value_1 возвращает 1-байтовое число, а x_get_value_2 – 2-байтовое.

Анализируем работу с x_get_value_3:

  • работа ведётся со строкой bt_args (или структурой, содержащей строку);
  • когда на вход подается число 2, на выходе – число размером 1 байт;
  • когда на вход подается число 4, на выходе – число размером 2 байта.

Сопоставив эти факты, можно выдвинуть предположение, что функция x_get_value_3 формирует число из hex-строки указанного размера.

Выполним переименования:

  • x_get_value_1 — x_get_byte;
  • x_get_value_2 — x_get_word;
  • x_get_value_3 — x_unhexlify.

Проверим, используется ли функция x_unhexlify где-то ещё.

Используется. Функция sub_8005344 выглядит так:

Реверс-инжиниринг прошивки устройства на примере мигающего «носорога». Часть 1 - 41

Можно переименовать её в x_get_dword.

Заинтересованный читатель может погрузиться в статический анализ функции x_unhexlify и структуры bt_args — наверняка это будет увлекательно.

На данный момент мы можем сформировать команду для управления светодиодами:

Реверс-инжиниринг прошивки устройства на примере мигающего «носорога». Часть 1 - 42

Остаётся вопрос – нужны ли разделители между отдельными полями?

Пользуясь преимуществом наличия устройства, я проверю 2 варианта:

  • пробелы в качестве разделителей;
  • без разделителей.

Для включения нулевого светодиода в красный цвет (следуя таблице преобразования) необходимо задать следующие значения:

  • Индекс светодиода (idx) = 0x00;
  • Оттенок (hue) = 0x00;
  • Насыщенность (saturation) = 0xFF;
  • Значение (value) = 0xFF.

Команда с пробелами: "LED 00 0000 FF FF" — светодиод зажегся ярким светло-голубым цветом.

Команда без пробелов: "LED 000000FFFF" (пробел после символов «LED» нужен по формату команды) – светодиод зажегся красным цветом.

Таким образом, можно сделать вывод, что параметры команды должны передаваться без пробелов. И здесь же можно выстроить предположение (которое могут подтвердить те товарищи, кто провёл полный статический анализ функции x_unhexlify), что функция x_unhexlify служит для потокового вычитывания информации с указанием размера из некого базового буфера.

  • Включить первый светодиод зелёным: "LED 010078FF80"
  • Включить второй светодиод синим: "LED 0200F0FFFF"
  • Включить третий светодиод фиолетовым: "LED 03012СFF80"

В LED-ветке осталась неизученной функция sub_8003B7C. Она принимает на вход некую переменную dword_20000624. Посмотрим, где используется эта переменная – на всякий случай сразу воспользуемся бинарным поиском (Alt + B):

Реверс-инжиниринг прошивки устройства на примере мигающего «носорога». Часть 1 - 43

Обратите внимание на адреса 0x08004FF0, 0x08005D40. Хотела спрятаться! Помогаем Иде – создаём ссылки.

Посмотрим теперь, куда ведут ссылки off_8004FF0 и off_8005D40:

  • функция sub_8004D84 – явно стартовая функция прошивки, так как внутри используется строка «rnHardware init done… Starting FreeRTOSrn» — переименуем эту функцию в x_main;
  • функция sub_8005A08 – в самом начале использует строку «LED taskrn» — переименуем эту функцию в x_leds_task.

Таким образом, переменная dword_20000624 используется:

  • ближе к концу функции main;
  • после получения данных по Bluetooth в x_bluetooth_task;
  • в начале цикла функции x_leds_task.

Те, кто программировал потоки в обычной ОС или же работал с тасками RTOS, увидят в этой переменной указатель на очередь для обмена данными между тасками – и правильно сделают. Выполним еще несколько переименований:

  • dword_20000624 — leds_queue;
  • sub_8003BD0 — x_queue_recv;
  • sub_8003B7C — x_queue_send.

Дополнительно можно убедиться в правильности названий, если посмотреть места, где используются эти функции:

Реверс-инжиниринг прошивки устройства на примере мигающего «носорога». Часть 1 - 44

Реверс-инжиниринг прошивки устройства на примере мигающего «носорога». Часть 1 - 45

Переименуем:

  • sub_800501C — x_sendMsg;
  • sub_8005044 — x_recvMsg.

Теперь, чтобы убедиться, что мы полностью умеем управлять светодиодами, исследуем функцию x_leds_task.

На этом мы немного прервёмся, выпьем чай с шоколадкой и продолжим во второй части статьи.

Результаты первого этапа

  • Проведён внешний осмотр устройства.
  • Прошивка загружена в дизассемблер.
  • Найдены полезные для исследования строки.
  • Было установлено, что «носорог» управляется через Bluetooth по простому текстовому протоколу.
  • Частично исследован таск обработки команд протокола обмена по Bluetooth.

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

Автор: prusanov

Источник


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js