Реверс USB-SATA-адаптера (история одного стажера)

в 9:25, , рубрики: информационная безопасность, Компьютерное железо, Производство и разработка электроники, реверс-инжиниринг, реверс-инжиниринг для новичков, стажировка

Предыстория

Стажировка – это процесс получения знаний и опыта. Наша команда Raccoon Security считает, что повышение уровня информационной безопасности окружающих нас устройств и ПО невозможно без передачи этих знаний и опыта будущим поколениям специалистов. Именно поэтому мы уже много лет организуем индивидуальные стажировки для талантливых студентов и выпускников.

Исследование защищенности – это умение, которому не учат в университете. Ему можно научиться на конкретных примерах и под руководством опытных наставников. Ежегодно наши стажеры решают сложные технические задачи, добиваются поставленных целей и двигаются дальше, расширяя свой профессиональный кругозор и делая мир чуточку безопаснее. У каждого из них своя история становления специалистом, а под катом – начало одной из них.

Реверс USB-SATA-адаптера (история одного стажера) - 1

Введение

В октябре прошлого года я пришел на техническую стажировку в компанию «НТЦ «Вулкан». Мой интерес был направлен в область реверс-инжиниринга. Я знал, что это такое, уже пробовал самостоятельно исследовать crackme под x86, но понимал – самое интересное лежит именно на стыке ПО и «железа». Опыта в этой области у меня не было, но было желание попробовать свои силы.

У меня не было каких-то конкретных ожиданий от этого мероприятия – друзья и знакомые достаточно часто рассказывают про технические стажировки в разных известных компаниях. И когда мне предложили попробовать свои силы в исследовании USB-SATA-адаптера, я был просто рад новой возможности научиться чему-то. Полученный опыт и достигнутый мной результат позволили убедиться в правильности выбора места стажировки и будущей профессии.

А началось исследование с получения на руки обычного USB-SATA-адаптера. Вот что я делал дальше.

Визуальный схемотехнический анализ

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

Реверс USB-SATA-адаптера (история одного стажера) - 2

USB-SATA-адаптер. Вид сверху

Реверс USB-SATA-адаптера (история одного стажера) - 3

USB-SATA-адаптер. Вид снизу

Проведя некоторое время в гугле, я выяснил, что на плате расположено два преобразователя напряжения: один на 3,3 В, другой на 1,2 В. Также очень легко определилась флеш-память, установленная на плате. ПЗУ работает по интерфейсу SPI, а объем памяти составляет 512 Кбит.

Казалось бы, что этап схемотехнической разведки практически завершен, но беглый поиск в Интернете совершенно не дал результатов по запросу «ASM1051». Никаких документов на чип, установленный на плате, найти не удалось. Правда, все же удалось отыскать ПО, позволяющее обновлять его. Кроме того, есть небольшой datasheet на старшую модель ASM1053.

USB

Адаптер при подключении к компьютеру отображается как запоминающее USB-устройство. Я решил, что для исследования мне наверняка пригодятся более глубокие знания о USB, поэтому следующие пару часов я потратил на изучение интерфейса.
Вообще, USB-устройства могут быть разных классов в зависимости от их функциональности. Например, флешки – это Mass Storage Device, а клавиатуры и мышки – Human Interface Device (HID). И раз мой адаптер виден в диспетчере устройств как запоминающее устройство, значит он определяется в виде Mass Storage и должен работать со SCSI-командами.

Основная литература по USB, которая пригодилась

Чтение памяти из ПЗУ

Так как про ASM1053, установленный на плате, ничего не известно, самым очевидным действием было считать память из ПЗУ. Я перебрался в лабораторию. Паяльным феном отделил микросхему флеш-памяти, подключил ее к USB-программатору ChipProg-48. Проблем при чтении не возникло, и у меня на руках оказался бинарный файл. На тот момент я не смог сказать, что находилось на флешке, и начал анализ полученных данных.

Анализ бинарного файла

Первым делом я открыл дамп памяти из ПЗУ с помощью WinHex, но можно воспользоваться любым HEX-редактором. Начал присматриваться к байтам:

Реверс USB-SATA-адаптера (история одного стажера) - 4

Начало дампа памяти, считанного из ПЗУ

На рисунке выше приведен скриншот из редактора. Сразу бросается в глаза строка ASMT1051, которая начинается с адреса 0х44. Также можно увидеть строчку asmedia с адреса 0х18. Для первичного анализа данных я использовал инструмент частотного анализа, который доступен в WinHex.

Реверс USB-SATA-адаптера (история одного стажера) - 5

Гистограмма частотного анализа памяти ПЗУ

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

  • 0x02;
  • 0x74;
  • 0x90;
  • 0xA3;
  • 0xE0;
  • 0xF0.

Можно было бы подтвердить мое предположение, что в ПЗУ находится прошивка. Простой способ это сделать – пробовать сравнивать опкоды (opcode) различных архитектур, подходящих для микроконтроллеров (далее – МК), с байтами, часто встречающимися в памяти.

Если грубо прикинуть, то очень часто в любом коде на ассемблере должны встречаться такие команды, как:

  • mov;
  • jmp;
  • call;
  • ret.

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

Мне пришлось перебрать несколько наборов инструкций для различных ядер, прежде чем нашлись подходящие. Сравнение с архитектурой Intel 8051 дало весьма правдоподобный результат. Опкоды некоторых команд совпадают с популярными байтами из файла, например:

  • 0x02 – LJMP addr16;
  • 0x74 – MOV A, #immed;
  • 0x90 – MOV DPTR, #immed;
  • 0xA3 – INC DPTR;
  • 0xE0 – MOVX A, @DPTR;
  • 0xF0 – MOVX @DPTR, A.

Действительно похоже, что в ПЗУ находится прошивка для МК. Можно было бы сразу прогрузить бинарник в дизассемблере IDA Pro, но за обедом один из коллег поинтересовался:

«А ты уверен, что код в памяти начинается именно с нулевого адреса?»

И правда, нужно учесть, что в памяти может лежать какой-то «мусор» или данные с адреса 0х00.

В общем, передо мной встала задача определения начального адреса кода. Для достижения этой цели лучше всего было воспользоваться SPI-эмулятором EM100. Эмулятор заменяет микросхему памяти на плате, с ним нет необходимости выпаивать ПЗУ каждый раз при прошивке, кроме того, EM100 может записывать лог обращений к памяти. Учитывая, что прошивка из ПЗУ уже прочитана, теперь можно загрузить ее в SPI-эмулятор. Далее эмулятор нужно припаять к плате адаптера и записать лог при подключении адаптера по USB к ПК.

Реверс USB-SATA-адаптера (история одного стажера) - 6

SPI-эмулятор припаян к плате USB-SATA-адаптера

Я припаял проводки от эмулятора на контактные площадки от флеш-памяти и прошил эмулятор считанной прошивкой. Теперь остается посмотреть, обращается ли МК к памяти, и если да, то по каким адресам.

Реверс USB-SATA-адаптера (история одного стажера) - 7

Лог обращений к памяти ПЗУ (получен при помощи ПО SPI-эмулятора)

На рисунке выше видно, что при подключении питания к адаптеру контроллер ASM1051, установленный на плате, отправляет несколько команд 0x03 (Read Data).

Первым делом ASM1051 считывает байт 0x80, начиная с адреса 0x0000. Следом – два байта, начиная с адреса 0x0080, потом еще два байта с адреса 0x8082. После чего считывает большую часть памяти из ПЗУ, начиная с адреса 0x0082.

Можно предположить, что большое количество байтов, которые читаются из ПЗУ последними, начиная с адреса 0x0082, наверное, и есть код. Что и зачем запрашивается до этого – пока не ясно. Известно только то, что в ответ на первый запрос ASM1051 получит от флеш-памяти строки, которые отмечены на рисунке выше. Они как раз были расположены в первых 0x80 байт.

Настало время проверить догадку, что во внешней памяти на плате находится прошивка для МК с ядром 8051, а сам код расположен с адреса 0x0082. Открываем дамп памяти в IDA Pro, указываем Processor type Intel 8051 и offset для кода 0x0082.

Реверс USB-SATA-адаптера (история одного стажера) - 8

Бинарный файл открыт в IDA Pro со смещением 0x82

С открытием бинарника в дизассемблере проблем не возникло.

Выводы:

  1. МК ASM1051 имеет архитектуру 8051.
  2. В ПЗУ есть код, который начинается с адреса 0х82. Кроме кода есть что-то еще.
  3. Первые 0х80 байт чем-то привлекают внимание.

Анализ кода

Теперь, когда я убедился, что код в IDA загружен верно, можно начать анализировать его и параллельно комментировать.

В ходе исследования кода находились простые функции, такие как вычитание 32-битных чисел, попадались различные обработчики, похожие на switch () в С. Мелькали и очень простые функции вроде сохранения значения из регистра R7 в память по какому-то адресу. Самые значимые находки я опишу ниже.

Находка № 1

Интересно, что в ответ на мой запрос INQUIRY (SCSI-команда) я получил ответ, содержащий две строки, которые мы видели в начале памяти ПЗУ. Я, конечно, тут же изменил эти строчки в памяти эмулятора, ожидая при запросе INQUIRY увидеть то, что я написал. Такая наивная мечта быстро рухнула. Теперь же в ответ на команду я видел другую строку, ASM1051 не запрашивал большую часть памяти у ПЗУ. МК читал только первые 0х80 байт и все. В архитектуре 8051 может использоваться масочная (аппаратная) прошивка, видимо, ASM1051 начинал загружаться с нее.

Так стало понятно, что первые 0х80 байт действительно важны, а менять их просто так не получится. Я решил подробнее изучить запросы, которые делает МК по SPI до загрузки кода.

Реверс USB-SATA-адаптера (история одного стажера) - 9

SPI-запрос данных в ПЗУ

Интересным показались два запроса двух байтов. Поиск в IDA 0х00, 0х80 и 0хEB дал огромное количество результатов, которые анализировать я не стал, а вот байт 0х5А попадался реже.

Реверс USB-SATA-адаптера (история одного стажера) - 10

Сравнение с байтом 0х5А. Подсчет checksum-8

Буквально шестой клик привел меня к участку кода, изображенному на рисунке выше. Видно, что значение из регистра с адресом 0х807E сравнивается с 0х5А. Потом считывается checksum-8 для значений, расположенных с адреса 0х8004 до 0х807E. Далее значение по адресу 0х807F сравнивается с полученной ранее суммой.

Реверс USB-SATA-адаптера (история одного стажера) - 11

Начало памяти в ПЗУ

Такие смещения напомнили начало дампа памяти из ПЗУ. На рисунке выше видно, что в адресе 0х7Е находится байт 0x5A. А если посчитать checksum-8 для байтов с позиции 0х04 до 0х7E, то получим 0хА7, а такое значение как раз лежит по адресу 0х7F.

Аналогичным образом удалось найти и подсчет чек-суммы для байтов с адреса 0х0082 до 0х807F (видимо это весь код), которая сверяется с байтом по адресу 0х8083. А по адресу 0х8082 снова лежит значение 0х5А.

Да, это уже чуть сложнее, чем просто менять строчки в памяти. Их я тоже поменял, но и чек-суммы для нового файла посчитал и записал в нужные места. После этого в ответ на SCSI-команду INQUIRY я увидел свои строчки.

Выводы:

  1. Во время загрузки ASM1051 пытается загрузить код из ПЗУ.
  2. Первым делом ASM1051 сравнивает байт checksum-8 с адреса 0х04 до 0х7E со значением по адресу 0х7F.
  3. Если сравнение чек-суммы для преамбулы проведено успешно, то можно считать ее для «кода» (адреса с 0х0082 до 0х807F). Эту сумму ASM1051 сравнивает со значением по адресу 0х8083 и проверяет, что по адресу 0х8082 находится байт 0х5А.
  4. Если все проверки верны, то ASM1051 загружается из ПЗУ, в противном случае использует масочную прошивку.

Находка № 2

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

Реверс USB-SATA-адаптера (история одного стажера) - 12

Функция PRINTF в IDA Pro

Сама функция была представлена на рисунке выше. Давайте разберемся с ней. Первым делом нужно переместить значение из регистра с адресом 0x7F6 в аккумулятор. Если там оказался ноль, то выходим из функции. Самое интересное происходит, если там окажется не ноль. Тогда значение регистра R7 перемещается в регистр с адресом 0xC001, а, как мы помним, перед вызовом этой функции в R7 записывается печатный символ. Далее следует проверка, равно ли значение в R7 коду символа «.» или «-», если нет, то выходим из функции. А вот если сравнение оказалось удачным, то функция берет значение из регистра с адресом 0x16A и перемещает его в 0xC001, но делает это хитро. Например, вместо байта 0х41 (символ «А» в ASCII) функция переместит в 0хС001 байт 0х34 (символ «4» в ASCII), а потом 0х31 (символ «1» в ASCII). Снова выходим из функции.

Я выяснил, что проверка в начале функции не может быть пройдена, так как регистр с адресом 0x7F6 инициализируется нулем, потом в коде не изменяется. То есть данная функция отключена программистом, хотя и осталась скомпилированной. То, что в регистр 0хСС01 только записываются байты (а иногда по два подряд), натолкнуло на мысль, что это, скорее всего, аппаратный регистр.

Все это напоминает UART. Чтобы выяснить, так ли это, необходимо сделать следующее:

  1. Определить ножки на ASM1051, куда выведен UART.
  2. Определить параметры UART (скорость, четность, количество стоп-битов).
  3. Хорошо бы включить UART в коде (судя по всему, он выключен).

Выглядит все достаточно просто: можно по очереди прикасаться к ножкам логическим анализатором и искать ту, на которой будет виден момент посылки UART. При наличии сигнала скорость можно определить по времени импульсов. С остальными параметрами тоже все понятно, достаточно лишь увидеть момент посылки байта на анализаторе.

Чтобы «включить» данную функцию, можно записать нули вместо первых трех строк, где выполняется проверка значения в регистре с адресом 0х7F6. Для этого еще раз открываю прошивку в WinHex.

Реверс USB-SATA-адаптера (история одного стажера) - 13

Выделены шесть байтов, которые нужно обнулить

В редакторе меняю нужные шесть байтов на нули. Теперь прошивка готова и ее можно загрузить в эмулятор ПЗУ. Если предположить, что функция для вывода байтов в UART включена, а ее вызов расположен очень часто по всему коду, то можно ожидать, что байты должны «полететь» из UART при работе адаптера. Надеюсь увидеть трейсер, который сигнализирует байтами в UART о том, какая часть кода исполняется.

Как я уже писал выше, для того чтобы найти нужные ножки Rx и Tx, можно смотреть логическим анализатором по очереди все. Однако я предположил, что Rx и Tx на ASM1051 находятся там же, где и у ASM1053 – ножки 40 и 41 соответственно. Прикладываю щуп анализатора к пину 41 (предполагаемый Tx) и вижу что-то похожее на искомый сигнал:

Реверс USB-SATA-адаптера (история одного стажера) - 14

Временная диаграмма с ножки 41 – Tx

Для того чтобы подключить преобразователь USB-UART и наблюдать в терминале приходящие печатные символы, пришлось припаять два тонких проводка прямо на плату адаптера и закрепить термоклеем.

Реверс USB-SATA-адаптера (история одного стажера) - 15

Два проводка припаяны к RX и TX

Немного изучил диаграмму с рисунка «Временная диаграмма с ножки 41 – Tx»: время одного импульса, судя по всему, – 1 мкс, а для шести бит – 6,3 мкс. Пересчитав значение в боды, получил около 950000 бод, ближайшая стандартная скорость UART – 921600 бод. Думаю, такое расхождение получается из-за погрешности измерения логическим анализатором, я взял не самый достойный аппарат, а китайского «малыша». После установки параметров в окне программы Terminal 1.9b я смог наблюдать приходящие байты с МК ASM1051 во время его работы.

Реверс USB-SATA-адаптера (история одного стажера) - 16

Окно программы Terminal 1.9b во время работы адаптера

Вывод:

В МК ASM1051 есть аппаратный модуль UART. Регистр для отправки данных имеет адрес 0хСС01. Скорость передачи данных – 921600 бод. Имеется один стоп-бит. Ножка 41 – Tx, а 40 – Rx (хотя это не точно).

Находка № 3

Листая код в дизассемблере, добавляя комментарии, можно найти конструкции сложнее, чем запись числа в регистр. Так мне попался интересный обработчик, часть которого на С, выглядела как switch ().

Реверс USB-SATA-адаптера (история одного стажера) - 17

Обработчик команды из регистра с адресом 0x800F

Понимая, что где-то обязательно должны обрабатываться SCSI-команды, я стал среди них искать байты, с которыми на рисунке выше сравнивается содержимое регистра с адресом 0x800F. Оказалось, что первые четыре ветки проверяют команды Read(10), Write(10), Read(16), Write(16). Сомнений в том, что это обработчик команд SCSI, больше не осталось. Далее я просмотрел функцию, которая вызывается в случае, если пришедшая команда не Read/Write (u_Switch). Она, в зависимости от байта в регистре с адресом 0x16A (значение взято из 0x800F), считывает адрес, на который мы попадем при выходе их этой функции. Это похоже на switch ().

Реверс USB-SATA-адаптера (история одного стажера) - 18

Switch SCSI-команд

Так как я уже определил байт, с которым сравниваю пришедшую в адаптер SCSI-команду, то быстро расставил соответствие адресов по командам. Так, например, на рисунке выше видно, что если бы в регистре с адресом 0x16A оказался байт 0x1A, то после выхода из функции u_Switch мы бы перешли по адресу 0x1B85. Интересно, что не все байты, с которыми происходит сравнение в u_Switch, были определены в стандарте SCSI. То есть адаптер может обработать байты 0хЕ6 или 0xDF, но они не закреплены стандартом.

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

Реверс USB-SATA-адаптера (история одного стажера) - 19

Страница 13 из Universal Serial Bus Mass Storage Class

Обратим внимание на смещение 0x0F относительно адреса 0x8000. Перед обработчиком именно из регистра с адресом 0x800F считывается команда SCSI. Если внимательно прочитать таблицу на рисунке выше, то можно увидеть, что в Command Block Wrapper (CBW) поле CBWCB тоже имеет смещение 0x0F. Получается, что адреса RAM-памяти ASM1051, начиная с 0x8000, могут быть USB-буфером, как показано в таблице ниже.

Адрес памяти Описание
0х8000-0х8003 dCBWSignature (USBC – в случае получения пакета)
0х8004-0х8007 dCBWTag
0х8008-0х800B dCBWDataTransferLength
0х800C bmdCBWFlag
0х800D bCBWLUN
0х800E bCBWCBLength
0х800F-0х801F CBWCB – SCSI-команда и ее параметры

На рисунке ниже показан участок кода, где происходит сравнение со строкой USBC (такой должна быть сигнатура dCBWSignature) и расположена предполагаемая сигнатура с адреса 0х8000. Думаю, этого достаточно, чтобы убедиться в том, что USB-буфер расположен в RAM-памяти начиная с 0х8000.

Реверс USB-SATA-адаптера (история одного стажера) - 20

Проверка поля dCBWSignature на совпадение со строкой USBC

Выводы:

  1. МК ASM1051 умеет обрабатывать не только SCSI-команды, которые описаны в стандарте.
  2. Начальный адрес USB-буфера – 0х8000. SCSI-команда располагается в регистре с адресом 0х800F, значит дальше будут приходящие данные/аргументы команд.

Находка № 4

Зная, что МК может обработать нестандартные команды, захотелось узнать, что же они делают. Большинство из них мне достаточно быстро покорилось. Не буду приводить исследование кода этих команд, так как это долго и может быть материалом для отдельной статьи с названием «Ассемблер – это просто», опишу полученные результаты в таблице ниже.

SCSI-команда Описание команды
0хЕ0 Позволяет прочитать первые 0х80 байт из ПЗУ. В дальнейшем эту часть памяти я буду называть преамбулой (да, те самые 0x80 байт, в которых есть строчки asmedia и ASM1051)
0хЕ1 Записывает первые 0х80 байт в ПЗУ
0хЕ3 Записывает в память ПЗУ с 0х80 адреса любое количество байтов. В качестве аргумента (как оказалось) передается размер посылки
0хЕ4 Позволяет прочитать блок байтов RAM-памяти ASM1051. В качестве аргумента принимает начальный адрес и количество байт, которое читаем
0хЕ5 Записывает один байт в RAM по адресу
0хЕ7 Читает последний принятый пакет в ATA-буфер
0хЕ8 Перезагружает устройство

Признаюсь, что не все команды я разгадал путем чтения функций в IDA. Уткнувшись во время исследования в стену, вспомнил, что видел ПО и много прошивок для ASM1051, когда искал документацию на него. С использованием найденного софта можно обновить прошивку и перезагрузить устройство. Поэтому я решил, что самое время воспользоваться Device Monitoring Studio и посмотреть, что же отправляет ПК на адаптер во время обновления.

Таким образом, удалось понять, как происходит процесс обновления прошивки: сначала отправляется преамбула (командой 0xE1), далее командой 0хЕ3 записывается код, затем все это шлифуется перезагрузкой (команда 0хЕ8). Для быстрого и удобного обновления я написал скрипт на Python, который вставляет в преамбулу нужные строки, затем считывает чек-суммы и обновляет устройство. Теперь мне уже не нужен эмулятор, я получил возможность заливать прошивку в ASM1051 через USB, можно вернуть родное ПЗУ на плату.

Выводы

Чтобы обновить прошивку, необходимо выполнить последовательно три SCSI-команды: 0xE1, 0хЕ3 и 0хЕ8.

Находка № 5

Кроме недокументированных команд, было интересно взглянуть на обработчики стандартных команд.

Реверс USB-SATA-адаптера (история одного стажера) - 21

Перемещение третьего бита из регистра 0хС884 в седьмой бит регистра 0x8002

В обработчике SCSI-команды MODE SENSE(10) есть одна интересная проверка. На рисунке выше показана часть кода функции. Видно, что из регистра 0хС884 происходит чтение третьего бита. Потом значение этого бита выставляется в регистр по адресу 0х8002.

Интересно тут то, что регистр 0хС884 нигде в коде не инициализируется, значит, скорее всего, он аппаратный.

Реверс USB-SATA-адаптера (история одного стажера) - 22

Таблица 362 из SCSI Commands Reference Manual

Кроме того, если посмотреть документацию на SCSI-команду 0х5А (MODE SENSE), становится ясно, что USB-SATA-адаптер должен отвечать на запрос MODE SENSE. Третий байт ответа содержит седьмым битом WP (Write Protect – защита от записи). Кстати, запись седьмого бита в 0х8002 я уже видел, да и смещение от начала USB-буфера (0х8000) тут как раз 3.

Вывод:

Исследуемый USB-SATA-адаптер считывает третий бит из аппаратного регистра по адресу 0хС884 и отправляет его на USB-хост как бит WP.

Находка № 6

Аппаратный регистр, найденный во время исследования обработчика SCSI-команды MODE SENSE, очень похож на GPIO. Чтобы это подтвердить, я решил прикасаться к ножкам ASM1051 резистором под напряжением и читать значение регистра (SCSI-командой 0хЕ4) с адресом 0хС884. Для этого я написал скрипт на Python, использующий кастомные SCSI-команды, который мониторит значение в регистре 0хС884 и выводит его на ПК.

Биты 0xC884 7 6 5 4 3 2 1 0
Ножка ASM1051 37 9 10 45 44

После проведения подобного эксперимента я составил таблицу, в которой отобразил, какие биты в регистре 0хС884 изменялись при касании ножек ASM1051 резистором. Получается, что исследуемый регистр тесно связан с GPIO, но попытка записи в него (SCSI-командой 0хЕ5) успехом не увенчалась – значение не менялось.

Тогда я решил, что этот регистр либо только для чтения, либо где-то запрещается в него запись на аппаратном уровне. Если бы, например, ножки МК были изначально настроены только на чтение, тогда, наверное, и запись в регистр 0хС884 могла бы быть недоступна.

В общем, для того чтобы найти регистры, связанные с GPIO, я пробежался по коду начальной инициализации МК. Выписал все регистры, адреса которых близки к 0хС884. Таких у меня получилось около 10. Напоминаю, что десятая ножка МК подключена к светодиоду на плате, она соответствует второму биту в регистре 0хС884. Это сократило список из десяти подозреваемых регистров до одного – 0хС880, так как в нем устанавливается второй бит во время инициализации МК (видимо, пин настраивается как выход). Факт интересный, но мое предположение, что регистр 0хС880 отвечает за настройку направления порта (вход/выход), а регистр 0хС884 содержит значение порта, нужно все-таки проверить.

Во время работы адаптера я записал единички в 0хС880 на места тех битов, которые в регистре 0хС884 связаны с ножками МК. После этого изменение регистра 0хС884 стало возможным. К тому же его изменение соответствовало логическим уровням на ножках ASM1051.

Вывод:

Есть возможность использовать GPIO на ASM1051. Регистр с адресом 0хС880 содержит настройку вход/выход для порта I/O. Регистр 0хС884 содержит значение порта I/O.

Находка № 5. Продолжение

После исследования GPIO-регистров стало ясно, что 45-я ножка МК связана с первым битом в регистре с адресом 0хС884. Именно первый бит из этого регистра влияет на значение бита WP, который отправляется по USB. Теоретически можно попробовать менять значение на 45-й ножке МК и ожидать, что запись на HDD, подключенный через адаптер к ПК, будет невозможна.

Реверс USB-SATA-адаптера (история одного стажера) - 23

Попытка изменить текстовый файл на HDD, после подачи логической единички на 45-ю ножку МК

Проверить это было совсем просто. Тем же резистором я подтянул к GND 45-ю ножку МК и попробовал открыть файл, внести изменения и сохранить на HDD. Результат представлен на рисунке выше.

Вывод

Воздействием на 45-ю ножку ASM1051 можно включать и выключать защиту от записи на HDD.

Разработка собственного устройства

На этом этапе я закончил исследование USB-SATA-адаптера. Во время реверса ПО была найдена возможность удобного обновления прошивки ASM1051. Также я узнал, какие чек-суммы нужно посчитать, чтобы МК принял новую прошивку. Мне стало известно, как настраивать и управлять GPIO. А самое интересное – на ASM1051 есть ножка, при воздействии на которую можно защитить от записи HDD. Учитывая, что профильное направление, по которому я учусь («Проектирование и технология производства электронной аппаратуры»), тесно связано с разработкой электроники, было решено, что часть стажировки я могу посвятить разработке собственного USB-SATA-адаптера на основе ASM1051.

Признаюсь, что на первой итерации разработки платы была допущена ошибка с footprint для ASM1051, так как я взял размеры из datasheet на ASM1053. Он оказался немного меньше МК, но для проверки работы устройства я припаял ASM1053 на коротких проводках.

Реверс USB-SATA-адаптера (история одного стажера) - 24

ASM1051 припаян на проводках к плате

Старшие коллеги мне напомнили, что следовало бы для начала создать 3D-модель платы, а затем собрать образец.

Реверс USB-SATA-адаптера (история одного стажера) - 25

3D-модель разработанной платы и фотография собранного образца

В данное устройство была добавлена кнопка с фиксацией для управления функцией WP. Неиспользуемые GPIO ASM1051 выведены на внешний разъем так же, как и UART. Кроме того, добавлена кнопка отключения питания для SATA, чтобы была возможность перезагрузки HDD. Неудобный и вечно вываливающийся разъем USB 3.0 Micro-B заменен на более современный Type-C. Некоторым HDD может быть мало питания по USB, а для HDD 3.5" необходимо +12 В, поэтому на разработанной плате есть возможность подключать внешнее питание от 12 до 21 В. Ниже представлена фотография собранного устройства.

Реверс USB-SATA-адаптера (история одного стажера) - 26

Фотография разработанного устройства в корпусе

Заключение

В завершение этого наивного для профессионалов повествования, хотелось бы подвести небольшой итог моей стажировки.

За очень короткое время мне удалось немного проникнуть за кулисы реверс-инжиниринга, область не очень освещенную, но жутко интересную. Большим плюсом стажировки был дружный и высококвалифицированный коллектив «НТЦ «Вулкан», который всегда мог помочь и пролить свет на интересующие темы. На меня было потрачено много сил и времени, за что всем причастным выражаю огромные благодарности.

Как мне кажется, я прошел все (ну, или почти все) этапы исследования embedded-устройств. Конечно, мне помогали, направляли и наставляли намного более опытные исследователи. Все время меня не покидало чувство, что знаю я мало, а необходимо знать все, наверное, именно поэтому направление реверса стало столь желанным для меня.

За время стажировки я прочитал много документов, стандартов и datasheets, пытался выцепить важные вещи, чтобы их применять. Но уже на второй неделе я понял, что в реверсе важно ВСЕ!

Автор: RaccoonSecurity

Источник


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


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