Как найти uart на плате

Введение

В этом посте мы расскажем об UART, UBoot и USB, а нашей целью станет игровой автомат Arcade 1UP Marvel. Серия автоматов Arcade 1Up предоставляет возможность за приемлемую цену приобрести домашнюю аркадную машину. С момента выпуска этих автоматов появилось множество модов, демонстрирующих, как заменить внутренние компоненты автомата для запуска стандартного ПО MAME. В посте мы исследуем оборудование автомата и узнаем, как извлечь его прошивку.

Задачи

В этом посте мы раскроем следующие темы:

  • Разборка встроенной системы
  • Идентификация компонентов по маркировкам на печатных платах
  • Измерение напряжений на ножках при помощи мультиметра
  • Использование и настройка логического анализатора
  • Анализ и просмотр UBoot
  • Скриптинг взаимодействий с UBoot при помощи depthcharge

Цель этой статьи заключается в том, чтобы познакомить читателей с процессом нахождения активного UART в системе, работой с консолью UBoot и в конечном итоге использованием этих компонентов для извлечения флэш-памяти из системы. Прочитав статью, вы познакомитесь с утилитой screen из библиотеки depthcharge python3.

Краткое описание оборудования

При изучении новой платформы одна из первых задач заключается в анализе доступных интерфейсов. В случае этого аркадного автомата поначалу кажется, что набор интерфейсов очень ограничен. Пользователи взаимодействуют с устройством посредством джойстика/кнопок и USB-разъёмом на боковой панели автомата. Похоже, относительно USB-разъёма существует довольно мало информации. Стоит заметить, что даже на фотографиях с сайта производителя USB-разъёма нет. Однако наличие разъёма для USB-устройств подразумевает поддержку внешних контроллеров. На другой стороне устройства есть стандартный разъём для наушников. Эти два периферийных разъёма ведут себя как положено — к USB-разъёму можно подключить внешний контроллер, да и разъём наушников работает в соответствии с описанием.

Интересный факт: на некоторых старых мобильных телефонах можно было настроить аудиоразъём так, чтобы при запуске он работал в качестве последовательного терминала. Подробнее об этом можно прочитать здесь. К сожалению, подобные модификации не работают на нашей платформе.

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

Разборка автомата

Внутри автомат практически пуст, если не считать прикреплённого к экрану металлического корпуса.

Под металлической крышкой находится основная печатная плата автомата; аккуратно сняв дополнительную металлическую накладку, мы видим следующее:

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

На этой компоненте написано Rockchip RK3128. Если поискать этот артикул онлайн, мы найдём очень много информации; информация ниже взята из вики Rockchip

  • CPU
    • четырёхъядерный процессор ARM Cortex-A7MP Core, высокопроизводительный, с низким энергопотреблением и кэшированием приложений
    • Полная реализация набора команд v7-A архитектуры ARM, поддержка ARM Neon Advanced SIMD (single instruction, multiple data) для ускорения медиавычислений и обработки сигналов
  • GPU
    • ARM Mali400 MP2
    • высокопроизводительный, с поддержкой OpenGL ES1.1, 2.0, OpenVG1.1 и т. д.
  • Память
    • 8 КБ внутренней SRAM
    • Dynamic Memory Interface (DDR3/DDR3L/LPDDR2):совместим с DDR3-1066/DDR3L-1066/LPDDR2-800 SDRAM стандарта JEDEC. Поддерживает 32-битную ширину данных, 2 ранга (выбирается чипом), общее адресное пространство размером 2 ГБ (максимум).
    • Интерфейс Nand Flash: поддерживает 8-битные async/toggle/syncnandflash, до 4 банков, 16-битную, 24-битную, 40-битную, 60-битную аппаратную ECC
    • Интерфейс eMMC: совместимый со стандартным интерфейсом eMMC, поддерживает протокол MMC4.5
  • Видео
    • Декодер видео MPEG-1, MPEG-2, MPEG-4,H.263, H.264, H.265, VC-1, VP8, MVC в реальном времени
  • Аудио
    • I2S/PCM с 8 каналами: до 8 каналов (8xTX, 2xRX). Разрешение аудио от 16 бит до 32 бит. Частота сэмплирования до 192 кГц
    • I2S/PCM с 2 каналами: до 2 каналов (2xTX, 2xRX). Разрешение аудио от 16 бит до 32 бит. Частота сэмплирования до 192 кГц
  • Разъёмы
    • Контроллер SPI: один встроенный контроллер SPI на чипе
    • Контроллер UART: 3 контроллера UART на чипе
    • Контроллер I2C: 4 контроллера I2C на чипе
    • USB Host2.0: встроенные интерфейсы 1 USB Host 2.0
    • USB OTG2.0: совместимый со спецификацией USB OTG2.0. Поддерживает режимы high-speed (480 Мбит/с), full-speed (12 Мбит/с) и low-speed (1,5 Мбит/с).

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

Непосредственно рядом с CPU есть ещё один компонент, на изображении ниже выделенный оранжевым.

SRAM

Этот компонент имеет маркировку SEC931 K4B2G1646F-BYMA, и нам повезло найти этот артикул в результатах поиска на веб-странице Samsung. Информация на этой странице сообщает нам, что это чип DDR3 SDRAM на 2 ГБ. На той же странице можно скачать даташит; при подобной работе всегда стоит собирать даташиты, если они доступны. Этот чип отвечает за расширение доступной для CPU памяти и обеспечение источника энергозависимой памяти (ОЗУ).

Пока мы выявили то, что скорее всего является основным CPU и внешней ОЗУ. Однако мы пока не знаем тип энергонезависимой памяти. Поэтому далее давайте исследуем компонент, выделенный на изображении розовым.

Этот компонент имеет маркировку Winbond 25N01GVZEIG, поиск такого артикула приводит нас к этому даташиту. Это устройство является последовательным чипом флэш-памяти SLC NAND на 1 Гбит. Согласно даташиту, этот чип использует Serial Peripheral Interface и совместим с диапазоном напряжений от 2,6 В до 3,3 В. С большой вероятностью в этом чипе хранится основной массив данных, используемых автоматом, и он будет нашей основной целью для извлечения прошивки.

Последний компонент находится рядом с линиями GPIO и имеет маркировку MIX2018A. Он непохож на другие тем, что про него я не смог найти почти никакой информации. Однако, судя по информации на нескольких сайтах, эта интегральная схема является звукоусилителем. Во всех источниках про это устройство, которые мне удалось найти онлайн, оно называется именно так, поэтому будем пока считать, что в этом и заключается его функция.

Итак, повторим компоненты, которые мы обнаружили:

  1. ARM CPU Rockchip RK3128
  2. Чип Samsung SRAM
  3. Флэш-память Winbond NAND на 1 Гбит
  4. Звукоусилитель MIX2018A

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

Анализ разъёмов

Задокументировав все дискретные компоненты материнской платы, мы попытаемся распознать её внешние разъёмы. Во-первых, у нас есть круглый разъём, показанный на изображении внизу синим цветом:

Этот разъём используется для подачи питания на автомат.

Справа от круглого разъёма есть разъём micro-USB. Это сразу вызывает удивление по двум причинам:

  1. Это разъём не для пользователя
  2. Это не разъём USB-хоста; это разъём micro, намекающий на USB-устройство или, возможно, на контроллер OTG (on the go)

Ещё правее находится два ряда контактов. Они были подключены к серому гибкому шлейфу, показанному на предыдущих изображениях. Этот разъём соединяется с отдельной платой управления и используется для управления джойстиками/кнопками.

После разъёма платы управления есть ещё один четырёхконтактный разъём. Не совсем очевидно, куда он ведёт. Например, этот разъём может вести к USB-разъёму или к разъёму для наушников. Мы можем попробовать определить это при помощи мультиметра и прозвонки цепи. Прозвонка позволяет проверить, может ли течь ток между двумя щупами и обычно обозначается на мультиметре одним из следующих символов:

Мы можем использовать эту модель для проверки того, соединены ли два компонента. Я вставил в разъём для наушников кабель и прижал щуп к одному из металлических колец, чтобы проверить соединение. Другим щупом я касался каждой точки четырёхконтактного разъёма и на одной из линий мультиметр издал громкий писк, сообщая, что между этими двумя точками есть соединение. Каждый из трёх контактов совпадал с кольцом на аудиоразъёме; это разъём для наушников!

Далее у нас находится разъём для дисплея:

Рядом с дисплеем расположены два двухконтактных разъёма, один в правом нижнем углу, он используется для питания подсветки самого автомата, а другой идёт к переключателю «вкл./выкл.», находящемуся снаружи металлического корпуса.

Следующий разъём похож на аудиоразъём; это четырёхконтактный соединитель, кабели которого ведут к панели управления. Остался только один интерфейс, который мы пока не рассмотрели: USB-разъём на боковой панели автомата. Если переключить мультиметр на режим прозвонки цепей и проверить контакты этот разъёма с USB-разъёмом, то мы убедимся, что они действительно связаны. Это наш внешний USB-разъём.

Мы разобрались со всеми разъёмами, которые пришлось отсоединить, чтобы лучше видеть плату. Следовательно, исследовать нам осталось не так много. При изучении печатной платы стоит рассмотреть неиспользуемые тестовые площадки или переходные соединения; на изображении ниже я выделил неиспользуемые контакты/площадки.

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

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

Последняя группа площадок выглядит очень похоже на разъёмы, использованные для USB и аудио. Подобные четырёхконтактные соединения неиспользуемых площадок часто являются кандидатами на отладочную консоль через UART; мы исследуем эти контакты и обсудим UART в следующем разделе.


Исследование отладочных контактов

Изучая неизвестные контакты наподобие описанных в предыдущем разделе, я обычно начинаю с замера напряжения. Это можно сделать при помощи наших мультиметров. Чтобы вычислить напряжение на этих площадках, мы переключим мультиметр в режим измерения постоянного тока и будем касаться щупом интересующих нас точек, держа чёрный щуп на точке заземления. Эти контакты имеют следующие показания:

На этих линиях нет напряжения; хоть это нас и разочаровало, но неожиданностью не стало. Если бы передавался активный UART или другой цифровой сигнал, мы бы ожидали увидеть активность в виде колебаний напряжения. Давайте перейдём к другому трёхконтактному разъёму.

При замерах на этом разъёме начинаются резкие колебания на втором контакте, постепенно сводящиеся к 3,3 В; пример того, как выглядят эти колебания, см. в показанном ниже gif:

Примечание: при поиске последовательного разъёма вы не всегда сможете увидеть колебания напряжения такой величины. Колебания напрямую коррелируют с уровнем активности сигнала, то есть если трафик небольшой, то колебания будут небольшими или их вообще не будет. Если вы подозреваете, что нашли контакт UART или какой-то цифровой интерфейс, то всегда стоит проверить его логическим анализатором.

Мы видим то, что может походить на активность сигнала (на основании колебаний напряжения). Далее нам нужно исследовать этот трафик логическим анализатором. Логические анализаторы помогают нам преобразовать эти колебания напряжения в человекочитаемую последовательность единиц и нулей. Для этого мы соединим логический анализатор с двумя интересующими нас точками при помощи показанного ниже переходника «мама-мама»:

Подключив анализатор, мы запустим Pulseview и выберем его в раскрывающемся меню; в приложении это устройство отображается как «Saleae Logic». Для этого анализатора максимальная частота захвата составляет 24 МГц, и именно её мы будем использовать для анализа. Также нам нужно указать количество сэмплов. Я выбрал значение 500G (500 миллиардов).

Мы запустим захват нажатием на Run, а затем включим питание автомата с этими параметрами.

Успех! Мы перехватили какой-то трафик; прежде чем двигаться дальше в Pulseview, давайте подробнее поговорим о том, как работает UART на уровне сигналов. Мы убедились в том, что по этим линиям передаётся некий трафик; далее нам нужно чуть больше узнать о трафике UART и о том, как его анализировать.

UART

UART расшифровывается как Universal Asynchronous Receiver Transmitter. UART — это двухпроводной асинхронный последовательный протокол, позволяющий общаться двум устройствам. Обеим сторонам требуется две линии: Transmit (Tx) и receive (Rx). Во встроенной системе UART может использоваться для множества задач, в том числе для общения с другими процессорами, передачи данных датчиков и доступа к отладке. UART — асинхронный протокол, то есть ему не требуется тактовый сигнал. Вместо этого обе общающиеся стороны настраиваются на общение с определённой скоростью, называемой baud rate. Baud rate измеряется в битах в секунду.

Пакет/передача UART состоит из следующих полей:

Даже зная представленное выше описание пакета, нам сложно определить содержимое перехвата логики. К счастью, в Pulseview есть декодер UART, которым мы можем воспользоваться.

Декодируем трафик UART

С помощью pulseview мы можем попытаться декодировать этот трафик и посмотреть, действительно ли это активный UART. Для подготовки декодера нужно нажать на показанные ниже зелёный и жёлтый символы. Откроется окно выбора декодера, введите в панели поиска uart и выберите декодер UART.

Далее нужно настроить декодер UART. Нам нужно выбрать соответствующие каналы и задать все параметры протокола, необходимые этому декодеру. См. настраиваемые параметры ниже:

Сначала выберем линию Rx как содержащий трафик канал; в нашем случае это будет D1. Во всех остальных полях оставим стандартные значения: 8-битная ширина данных, отключенный контроль чётности и т. п.

Нам нужно определить и указать самостоятельно один параметр: baud rate. Не забывайте, что стороны должны заранее согласовать baud rate; нет никакого этапа согласования/запуска. Нам нужно определить этот baud rate самостоятельно; в противном случае, декодер не будет знать, как правильно парсить эти сигналы. Для определения baud rate мы можем сделать следующее.

  1. Приблизить то, что кажется одним из наименьших импульсов (предположительно, он обозначает передаваемый по проводнику один бит)
  2. Выбрать ширину импульса при помощи маркеров данных в Pulseview, нажать показанную ниже кнопку, чтобы включить их:

  3. После выбора диапазона малого импульса Pulseview автоматически вычислит частоту и выдаст нам показатель в герцах, как показано на скриншоте ниже.

Герц измеряется в тактах на секунду; вспомним, что baud rate измеряется в битах на секунду. Следовательно, если мы выделили один бит, передаваемый по проводнику, и частоту этого импульса, то у нас есть и baud rate.

Согласно Pulseview, вычисленная частота равна 115,384 кГц, что эквивалентно baud rate в 115385 бит/с. Те, кто знаком с консолями отладки, должны заметить, что это очень близко к стандартно используемому baud rate, равному 115200. Так что давайте вставим это значение в декодер и посмотрим, что произойдёт.

На скриншоте ниже мы видим настоящий лог отладки.

У нас есть активный UART и мы наем его baud rate, но теперь нам нужно найти способ взаимодействия с ним. Для этого мы воспользуемся Raspberry Pi. Дополненная схема расположения выводов автомата имеет следующий вид:

Конфигурируем Raspberry Pi

Raspberry Pi имеет множество UART; тот, который мы будем использовать, выделен на изображении ниже:

Чтобы включить этот UART, нам нужно убедиться, что включен блоб дерева соответствующего устройства. Блоб дерева устройства (device tree blob, DTB) необходим для того, чтобы ядро понимало доступную аппаратную периферию. Ядро считывает эту двоичную информацию при запуске и перечисляет указанную периферию. При реверс-инжиниринге встроенной системы на Linux извлечение этой информации может пойти на пользу, потому что её можно декомпилировать и наметить, где в памяти находятся разные устройства.

Все нужные нам блобы дерева устройств в raspberry pi могут находиться в /boot/overlays/. Найдите в этой папке двоичные объекты дерева устройств для различных аппаратных конфигураций, некоторые для конкретных HAT (специализированных печатных плат, спроектированных для Pi), подключаемых к Pi, и другие для включения различной периферии ввода-вывода. Мы можем включить соответствующий DTB для периферии UART при помощи инструмента raspi-config.

Используем Raspi Config

raspi-config — это инструмент пользовательского пространства, позволяющий нам конфигурировать различные аспекты Raspberry Pi, одним из которых является включение различных внешних интерфейсов. Мы воспользуемся raspi-config для включения интерфейса UART; начнём с запуска инструмента:

sudo raspi-config

При этом появится следующий экран:

Далее мы выберем Interface Options, а затем Serial Port, как показано на изображении ниже:

После выбора этой опции отобразится два вопроса:

  1. Would you like a login shell to be accessible over serial? (Сделать login shell доступной через последовательный порт?)
    • No (Нет)
  2. Would you like the serial port hardware to be enabled? (Включить оборудование последовательного порта?)
    • Yes (Да)

Так мы включили UART на Raspberry Pi. Далее нужно подключить его к автомату. Мы подключим Tx автомата к Rx устройства Pi, а Rx автомата — к Tx устройства Pi:

Инструменты UART

При помощи интерфейса UART на Raspberry Pi мы можем попытаться подключиться к этому последовательному порту нашей цели. Для взаимодействия с этим последовательным портом мы будем использовать утилиту screen. При взаимодействии с UART утилите Screen нужно передать устройство и baud rate; так как мы знаем baud rate из предыдущего раздела, то мы запустим screen следующим образом:

sudo screen -L -Logfile cabinet-bootup.log /dev/ttyS0 115200

  • -L -Logfile cabinet-bootup.log — записываем сессию в файл cabinet-bootup.log
  • /dev/ttyS0 — использовать это последовательное устройство
  • 115200 — Baud rate

Теперь мы можем включить питание автомата, сконфигурировав UART и запустив screen. При включении питания автомата мы видим следующее:

И наконец мы оказываемся в консоли:

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

[root@rk3128:/]# mount
/dev/root on / type squashfs (ro,relatime)
devtmpfs on /dev type devtmpfs (rw,relatime,size=103544k,nr_inodes=25886,mode=755)
proc on /proc type proc (rw,relatime)
devpts on /dev/pts type devpts (rw,relatime,gid=5,mode=620,ptmxmode=000)
tmpfs on /dev/shm type tmpfs (rw,relatime,size=112248k,nr_inodes=28062,mode=777)
tmpfs on /tmp type tmpfs (rw,relatime,size=112248k,nr_inodes=28062)
tmpfs on /tmp type tmpfs (rw,nosuid,nodev,relatime,size=112248k,nr_inodes=28062,mode=755)
sysfs on /sys type sysfs (rw,relatime)
debug on /sys/kernel/debug type debugfs (rw,relatime)
pstore on /sys/fs/pstore type pstore (rw,relatime)
/dev/root on /var type squashfs (ro,relatime)
tmpfs on /tmp type tmpfs (rw,nosuid,nodev,relatime,size=112248k,nr_inodes=28062,mode=755)
/dev/rkflash0p5 on /userdata type ext2 (rw,relatime)
none on /sys/kernel/config type configfs (rw,relatime)
adb on /dev/usb-ffs/adb type functionfs (rw,relatime)

Наша файловая система рута смонтирована как read-only и использует формат squashfs. Кроме того, смонтирован ещё один раздел с меткой userdata. Если мы исследуем доступные блочные устройства, то увидим следующее:

[root@rk3128:/]# ls -lathr /dev/block/by-name/
lrwxrwxrwx 1 root root 16 Jan 1 00:00 userdata -> ../../rkflash0p5
lrwxrwxrwx 1 root root 16 Jan 1 00:00 uboot -> ../../rkflash0p1
lrwxrwxrwx 1 root root 16 Jan 1 00:00 trust -> ../../rkflash0p2
lrwxrwxrwx 1 root root 16 Jan 1 00:00 rootfs -> ../../rkflash0p4
lrwxrwxrwx 1 root root 16 Jan 1 00:00 boot -> ../../rkflash0p3
drwxr-xr-x 3 root root 380 Jan 1 00:00 ..
drwxr-xr-x 2 root root 140 Jan 1 00:00 .

Мы видим, что устройство SPI flash предположительно находится в /dev/rkflash0. Чтобы получить образ этого блочного устройства, мы можем подключить USB-накопитель к USB-разъёму автомата и использовать утилиту dd. После вставки USB-накопителя он регистрируется как /dev/sda и мы можем создать на USB-накопитель образ содержимого SPI flash с помощью следующей команды:

sudo dd if=/dev/rkflash0 of=/dev/sda status=progress

Если мы подключим USB-накопитель к Pi и исследуем таблицу разделов, то увидим, что образы соответствующих разделов записались на накопитель!

pi@voidstar:~ $ lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
sda 8:0 1 57.8G 0 disk
├─sda1 8:1 1 4M 0 part
├─sda2 8:2 1 2M 0 part
├─sda3 8:3 1 9M 0 part
├─sda4 8:4 1 80.8M 0 part
└─sda5 8:5 1 8M 0 part

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

CLK: (uboot. arm: enter 600000 KHz, init 600000 KHz, kernel 0N/A)
apll 600000 KHz
dpll 600000 KHz
cpll 650000 KHz
gpll 594000 KHz
armclk 600000 KHz
aclk_cpu 148500 KHz
hclk_cpu 74250 KHz
pclk_cpu 74250 KHz
aclk_peri 148500 KHz
hclk_peri 74250 KHz
pclk_peri 74250 KHz
Net: Net Initialization Skipped
No ethernet found.
Hit key to stop autoboot('CTRL+C'): 0

Если зажать Ctrl-c в командной строке screen при включении питания автомата, то мы увидим следующее:

Hit key to stop autoboot('CTRL+C'): 0
=> <INTERRUPT>

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


UBoot

UBoot — это загрузчик в open-source, часто используемый во встроенных системах. Он имеет поддержку широкого ассортимента архитектур и типов CPU. Однако задача UBoot обычно заключается в загрузке ядра операционной системы или основного приложения встроенной системы.

Также UBoot содержит утилиты, полезные в процессе реверс-инжиниринга; самым примечательным является командная строка UBoot.

Команды UBoot

Консоль UBoot может содержать большое количество встроенных утилит. Эти утилиты можно использовать в процессе стандартной загрузки (часто с помощью переменных среды) или в командной строке UBoot. Набор команд зависит от того как был собран образ UBoot.

Теперь, когда мы обнаружили консоль UBoot, давайте начнём с того, что посмотрим, какие команды публично доступны нам, выполнив help command

android_print_hdr base bdinfo bidram_dump BMP boot boot_android bootavb
bootd bootm bootp bootrkp bootz charge cmp coninfo cp crc32 ...
=>
? - alias for 'help'
android_print_hdr- print android image header
base - print or set address offset
bdinfo - print Board Infostructure
bidram_dump- Dump bidram layout
BMP - manipulate BMP image data
boot - boot default, i.e., run 'bootcmd'
boot_android- Execute the Android Bootloader flow.
bootavb - Execute the Android avb a/b boot flow.
bootd - boot default, i.e., run 'bootcmd'
bootm - boot application image from memory
bootp - boot image via network using BOOTP/TFTP protocol
bootrkp - Boot Linux Image from rockchip image type
Bootz - boot Linux zImage image from memory
charge - Charge display
CMP - memory compare
coninfo - print console devices and information
cp - memory copy
crc32 - checksum calculation
DHCP - boot image via network using DHCP/TFTP protocol
dm - Driver model low level access
download- enter rockusb/bootrom download mode
dtimg - manipulate dtb/dtbo Android image
dump_atags- Dump the content of the atags
dump_irqs- Dump IRQs
echo - echo args to console
editenv - edit environment variable
env - environment handling commands
exit - exit script
ext2load- load binary file from a Ext2 filesystem
ext2ls - list files in a directory (default /)
ext4load- load binary file from a Ext4 filesystem
ext4ls - list files in a directory (default /)
ext4size- determine a file's size
false - do nothing, unsuccessfully
fastboot- use USB or UDP Fastboot protocol
fatinfo - print information about filesystem
fatload - load binary file from a dos filesystem
fatls - list files in a directory (default /)
fantasize - determine a file's size
fatwrite- write file into a dos filesystem
fdt - flattened device tree utility commands
fstype - Lookup a filesystem type
go - start application at address 'addr'
gpt - GUID Partition Table
help - print command description/usage
iomem - Show iomem data by device compatible(high priority) or node name
lcdputs - print string on video framebuffer
load - load binary file from a filesystem
loop - infinite loop on address range
ls - list files in a directory (default /)
MD - memory display
mii - MII utility commands
mm - memory modify (auto-incrementing address)
mmc - MMC subsystem
mmcinfo - display MMC info
MW - memory write (fill)
NFS - boot image via network using NFS protocol
nm - memory modify (constant address)
part - disk partition related commands
ping - Send ICMP ECHO_REQUEST to network host
printenv- print environment variables
pxe - commands to get and boot from pxe files
rbrom - Perform RESET of the CPU
reboot - Perform RESET of the CPU, alias of 'reset'
reset - Perform RESET of the CPU
rkimgtest- Test if storage media have rockchip image
rknand - rockchip nand flash sub-system
rksfc - rockchip SFC sub-system
rktest - Rockchip board modules test
rockchip_show_bmp- load and display BMP from resource partition
rockchip_show_logo- load and display log from resource partition
rocks - Use the rockusb Protocol
run - run commands in an environment variable
save - save file to a filesystem
setcurs - set cursor position within screen
setenv - set environment variables
showvar - print local hushshell variables
size - determine a file's size
source - run script from memory
sysboot - command to get and boot from syslinux files
sysmem_dump- Dump system layout
sysmem_search- Search a available system region
test - minimal test like /bin/sh
TFTP - download image via network using TFTP protocol
true - do nothing, successfully
ums - Use the UMS [USB Mass Storage]
USB - USB sub-system
usbboot - boot from USB device
version - print monitor, compiler, and linker version
=>

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

download- enter rockusb/bootrom download mode
dtimg - manipulate dtb/dtbo Android image
dump_atags- Dump the content of the atags
ext2load- load binary file from a Ext2 filesystem
ext2ls - list files in a directory (default /)
ext4load- load binary file from a Ext4 filesystem
ext4ls - list files in a directory (default /)
ext4size- determine a file's size
fastboot- use USB or UDP Fastboot protocol
fatinfo - print information about filesystem
fatload - load binary file from a dos filesystem
fatls - list files in a directory (default /)
fantasize - determine a file's size
fatwrite- write file into a dos filesystem
mm - memory modify (auto-incrementing address)
rknand - rockchip nand flash sub-system
rksfc - rockchip SFC sub-system
ums - Use the UMS [USB Mass Storage]
USB - USB sub-system

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

Переменные среды UBoot

При сборке или конфигурировании образа UBoot для устройства могут быть настроены различные переменные среды. Эти переменные управляют тем, какие операции выполняются при запуске. Такие переменные могут храниться различным образом. Иногда они жёстко прописаны в самом двоичном файле; также они могут находиться на разделе флэш-памяти, что позволяет пользователям изменять их через командную строку UBoot.

Мы можем исследовать переменные среды при помощи команды printenv:

=> printenv
arch=arm
baudrate=115200
board=evb_rk3128
board_name=evb_rk3128
boot_a_script=load ${devtype} ${devnum}:${distro_bootpart} ${scriptaddr} ${prefix}${script}; source ${scriptaddr}
boot_extlinux=sysboot ${devtype} ${devnum}:${distro_bootpart} any ${scriptaddr} ${prefix}extlinux/extlinux.conf
boot_net_usb_start=usb start
boot_prefixes=/ /boot/
boot_script_dhcp=boot.scr.uimg
boot_scripts=boot.scr.uimg boot.scr
boot_targets=mmc1 mmc0 rknand0 usb0 pxe dhcp
bootargs=storagemedia=nand androidboot.storagemedia=nand androidboot.mode=normal
bootcmd=boot_android ${devtype} ${devnum};bootrkp;run distro_bootcmd;
bootcmd_dhcp=run boot_net_usb_start; if dhcp ${scriptaddr} ${boot_script_dhcp}; then source ${scriptaddr}; fi;
bootcmd_mmc0=setenv devnum 0; run mmc_boot
bootcmd_mmc1=setenv devnum 1; run mmc_boot
bootcmd_pxe=run boot_net_usb_start; dhcp; if pxe get; then pxe boot; fi
bootcmd_rknand0=setenv devnum 0; run rknand_boot
bootcmd_usb0=setenv devnum 0; run usb_boot
bootdelay=0
cpu=armv7
devnum=0
devtype=spinand
distro_bootcmd=for target in ${boot_targets}; do run bootcmd_${target}; done
ethaddr=d2:79:07:fc:f7:89
fdt_addr1_r=0x61700000
fdt_addr_r=0x68300000
kernel_addr1_r=0x62008000
kernel_addr_r=0x62008000
mmc_boot=if mmc dev ${devnum}; then setenv devtype mmc; run scan_dev_for_boot_part; fi
pxefile_addr1_r=0x60600000
pxefile_addr_r=0x60600000
ramdisk_addr1_r=0x63000000
ramdisk_addr_r=0x6a200000
rkimg_bootdev=if mmc dev 1 && rkimgtest mmc 1; then setenv devtype mmc; setenv devnum 1; echo Boot from SDcard;elif mmc dev 0; then setenv devtype mmc; setenv devnum 0;elif mtd_blk dev 0; then setenv devtype mtd; setenv devnum 0;elif mtd_blk dev 1; then setenv devtype mtd; setenv devnum 1;elif mtd_blk dev 2; then setenv devtype mtd; setenv devnum 2;elif rknand dev 0; then setenv devtype rknand; setenv devnum 0;elif rksfc dev 0; then setenv devtype spinand; setenv devnum 0;elif rksfc dev 1; then setenv devtype spinor; setenv devnum 1;fi;
scan_dev_for_boot=echo Scanning ${devtype} ${devnum}:${distro_bootpart}...; for prefix in ${boot_prefixes}; do run scan_dev_for_extlinux; run scan_dev_for_scripts; done;
scan_dev_for_boot_part=part list ${devtype} ${devnum} -bootable devplist; env exists devplist || setenv devplist 1; for distro_bootpart in ${devplist}; do if fstype ${devtype} ${devnum}:${distro_bootpart} bootfstype; then run scan_dev_for_boot; fi; done
scan_dev_for_extlinux=if test -e ${devtype} ${devnum}:${distro_bootpart} ${prefix}extlinux/extlinux.conf; then echo Found ${prefix}extlinux/extlinux.conf; run boot_extlinux; echo SCRIPT FAILED: continuing...; fi
scan_dev_for_scripts=for script in ${boot_scripts}; do if test -e ${devtype} ${devnum}:${distro_bootpart} ${prefix}${script}; then echo Found U-Boot script ${prefix}${script}; run boot_a_script; echo SCRIPT FAILED: continuing...; fi; done
scriptaddr=0x60500000
scriptaddr1=0x60500000
serial#=c3d9b8674f4b94f6
soc=rockchip
stderr=serial,vidconsole
stdout=serial,vidconsole
usb_boot=usb start; if usb dev ${devnum}; then setenv devtype usb; run scan_dev_for_boot_part; fi
vendor=rockchip

Environment size: 3477/32764 bytes
=>

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

Если на этом этапе мы сопоставим это с информацией, полученной при анализе оборудования, то получим согласованные результаты. После анализа оборудования мы предположили, что основным накопителем является SPI flash, и это предположение подтверждается переменными среды UBoot, а также доступными командами.

Давайте начнём с исследования команд rksfc; гугление подсказывает нам, что это инструмент интерфейса RockChip SPI SFC (serial flash controller). Эта команда имеет следующие подкоманды:

=> rksfc
rksfc - rockchip sfc sub-system

Usage:
rksfc scan - scan Sfc devices
rksfc info - show all available Sfc devices
rksfc device [dev] - show or set current Sfc device
dev 0 - spinand
dev 1 - spinor
rksfc part [dev] - print partition table of one or all Sfc devices
rksfc read addr blk# cnt - read `cnt' blocks starting at block
`blk#' to memory address `addr'
rksfc write addr blk# cnt - write `cnt' blocks starting at block
`blk#' from memory address `addr'


Получить информацию о SPI flash можно при помощи следующих команд:

=> rksfc scan
=> rksfc info
Device 0: Vendor: 0x0308 Rev: V1.00 Prod: rkflash-SpiNand
Type: Hard Disk
Capacity: 107.7 MB = 0.1 GB (220672 x 512)
=> rksfc device 0

Device 0: Vendor: 0x0308 Rev: V1.00 Prod: rkflash-SpiNand
Type: Hard Disk
Capacity: 107.7 MB = 0.1 GB (220672 x 512)
... is now current device
=> rksfc part 0

Partition Map for SPINAND device 0 -- Partition Type: EFI

Part Start LBA End LBA Name
Attributes
Type GUID
Partition GUID
1 0x00002000 0x00003fff "uboot"
attrs: 0x0000000000000000
type: ea450000-0000-424f-8000-0cd500004c0a
guid: 325b0000-0000-4d21-8000-6e10000051c5
2 0x00004000 0x00004fff "trust"
attrs: 0x0000000000000000
type: b44a0000-0000-4121-8000-4e1600002902
guid: 62500000-0000-4f7f-8000-4a7800006ca1
3 0x00005000 0x000097ff "boot"
attrs: 0x0000000000000000
type: 6c1e0000-0000-4833-8000-5d07000065c4
guid: 442c0000-0000-4c4c-8000-2ed400005ecb
4 0x00009800 0x00031dff "rootfs"
attrs: 0x0000000000000000
type: 9b050000-0000-4e44-8000-5f3000007157
guid: 614e0000-0000-4b53-8000-1d28000054a9
5 0x00031e00 0x00035dde "userdata"
attrs: 0x0000000000000000
type: c8050000-0000-4b18-8000-3b1a000041c3
guid: 40780000-0000-493e-8000-688900001525
=>

При помощи этих команд мы можем узнать больше о SPI flash. Мы видим, что его размер блока равен 512 и что чип суммарно содержит 220672 (0x35E00) блока, разбитые на пять разделов:

  • uboot — вероятно, содержит образ UBoot / загрузчик первого этапа
  • trust — образ Trusted execution environment
  • boot — образ ядра / ramdisk
  • rootfs — самый большой раздел, файловая система рута ядра
  • user data — пользовательские данные, скорее всего, используется для записи рекордов, пользовательских настроек и пр.

Обратите внимание, что эти данные совпадают с тем, что мы видели ранее в командной строке консоли рута. Теперь мы знаем, как разбита флэш-память, и какие данные могут быть доступны, но можно ли считывать/записывать эти данные без припаивания дополнительных линий к плате? Изучив команду usb, мы увидим следующее:

=> usb
usb - USB sub-system

Usage:
usb start - start (scan) USB controller
usb reset - reset (rescan) USB controller
usb stop [f] - stop USB [f]=force stop
usb tree - show USB device tree
usb info [dev] - show available USB devices
usb test [dev] [port] [mode] - set USB 2.0 test mode
(specify port 0 to indicate the device's upstream port)
Available modes: J, K, S[E0_NAK], P[acket], F[orce_Enable]
usb storage - show details of USB storage devices
usb dev [dev] - show or set current USB storage device
usb part [dev] - print partition table of one or all USB storage devices
usb read addr blk# cnt - read `cnt' blocks starting at block `blk#'
to memory address `addr'
usb write addr blk# cnt - write `cnt' blocks starting at block `blk#'
from memory address `addr'

Если мы вставим устройство в USB-разъём на боковой панели автомата и выполним USB start, а затем USB info, то получим следующий результат:

=> usb start
starting USB...
Bus usb@10180000: Bus usb@101c0000: USB EHCI 1.00
Bus usb@101e0000: USB OHCI 1.0
scanning bus usb@10180000 for devices... 1 USB Device(s) found
scanning bus usb@101c0000 for devices... RKPARM: Invalid parameter part table
2 USB Device(s) found
scanning bus usb@101e0000 for devices... 1 USB Device(s) found
scanning usb for storage devices... 1 Storage Device(s) found
=> usb info
1: Hub, USB Revision 1.10
- U-Boot Root Hub
- Class: Hub
- PacketSize: 8 Configurations: 1
- Vendor: 0x0000 Product 0x0000 Version 0.0
Configuration: 1
- Interfaces: 1 Self Powered 0mA
Interface: 0
- Alternate Setting 0, Endpoints: 1
- Class Hub
- Endpoint 1 In Interrupt MaxPacket 2 Interval 255ms

1: Hub, USB Revision 2.0
- u-boot EHCI Host Controller
- Class: Hub
- PacketSize: 64 Configurations: 1
- Vendor: 0x0000 Product 0x0000 Version 1.0
Configuration: 1
- Interfaces: 1 Self Powered 0mA
Interface: 0
- Alternate Setting 0, Endpoints: 1
- Class Hub
- Endpoint 1 In Interrupt MaxPacket 8 Interval 255ms

2: Mass Storage, USB Revision 2.10
- USB DISK 3.0 0719146D1CBF9257
- Class: (from Interface) Mass Storage
- PacketSize: 64 Configurations: 1
- Vendor: 0x13fe Product 0x6300 Version 1.0
Configuration: 1
- Interfaces: 1 Bus Powered 498mA
Interface: 0
- Alternate Setting 0, Endpoints: 2
- Class Mass Storage, Transp. SCSI, Bulk only
- Endpoint 1 In Bulk MaxPacket 512
- Endpoint 2 Out Bulk MaxPacket 512

1: Hub, USB Revision 1.10
- U-Boot Root Hub
- Class: Hub
- PacketSize: 8 Configurations: 1
- Vendor: 0x0000 Product 0x0000 Version 0.0
Configuration: 1
- Interfaces: 1 Self Powered 0mA
Interface: 0
- Alternate Setting 0, Endpoints: 1
- Class Hub
- Endpoint 1 In Interrupt MaxPacket 2 Interval 255ms

Превосходно, мы видим, что стек USB успешно регистрируется и распознаёт наш накопитель mass storage device.

Прежде чем двигаться дальше, давайте перечислим то, что мы знаем о нашей среде UBoot:

  1. Изучение переменных среды дало нам используемые адреса в ОЗУ
  2. При помощи утилиты rksfc read мы можем считывать секторы SPI flash в ОЗУ
  3. При помощи команд USB мы можем регистрировать USB-устройство и выполнять на него запись

Можно считать SPI flash в ОЗУ, подключить USB-устройство, а затем записать данные с SPI flash data на USB-устройство при помощи команды USB write. Если это сработает, то мы сможем и восстанавливать образы, выполнив эти операции в обратном порядке: считывать данные с USB-накопителя и записывать их на флэш-память с помощью rksfc write. Давайте начнём с проверки записи.

Сначала мы можем попробовать считать всю SPI flash в ОЗУ при помощи следующей команды. В качестве адреса назначения можно попробовать адрес, сохранённый в $ramdisk_addr_r, то есть 0x6a200000:

=> rksfc read $ramdisk_addr_r 0 0x35E00

spinand read: device 0 block # 0, count 220672 ... undefined instruction
pc : ce695528 lr : 1fadca4d
sp : 6be17bd8 ip : 00000020 fp : 60093204
r10: 00004254 r9 : 6be1bdf8 r8 : ad758c77
r7 : ebaa79cb r6 : b052b720 r5 : 36395b84 r4 : f3a911be
r3 : 780fb750 r2 : 00000000 r1 : 600a62fc r0 : 200a226c
Flags: nZcv IRQs on FIQs off Mode SVC_32

Call trace:
PC: [< ce695528 >]
LR: [< 1fadca4d >]

Stack:
[< ce695528 >]

Copy info from "Call trace..." to a file(eg. dump.txt), and run
command in your U-Boot project: ./scripts/stacktrace.sh dump.txt

Resetting CPU ...

### ERROR ### Please RESET the board ###

Не сработало; каким-то образом мы вызвали undefined instruction exception. Скорее всего, мы поломали что-то, что используется UBoot; давайте посмотрим, что получится, если попробовать другой адрес ниже в памяти:

=> rksfc read $scriptaddr 0 0x35E00

spinand read: device 0 block # 0, count 220672 ... 220672 blocks read: OK

Переход на более низкий адрес в ОЗУ позволил считать всё полностью, ничего не сломав; давайте посмотрим, сможем ли мы теперь записать эти данные на USB-накопитель:

usb write addr blk# cnt - write `cnt' blocks starting at block `blk#'
from memory address `addr'
=> usb write $scriptaddr 0 0x35E00

usb write: device 0 block # 0, count 220672 ... 220672 blocks written: OK
=>

Давайте теперь посмотрим на содержимое этого накопителя, вставив его в Raspberry Pi:

pi@voidstar:~ $ lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
sda 8:0 1 57.8G 0 disk
├─sda1 8:1 1 4M 0 part
├─sda2 8:2 1 2M 0 part
├─sda3 8:3 1 9M 0 part
├─sda4 8:4 1 80.8M 0 part
└─sda5 8:5 1 8M 0 part

Теперь мы видим, что таблица разделов в USB-накопителе совпадает с результатами, выведенными командой rksfc part 0. Далее мы используем утилиту dd, чтобы извлечь отдельные разделы для анализа.

pi@voidstar:~/marvel-cab/parts $ sudo dd if=/dev/sda1 of=part1.bin
4194304 bytes (4.2 MB, 4.0 MiB) copied, 0.18225 s, 23.0 MB/s
pi@voidstar:~/marvel-cab/parts $ sudo dd if=/dev/sda2 of=part2.bin
2097152 bytes (2.1 MB, 2.0 MiB) copied, 0.109297 s, 19.2 MB/s
pi@voidstar:~/marvel-cab/parts $ sudo dd if=/dev/sda3 of=part3.bin
9437184 bytes (9.4 MB, 9.0 MiB) copied, 0.386968 s, 24.4 MB/s
pi@voidstar:~/marvel-cab/parts $ sudo dd if=/dev/sda4 of=part4.bin
84672512 bytes (85 MB, 81 MiB) copied, 2.96481 s, 28.6 MB/s
pi@voidstar:~/marvel-cab/parts $ sudo dd if=/dev/sda5 of=part5.bin
8371712 bytes (8.4 MB, 8.0 MiB) copied, 0.314125 s, 26.7 MB/s
pi@voidstar:~/marvel-cab/parts $ file *
part1.bin: data
part2.bin: data
part3.bin: Android bootimg, kernel (0x10008000), second stage (0x10f00000), page size: 2048
part4.bin: Squashfs filesystem, little endian, version 4.0, xz compressed, 71663599 bytes, 1185 inodes, blocksize: 131072 bytes, created: Mon May 31 09:06:53 2021
part5.bin: Linux rev 1.0 ext2 filesystem data (mounted or unclean), UUID=42185cbc-b698-4af6-8a47-e444e5635787, volume name "userdata" (large files)

Пока данные совпадают и с выводом на запущенной системе, и в таблице разделов из меню UBoot. Следовательно, мы можем извлечь раздел squashfs с помощью unsquashfs и попробовать смонтировать раздел ext2, чтобы убедиться в их правильности:

pi@voidstar:~/marvel-cab/parts $ unsquashfs part4.bin
Parallel unsquashfs: Using four processors
1029 inodes (1792 blocks) to write
create_inode: could not create character device squashfs-root/dev/console, because you're not superuser!
created 596 files
created 157 directories
created 431 symlinks
created 0 devices
created 0 fifos
pi@voidstar:~/marvel-cab/parts $ ls squashfs-root/
bin busybox.config data dev etc lib lib32 linuxrc media misc mnt moo OEM opt proc root run sbin sdcard sys timestamp tmp udisk userdata usr var
pi@voidstar:~/marvel-cab/parts $ ls squashfs-root/moo/
docs logo.mp4 MOO MOO-Ship-MIME_CCADE_MSH_2P-BRK01 SKUShell.MIME_CCADE_SF2_2P.19.exe start.sh _ui assets

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

Убедившись, что мы можем считывать флэш-память, давайте проверим, сможем ли мы записать этот образ обратно при помощи описанного выше способа:

=> usb read $scriptaddr 0 0x35E00
usb read: device 0 block # 0, count 220672 ... 220672 blocks read: OK
=> rksfc write $scriptaddr 0x35E00 0
spinand write: device 0 block # 0, count 220672 ... 220672 blocks written: OK

Перезагрузимся и будем надеяться, что перезаписанный образ будет работать.

Успех! Теперь мы можем считывать/записывать SPI flash из UBoot при помощи USB-накопителя; это будет полезно для тестирования патчей и модификаций прошивки!

Теперь, когда мы научились считывать/записывать флэш-память автомата при помощи UBoot, было бы здорово научиться затирать отдельные разделы и сегменты флэш-памяти автоматически, без необходимости каждый раз вводить интервалы вручную. Для этого мы воспользуемся утилитой Depthcharge, позволяющей оптимизировать взаимодействие с UBoot!

Скриптинг UBoot при помощи Depthcharge

При работе со средами UBoot нам часто бывает нужно автоматизировать наше взаимодействие. В нашем случае, например, нам может потребоваться автоматизация перезаписи определённого раздела во флэш-памяти без необходимости каждый раз вводить смещения адресов. К счастью, ребята из NCC Group создали инструмент depthcharge, который поможет нам в этом. Можно использовать его для автоматизации процесса считывания и записи данных между флэш-чипом и внешним USB-накопителем. Наш скрипт должен уметь делать следующее:

  1. Подключаться к UART и обнаруживать командную строку UBoot
  2. Выполнять считывание и запись в SPI flash с помощю команд rksfc read/write
  3. Выполнять считывание и запись на USB-накопитель при помощи команд USB read/write

Сначала нужно установить модуль; мы можем установить depthcharge на Pi, выполнив sudo pip install depthcharge.

Подключение к UART и обнаружение командной строки UBoot

Мы можем подключиться к командной строке UBoot при помощи следующего кода на python:

def console_setup():
    console=Console("/dev/ttyS0",baudrate=115200)
    ctx = Depthcharge(console,arch="arm")
    return ctx

В представленной выше функции и мы создаём объект Console, требующий, чтобы мы указали путь к последовательному порту и baud rate. Этот объект консоли затем используется для создания контекста Depthcharge, которым мы будем пользоваться для доступа к возможностям Depthcharge. В документации depthcharge есть хорошо описанный пример этого и подробно излагается процесс настройки.

Считывание и запись во флэш-память при помощи depthcharge

Теперь, когда мы подключились к интерфейсу, нам нужно реализовать команды read и write rksfc. Мы можем это сделать при помощи API send_command() утилиты depthcharge. Этот вызов API позволяет нам генерировать и передавать команду UBoot в командную строку и возвращать ответ. В примере ниже мы создаём команду чтения в переменной cmd_str и проверяем правильность форматирования аргументов, а затем отправляем команду при помощи API send_command().

def rksfc_read(ctx,dest_addr,src_addr,size):
    cmd_str = f"rksfc read  0x{dest_addr:02x} 0x{src_addr:02x} 0x{size:02x}"
    resp = ctx.send_command(cmd_str)
    return resp

def rksfc_write(ctx,dest_addr,src_addr,size):
    cmd_str = f"rksfc write 0x{dest_addr:02x} 0x{src_addr:02x} 0x{size:02x}"
    resp = ctx.send_command(cmd_str)
    time.sleep(10)
    return resp

Реализовав считывание и запись флэш-памяти, мы должны теперь зарегистрировать стек USB, а затем выполнять считывание/запись с накопителя.

Считывание и запись на USB при помощи depthcharge

Аналогично тому, как мы реализовали команды rksfc, далее нам нужно реализовать команды usb. Этот процесс будет схож с тем, который мы использовали для команд rksfc:

'''
usb_setup
This script is used to enumerate and set up the USB port
'''
def usb_setup(ctx,reset=False):
    resps = []
    if not reset:
        resp = ctx.send_command("usb start")
    else:
        resp = ctx.send_command("usb reset")
    resps.append(resp)
    resp = ctx.send_command("usb storage")
    resps.append(resp)
    resp = ctx.send_command("usb dev 0")
    resps.append(resp)
    return resps
  
'''
USB write addr blk# cnt - write `cnt' blocks starting at block `blk#'
    from memory address `addr'
'''
def usb_raw_write(ctx,source_addr,block,size):
    cmd = f"usb write 0x{source_addr:x} 0x{block:x} 0x{size:x}"
    resp = ctx.send_command(cmd)
    return resp

'''
USB read addr blk# cnt - read `cnt' blocks starting at block `blk#'
    to memory address `addr'
'''
def usb_raw_read(ctx,source_addr,block,size):
    cmd = f"usb read 0x{source_addr:x} 0x{block:x} 0x{size:x}"
    resp = ctx.send_command(cmd)
    return resp

Дамп флэш-памяти при помощи Depthcharge

Теперь, когда мы подготовили соответствующие функции, попробуем сделать следующее:

if __name__ == "__main__":
    log.info("Marvel Super Heroes Depthcharge Test...")
    ctx = console_setup()
    usb_setup(ctx,reset=False)
    # Read the SPI flash into RAM
    rksfc_read(ctx,TARGET_RAM_ADDR,0,0x35E00)
    log.info("Flash read into RAM")
    # Write the data from RAM to a USB drive
    usb_raw_write(ctx,TARGET_RAM_ADDR,0,0x35E00)
    log.info("Flash written to USB")

После запуска этого скрипта получим следующий результат:

pi@voidstar:~/marvel-cab/scripts $ python3 mvc.py
[+] Marvel Super Heroes Deptcharge Test...
[*] Using default payload base address: ${loadaddr} + 32MiB
[*] No user-specified prompt provided. Attempting to determine this.
[*] Identified prompt: =>
[*] Retrieving command list via "help"
[*] Reading environment via "printenv"
[!] Disabling payload deployment and execution due to error(s).
[*] Version: U-Boot 2017.09-g4857df5-dirty #lzy (Mar 24 2021 - 16:18:22 +0800)
[*] Enumerating available MemoryWriter implementations...
[*] Available: CpMemoryWriter
[*] Available: CRC32MemoryWriter
[*] Excluded: I2CMemoryWriter - Command "i2c" required but not detected.
[*] Excluded: LoadbMemoryWriter - Command "loadb" required but not detected.
[*] Excluded: LoadxMemoryWriter - Command "loadx" required but not detected.
[*] Excluded: LoadyMemoryWriter - Command "loady" required but not detected.
[*] Available: MmMemoryWriter
[*] Available: MwMemoryWriter
[*] Available: NmMemoryWriter
[*] Enumerating available MemoryReader implementations...
[!] Excluded: CpCrashMemoryReader - Operation requires crash or reboot, but opt-in not specified.
[*] Available: CRC32MemoryReader
[!] Excluded: GoMemoryReader - Payload deployment+execution opt-in not specified
[*] Excluded: I2CMemoryReader - Command "i2c" required but not detected.
[*] Excluded: ItestMemoryReader - Command "itest" required but not detected.
[*] Available: MdMemoryReader
[*] Available: MmMemoryReader
[*] Excluded: SetexprMemoryReader - Command "setexpr" required but not detected.
[*] Enumerating available Executor implementations...
[!] Excluded: GoExecutor - Payload deployment+execution opt-in not specified
[*] Enumerating available RegisterReader implementations...
[!] Excluded: CpCrashRegisterReader - Operation requires crash or reboot, but opt-in not specified.
[!] Excluded: CRC32CrashRegisterReader - Operation requires crash or reboot, but opt-in not specified.
[!] Excluded: FDTCrashRegisterReader - Operation requires crash or reboot, but opt-in not specified.
[!] Excluded: ItestCrashRegisterReader - Operation requires crash or reboot, but opt-in not specified.
[!] Excluded: MdCrashRegisterReader - Operation requires crash or reboot, but opt-in not specified.
[!] Excluded: MmCrashRegisterReader - Operation requires crash or reboot, but opt-in not specified.
[!] Excluded: NmCrashRegisterReader - Operation requires crash or reboot, but opt-in not specified.
[!] Excluded: SetexprCrashRegisterReader - Operation requires crash or reboot, but opt-in not specified.
[!] No default RegisterReader available.
[+] spinand read: device 0 block # 0, count 220672 ...
[+] Flash read into RAM
[+] => usb write 0x61700000 0x0 0x35e00

usb write: device 0 block # 0, count 220672 ...
[+] Flash written to USB

Вставив USB-накопитель, увидим следующие разделы:

pi@voidstar:~/marvel-cab/scripts $ lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
sda 8:0 1 57.8G 0 disk
├─sda1 8:1 1 4M 0 part
├─sda2 8:2 1 2M 0 part
├─sda3 8:3 1 9M 0 part
├─sda4 8:4 1 80.8M 0 part
└─sda5 8:5 1 8M 0 part

Победа! Мы извлекли SPI flash на USB-устройство при помощи Depthcharge!

Содержимое файловой системы

Теперь, когда мы надёжным образом можем считывать и записывать флэш-память, давайте вкратце изучим её содержимое. Интересные файлы расположены в папке /moo. В этой папке находится эмулятор и его ресурсы. Moo — это специализированный эмулятор, использующий собственный формат ROM; в 2020 году исследователи тщательно изучили другую версию этого эмулятора. Однако если посмотреть на содержимое папки, в глаза бросается нечто интересное:

pi@voidstar:~/marvel-cab/parts/squashfs-root/moo $ file *
docs: symbolic link to ../userdata
logo.mp4: ISO Media, MP4 Base Media v1 [IS0 14496-12:2003]
MOO: symbolic link to MOO-Ship-MIME_CCADE_MSH_2P-BRK01
MOO-Ship-MIME_CCADE_MSH_2P-BRK01: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-armhf.so.3, for GNU/Linux 4.4.0, stripped
SKUShell.MIME_CCADE_SF2_2P.19.exe: PE32+ executable (GUI) x86-64, for MS Windows
start.sh: POSIX shell script, ASCII text executable
_ui: directory
zassets: directory

Это ведь не может исполняемый файл Windows PE32? Ну, если мы скопируем его на машину с и попробуем его запустить, то получим следующее:

MOO Running

Работает! Очевидно, это артефакт сборки, который попал в систему незаметно для автора; он связался со мной в Twitter и мы отлично пообщались про реверс-инжиниринг и эмуляцию.

Благодаря описанным в статье способам мы можем выполнять считывание и запись между SPI flash и USB-накопителем при помощи UBoot. Мы извлекли файловую систему рута и идентифицировали основные компоненты эмуляции. Далее нам нужно будет выполнить реверс-инжиниринг части двоичных файлов на этой целевой платформе, чтобы определить, насколько сложно будет запускать собственные прошивки.

Выводы и дальнейшая работа

В этом посте мы рассказали о том, как подходить к разборке встроенного устройства и идентифицировать потенциальные отладочные разъёмы при помощи мультиметров/логических анализаторов. Затем мы рассказали о том, как анализировать неизвестный трафик UART и подключаться к последовательному порту при помощи screen на Raspberry Pi. Подключившись к последовательному порту, мы обнаружили, что доступ к консоли UBoot можно получить нажатием Ctrl-C. Изучив консоль UBoot, мы написали скрипт depthcharge для извлечения каждого из разделов SPI flash на внешний флэш-накопитель. В следующем посте мы подробно рассмотрим двоичный файл UBoot и узнаем, как создавать и модифицировать схемы распределения памяти при помощи Ghidra; затем мы попробуем прошить устройство собственным ядром и установить свою прошивку.

Все использованные скрипты и инструменты можно найти на github.

  1. 06.12.2010, 23:47


    #1

    MavRock вне форума


    Без позывного

    Аватар для MavRock


    Как определить UART(RS232) на плате

    Доброго времени суток, уважаемые знатоки! Вам такой вопрос : каким образом можно отыскать или же определить, если есть на плате RS232?


  2. 07.12.2010, 04:45


    #2

    Если 232 порт сделан на отдельной чипухе, то и искать надо эту самую чипуху с циферками 232 в маркировке, вокруг будут керамические конденсаторы кучковаться. Но, бывает данный порт реализован и внутри большого чипа, тогда только поиском документации. А так все микросхемы переписываешь и ищешь доки. Всё просто.


  3. 07.12.2010, 10:21


    #3

    MavRock вне форума


    Без позывного

    Аватар для MavRock


    Тобишь, если это процессор, и по документам у него есть выводы UART_TX/RX и тд. , то можно напрямую к ним цепляться?


  4. 07.12.2010, 11:16


    #4

    UW1WU вне форума


    Standart Power

    Аватар для UW1WU


    Цитата Сообщение от MavRock
    Посмотреть сообщение

    если это процессор, и по документам у него есть выводы UART_TX/RX

    Не совсем так, точнее, совсем не так.
    в 90-95% случаев на мат платах не последних годов выпуска последовательные порты выведены в виде разъема DB9 на заднюю панель. Для использования DB25 предусматриваются внешние переходники DB9 на DB25. Для универсальности , — были варианты, — один DB9 был выведен на заднюю панель, второй подключался через 9-ти штырьковый разъем, гибкий шлейф-кабель и крепился на посадочное место слотов расширения. Мог быть как DB9 так и DB25.
    В последнее время, сначала на ноутбуках, а теперь и на мат платах десктопов контроллеров последовательного интерфейса RS232 просто нет и не потому, что их не выводят наружу, а потому, что их нет там физически — не предусмотрены. В этом случае можно попробовать использовать переходники USB > RS232. Подпаиваться к незнакомым микросхемкам на мат платах я не рекомендую по очень простой причине — выход из строя всего устройства из-за неосторожного монтажа, перегрева или статического электричества, несоответствия уровней или превышение потребления тока по соотв. линиям и т.д. Много причин еще есть. Посмотрите внимательно на спецификацию вашей материнки и если там предусмотрено это, то смотрите схему разЪемов и контактов, а также их описание. Помните одно, делать Вы должны только то, в чем уверены до конца и точно знаете, что хотите и что делаете. Успехов.

    PS Есть еще вариант — приобрести плату расширения 1LPT 2Com. Стоимость этого добра 10-20 вечнозеленых убитых енотов. Но в этом варианте есть нюансы по настройке.

    Последний раз редактировалось UW1WU; 07.12.2010 в 11:21.

    Hpe cuagn, 73! Александр de UW1WU


  5. 07.12.2010, 17:27


    #5

    MavRock вне форума


    Без позывного

    Аватар для MavRock


    Спасибо за столь развернутый ответ! Дело в том, что я прочитал статью про UART , о том, что это протокол есть практически везде, где есть контроллер и процессор (вроде так). У меня есть убитая точка доступа неизвестной никому фирмы waveline, причем, которая была перешиты другой фирмой на свою прошивку, и с измененным сетевым интерфейсом. Ее убили в поптках прошить родную прошивку от waveline. Теперь нет пинга, а в статье про UART как раз описывалось , как всё с ним просто , и что можно видеть все стадии загрузки устройства. На плате есть несколько контактных площадок, но как определись who is who ,неясно пока что.
    Также, владею маленьким «игровым» блоком РИО ТАГ, который из себя представляет mini itx материнку вроде как советского производства, биос которой тоже свой. Есть вариант прошить эту железку через программатор путем вытаскивания чипа, но программатора у меня нет, а задница ищет приключений.
    Исходные данные : компьютер имеет 2х DB9 порта, один из который COM, другой — RS232. Вопрос : возможно ли, имея только COM шнур, подключиться к нему и что-то с ним сотворить, или же нужен всё таки преобразователь?


  6. 07.12.2010, 23:06


    #6

    Piter вне форума


    Без позывного

    Аватар для Piter


    Цитата Сообщение от MavRock
    Посмотреть сообщение

    один из который COM, другой — RS232

    здесь можно посмотреть, может меньше вопросов будет
    http://www.gaw.ru/html.cgi/txt/inter…s232/start.htm

    протокол RS232 как правило порт СОМ1…


  7. 07.12.2010, 23:28


    #7

    ER1CS вне форума


    Модератор


    Отправить сообщение для ER1CS с помощью ICQ

    Цитата Сообщение от MavRock
    Посмотреть сообщение

    возможно ли, имея только COM шнур, подключиться к нему и что-то с ним сотворить, или же нужен всё таки преобразователь?

    Смотря что нужно творить и что преобразовывать. Если комп не запускается — то ничего. Если комп не выдаёт на COM-порт никакой информации о загрузке, что в принципе вполне нормально, то тоже ничего.


  8. 08.12.2010, 09:33


    #8

    R3DMO вне форума


    Standart Power

    Аватар для R3DMO


    Цитата Сообщение от MavRock
    Посмотреть сообщение

    Вопрос : возможно ли, имея только COM шнур, подключиться к нему и что-то с ним сотворить, или же нужен всё таки преобразователь?

    Скорее всего нельзя!!!! Дело не в протоколе, а в уровнях сигналов. Как правило в точках доступа, сетевых накопителях да и много где , если используется UART то там уровень сигналов или 3.3В или 5В, а в стандарте RS232 +- 12В Вот как раз для преобразования уровня и ставятся микросхемы в названии которых присутствует цыферка 232. А вообще можно воспользоваться преобразователями от сотовых телефонов!

    Мы долго запрягаем, быстро ездим, и всё время тормозим!!!

    Ответив на вопрос ещё раз подумай, а на тот ли вопрос ты ответил !!!


  9. 08.12.2010, 10:44


    #9

    UW1WU вне форума


    Standart Power

    Аватар для UW1WU


    Цитата Сообщение от MavRock
    Посмотреть сообщение

    возможно ли, имея только COM шнур, подключиться к нему и что-то с ним сотворить

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

    Такой набор, о котором вы писали будет работать, но только в случае соглассования уровней, о чем написано выше и наличия программ обмена как в одном, так и в другом устройстве. Если планируете это в качестве стенда для самообразования, — проще связать 2 компа по последовательному порту и поиграться — там гарантия совместимости железа и куча инструментального терминального софта. Удачи Вам.

    Последний раз редактировалось UW1WU; 08.12.2010 в 10:51.

    Hpe cuagn, 73! Александр de UW1WU


  10. 08.12.2010, 18:58


    #10

    MavRock вне форума


    Без позывного

    Аватар для MavRock


    Решил начать с компьютера. Итак, по документам , у него 2 Serial порта, в виде DB9. Возле портов находятся 2 микросхемы ADM485. К этим портам осуществляется подключение доп. устройств. Используются пины RXD , GND и TXD. Однако есть и такие устройства, которые работают через согласователь. Тогда при подключении используются всё те же пины, но согласователь еще берёт +5V с другого разъёма. Только не пойму — это означает, что согласователь преобразовывает из 12 в 5, или наоборот(Тоесть, на компьютере мы имеем стандартный COM с +-12V или 5). Если это удастся выяснить, то можно будет пробно подключить его к настольнику и прозвонить терминалом.


  11. 08.12.2010, 19:39


    #11

    R3DMO вне форума


    Standart Power

    Аватар для R3DMO


    Цитата Сообщение от MavRock
    Посмотреть сообщение

    Только не пойму — это означает, что согласователь преобразовывает из 12 в 5, или наоборот(Тоесть, на компьютере мы имеем стандартный COM с +-12V или 5). Если это удастся выяснить, то можно будет пробно подключить его к настольнику и прозвонить терминалом.

    В современных согласующих внутри стоит преобразователь, а вообще есть интернет, посмотрите что за чипы у Вас стоят на согласовании и почитайте перед сном даташит!!! Очень увлекательное чтиво, когда что то сильно интересует. Но на выходе однозначно будут двуполярные сигналы в пределах от+-5 до +-12
    Удачи!

    Мы долго запрягаем, быстро ездим, и всё время тормозим!!!

    Ответив на вопрос ещё раз подумай, а на тот ли вопрос ты ответил !!!


  12. 09.12.2010, 00:44


    #12

    MavRock вне форума


    Без позывного

    Аватар для MavRock


    Спасибо конечно, но про ту материнку что у меня нет ровным счетом ничего в сети. Нашел мануал от другой платы, похожей, однако там не говорится о чипах…я в печали


  13. 09.12.2010, 11:19


    #13

    R3DMO вне форума


    Standart Power

    Аватар для R3DMO


    Цитата Сообщение от MavRock
    Посмотреть сообщение

    Спасибо конечно, но про ту материнку что у меня нет ровным счетом ничего в сети. Нашел мануал от другой платы, похожей, однако там не говорится о чипах…я в печали

    Я имел ввиду чипы около СОМ портов, хотя они и не обязательно рядом с ними, вы их можете увидеть , физически вскрыв компьютер, там кажется 20 пиновые в SOIC корпусах… но однозначно они у задней стенки…. А потом запросы в Инет

    Мы долго запрягаем, быстро ездим, и всё время тормозим!!!

    Ответив на вопрос ещё раз подумай, а на тот ли вопрос ты ответил !!!


  14. 09.12.2010, 20:12


    #14

    MavRock вне форума


    Без позывного

    Аватар для MavRock


    May day! Меня аватары лишили! Ужас, непонятки, хаос!


Практический реверс-инжиниринг. Часть 1 – Поиск отладочных портов

В этой серии статей будет описан процесс реверс-инжиниринга роутера Huawei HG533.

Автор: Juan Carlos Jiménez

В этой серии статей будет описан процесс реверс-инжиниринга роутера Huawei HG533.

Рисунок 1: Внешний вид роутера Huawei HG533

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

Несмотря на то, что процесс поиска будет описываться на примере роутера, те же самые методы можно применить и для других, повсеместно используемых, устройств, начиная от принтеров и заканчивая IP-камерами. Если аппарат обладает более менее приличным функционалом, то, скорее всего, работает на базе Linux и имеет скрытые отладочные порты, наподобие тех, которые мы будем искать.

Поиск последовательного порта

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

После осмотра платы мое внимание привлекло два набора площадок, которые не использовались до того момента, пока я не припаял к ним пины (см. рисунок ниже):

Рисунок 2: Плата роутера

По-видимому, в роутере имеются 2 последовательных порта, используемых для взаимодействия с двумя различными интегральными микросхемами. Отследив дорожки, можно понять, какой из портов соединен с главной микросхемой. Скорее всего, именно здесь мы найдем наиболее интересную информацию.

В любом случае мы просто пытаемся подключиться к обоим портам для того, чтобы выяснить, что «предлагает» нам каждый.

Идентификация ненужных пинов

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

Рисунок 3: Подсвеченная плата

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

  • Первый пин подсоединен к чему-то (можно увидеть путь от разрыва на уровне 2 часов).
  • Второй пин не подсоединен.
  • Третий пин подсоединен к одному или нескольким слоям. Обычно это свидетельствует о том, что разъем не используется. На чертеже пин может быть заземлен или соединен платой Vcc, но не обязательно.
  • Четвертый пин соединен по всем сторонам. Скорее всего, заземлен. Маловероятно, что разъем с данными на отладочном порту соединен с 4 различными дорожками.
  • Пятый пин подсоединен к чему-то.

Пайка пинов для более легкого доступа

На рисунке выше видны оба последовательных порта.

Площадки в этих портах сквозные и заполнены припоем с высокой температурой плавления, с которым очень тяжело работать

В случае со вторым последовательным портом я решил просверлить дырки (в качестве сверла использовался кусок иголки). Далее просовываем пины и припаиваем с обратной стороны платы.

Рисунок 4: Припаянные пины

Поиск выходного пина

На данный момент у нас есть два коннектора, на каждом из которых по 3 «полезных» пина. Мы пока что не определили работоспособные порты или последовательный протокол, используемый устройством, но количество и расположение пинов говорит о том, что, скорее всего, мы имеем дело с UART-портами.

Коротко рассмотрим протокол UART. В спецификации описаны 6 типа пинов:

  • Tx [Передающий пин. Соединяется с нашим пином с типом Rx]
  • Rx [Принимающий пин. Соединяется с нашим пином с типом Tx]
  • GND [Земля. Соединяется с нашим пином с типом GND]
  • Vcc [Питание. Обычно 3.3В или 5В. НЕ ПОДСОЕДИНЕН]
  • CTS [Обычно не используется]
  • DTR [Обычно не используется]

Мы также знаем, что согласно стандарту по умолчанию на пинах Tx и Rx напряжение повышается (устанавливается в 1В). Передатчик линии (Tx) отвечает за повышение напряжения, и если передатчик не будет подсоединен, напряжение линии будет плавать.

Подведем промежуточные итоги:

  1.  У каждого порта есть три рабочих пина, которые к чему-то подсоединены. Эти пины должны быть следующими: Tx, Rx и GND (земля).
  2. Один пин очень похож на землю, поскольку подсоединен к плате по всем четырем сторонам.
  3. На пине Tx будет повышаться напряжение и передаваться информация.
  4. На пине Rx напряжение будет плавать до тех пор, пока мы не подсоединим другой конец к линии.

Вышеприведенной информации вполне достаточно для того, чтобы наладить мост между портами UART и USB, но если подсоединять пины случайно вы не поймете механики процесса.

Продолжаем углубляться.

Мультиметра или логического анализатора вполне достаточно для того, чтобы определить типы пинов, но если вы хотите понять, что конкретно происходит на каждом разъеме, нет ничего лучше хорошего осциллографа:

Рисунок 5: Осциллограмма одного из пинов

После проверки пинов при помощи осциллографа приходим к следующим выводам:

  1. Заземленный пин (GND) найден. На выходе стабильные 0В.
  2. Пин Tx найден. Наблюдаем, как устройство передает информацию.
  3. На одном из пинов напряжение колеблется в районе 0В. Скорее всего, это Rx пин, на котором колеблется напряжение, поскольку мы еще не подсоединили другой конец.

Теперь мы знаем тип каждого пина, но для того, чтобы «пообщаться» с последовательным портом, необходимо выяснить скорость передачи данных в бодах (baudrate). Эту задачу можно решить при помощи логического анализатора. Если у вас нет данного устройства, можете пойти другим путем и подбирать скорость передачи из списка наиболее распространенных скоростей до тех пор, пока не начнете получать читаемый текст от последовательного порта.

На рисунке ниже показана информация, полученная от логического анализатора, на котором включена функция анализа протокола. Я игрался с различными скоростями до тех пор, пока не получил читаемый текст (nrnrU-Boot 1.1.3 (Aug…).

Рисунок 6: Анализ протокола при помощи логического анализатора

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

Рисунок 7: Схема распиновки последовательных портов

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

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

Рисунок 8: Вариант аппаратной сборки для подключения к последовательным портам

Когда мы откроем последовательный терминал на компьютере во время коммуникации с устройством, то увидим, как главный UART порт начинает выдавать полезную информацию. Ниже показаны команды, используемые мной для подсоединения к каждому порту, а также первые строки во время процесса загрузки:

Рисунок 9: Программная часть взаимодействия с последовательными портами


Please choose operation:
   3: Boot system code via Flash (default).
   4: Entr boot command line interface.
0

Словосочетание ‘Command line interface’ свидетельствует о том, что мы нашли способ попасть внутрь системы. После выбора пункта 4 мы попадаем в командную строку, предназначенную для взаимодействия с загрузчиком устройства.

Кроме того, если мы выберем пункт 3, подождем, когда закончится проверка контрольной суммы и нажмем enter, то получим сообщение Welcome to ATP Cli и строку для ввода логина. Если на устройстве изменен пароль, процедура авторизации может вызвать затруднения. Однако в большинстве случаев можно авторизироваться при помощи стандартной учетной записи. После нескольких попыток мне удалось попасть в систему при помощи комбинации admin:admin.


-------------------------------
-----Welcome to ATP Cli------
-------------------------------

 
Login: admin
Password:    #Password is ‘admin'
ATP>shell

 
BusyBox vv1.9.1 (2013-08-29 11:15:00 CST) built-in shell (ash)
Enter 'help' for a list of built-in commands.

 
# ls
var   usr   tmp   sbin  proc  mnt   lib   init  etc   dev   bin

Теперь мы можем выполнять команды с правами суперпользователя. На данном роутере установлен BusyBox с линуксовым интерфейсом, о котором я расскажу подробнее в следующей статье.

Что дальше?

После того как мы получили доступ к BusyBox CLI, можем начать исследование программного обеспечение. В зависимости от устройства это могут быть пароли в текстовом виде, TLS-сертификаты, полезные алгоритмы, небезопасные приватные API и так далее.

В следующей статье мы подробнее углубимся в программную часть. Я объясню различия между режимами загрузки, расскажу о выгрузке памяти и других интересных вещах, которые можно делать, если есть доступ к программному обеспечению устройства.

Спасибо за внимание. 

Использование cookie

(Онлайн справочник радиолюбителя)

UART CP2103

Мы уже писали, что низковольтный последовательный порт UART может заметно облегчить процесс диагностики современной электронной техники. В этом материале расскажем, как его правильно подключить к компьютеру с операционной системой Windows.

Рассмотрим самый популярный UART, собранный на микросхеме CP2103.

Если подключить вновь приобретенный модуль к USB-разъему компьютера, мы увидим следующее сообщение:

В системе нет драйвера

Чтобы убедиться, что Windows обнаружила наш модуль UART, откроем панель управления, а в ней диспетчер устройств.

диспетчер задач

Теперь видно, что система обнаружила модуль UART на микросхеме CP2103, но драйвера к нему не нашла, так как около значка устройства стоит восклицательный знак. Далее нужно по этой ссылке сохранить драйвер устройства.

загрузка драйвера

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

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

Если операционная система 32-х разрядная — необходимо запустить файл CP210xVCPInstaller_x86, а если 64-х разрядная — CP210xVCPInstaller_x64.

продолжение установки

Нажимаем «далее».

завершение установки

Принимаем условия соглашения и нажимаем «далее».

проверка установки

Нажимаем «готово» и возвращаемся в диспетчер устройств.

проверка установки

Здесь видно, что наш модуль правильно определился и переехал в раздел «Порты (COM и LPT)». Нужно запомнить номер COM-порта, который система присвоила модулю UART.

Поскольку, начиная с Windows7 Microsoft перестала поставлять программу «Гипертерминал», найдем ей достойную замену. Можно скачать бесплатную терминальную программу PyTTY с официального сайта.

сайт PuTTY

На сайте предлагается выбрать файл с нужной разрядностью Windows для загрузки.

загрузка PuTTY

Затем нужно согласиться с тем, что мы собираемся открыть исполняемый файл.

подтверждение

Но на этом Windows не успокаивается, она не знакома с производителем файла, поэтому нажимаем кнопку «запустить».

еще одно

После установки в разделе «Программы» появляется пункт PuTTY. Для дальнейшей работы его необходимо запустить.

запуск PuTTY

В форме программы нужно выбрать «Connection type — Serial», затем в поле «Serial line» ввести номер COM-порта, который мы запомнили из диспетчера устройств и установить скорость соединения. Для приставок DVB-T2 выбираем 115200, для другого оборудования скорости могут быть другими.

Затем нужно проверить работоспособность модуля UART. Нажимаем кнопку «Open» и попадаем в терминал. Далее замыкаем контакты RX и TX модуля между собой и набираем символы на клавиатуре. При замкнутых между собой выводах RX и TX на экране терминала должен печататься текст, набираемый на клавиатуре, при разомкнутых — не должен печататься.

Проверка работы UART

Теперь можно подключать наш диагностический модуль к испытуемому устройству. Помните, что сигналы приема и передачи нужно «крестить» — то есть RX модуля UART соединять с TX устройства, а TX — с RX устройства.

Подключение UART к приставке

Если на экране терминала появляется масса нечитаемых символов, значит необходимо изменить скорость порта.

Программатор CH341a

Использовать в качестве UART можно и программатор на микросхеме CH341a. Для этого необходимо удалить перемычку PROG / UART и установить драйвер последовательного режима работы. Процедура установки драйвера и запуска PuTTY аналогична представленной выше.

   

Понравилась статья — поделитесь с друзьями:

По ходу работы над очередной поделкой, для которой я воспользовался завалявшейся у меня платой Banana Pi BPI-M5, мне потребовалось подключить к ней внешнее устройство по UART.

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

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

Итак Banana Pi BPI-M5. Я в курсе, что это довольно ублюдская поделка с кривой поддержкой и косяками, но что есть то есть.

На плату я решил накатить свой любимый Armbian, который тоже не отличается стабильностью, но для китайских плат нет ничего стабильного, а Raspberry PI я не хочу использовать в силу ряда причин.
Так что Armbian. Образ есть на сайте Armbian https://www.armbian.com/bananapi-m5/. Каких-то затруднений с установкой не было.

Где мой UART?

На сайте с документацией есть распиновка, согласно которой у нас есть два UART-а.
Один отладочный для вывода сообщений при загрузке, а второй выведен на гребёнку GPIO пинов (UART_A) и типа может быть настроен по своему усмотрению — он то мне и нужен.

По умолчанию работает только отладочный UART и это нормально. Для подключения дополнительного оборудования у нас есть так называемые оверлеи, которые можно или прописать в файл /boot/armbianEnv.txt или воспользоваться программой armbian-config, в меню которой System -> Hardware мы можем увидеть такую картину.

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

Поищем что-ли в логах загрузки.

# dmesg | grep uart
ff803000.serial: ttyAML0 at MMIO 0xff803000 (irq = 14, base_baud = 1500000) is a meson_uart

Только одинокий ttyAML0. Это наш отладочный друг. Ни второго и ни уж тем более 3-го не видать.

Погружаемся в оверлеи

На самом деле это просто devicetree файлы с настройками устройств, применяемыми при загрузке. Эта штука работает в каждом компьютере (в частности я патчил свой ноутбук таким образом для более корректной работы в Linux) и кстати любимый мной ZephyrRTOS так-же использует эту систему.

Но вернёмся к нашей ситуации. У нас эти оверлеи лежат тут:

# ls -la /boot/dtb/amlogic/overlay/
total 44
drwxr-xr-x 2 root root 4096 Jan  7 21:27 .
drwxr-xr-x 3 root root 4096 Oct 20 12:00 ..
-rwxr-xr-x 1 root root  232 Oct 20 12:00 meson-fixup.scr
-rwxr-xr-x 1 root root  377 Oct 20 12:00 meson-g12-gxl-cma-pool-896MB.dtbo
-rwxr-xr-x 1 root root  343 Oct 20 12:00 meson-i2cA.dtbo
-rwxr-xr-x 1 root root  343 Oct 20 12:00 meson-i2cB.dtbo
-rwxr-xr-x 1 root root  238 Oct 20 12:00 meson-uartA.dtbo  # <==== вот наш пациент
-rwxr-xr-x 1 root root  238 Oct 20 12:00 meson-uartC.dtbo
-rwxr-xr-x 1 root root  759 Oct 20 12:00 meson-w1AB-gpio.dtbo
-rwxr-xr-x 1 root root  490 Oct 20 12:00 meson-w1-gpio.dtbo
-rwxr-xr-x 1 root root  339 Oct 20 12:00 README.meson-overlays

Но они в скомпилированом формате. Чтобы его декомпилировать воспользуемся командой dtc

# dtc -I dtb -O dts /boot/dtb/amlogic/overlay/meson-uartA.dtbo
/dts-v1/;

/ {
        compatible = "amlogic,meson-gxbb";

        fragment@0 {
                target-path = "/soc/bus@c1100000/serial@84c0";

                __overlay__ {
                        status = "okay";
                };
        };
};

Ну и для интереса глянем, что это за девайс такой. Для этого залезем в живой devicetree устройства, расположенный в файловой системе в папке/sys/firmware/devicetree/base/

# ls -la /sys/firmware/devicetree/base/soc
...
drwxr-xr-x 16 root root  0 Jan  6 22:17  bus@ff600000
drwxr-xr-x 14 root root  0 Jan  6 22:17  bus@ff800000
drwxr-xr-x 19 root root  0 Jan  6 22:17  bus@ffd00000
...

Как видим никакого bus@c1100000 у нас нет и в помине. В общем не буду томить — оверлеи в данной плате от Odroid C4. Видимо разрабы Armbian не стали заморачиваться и просто взяли оверлеи от похожего устройства на этом же чипе. Но не фортануло.

Ну что — изучим что же есть у нас.

# ls -ls /sys/firmware/devicetree/base/soc/bus@ff800000/
...
0 drwxr-xr-x 2 root root  0 Jan  6 22:17  serial@3000
0 drwxr-xr-x 2 root root  0 Jan  6 22:17  serial@4000
...

Уже что-то — есть два устройства с подозрительным именем serial

# ls -ls /sys/firmware/devicetree/base/soc/bus@ffd00000
...
0 drwxr-xr-x 2 root root  0 Jan  6 22:17  serial@22000
0 drwxr-xr-x 2 root root  0 Jan  6 22:17  serial@23000
0 drwxr-xr-x 2 root root  0 Jan  6 22:17  serial@24000
...

Ну и три штуки по этому адресу.

В общем надо разобраться что тут что.

Документация к чипу

В нашем случае это Amlogic S905×3 datasheet

Ищем раздел 13.5 Universal Asynchronious Receiver And Transmitter и оттуда мы узнаём, что у нас и правда 5 UART-ов.

Так-же оттуда мы узнаём, что 3 обычных UART-а у нас расположены по базовому адресу 0xffd00000.

Кроме того у нас есть 2 always on UART-а. Скажем прямо — негусто.

Исходники Linux

Далее я полез в исходники dts файлов для данной платы.

Вот родной dts файл для Banana Pi BPI-M5 meson-sm1-bananapi-m5.dts

aliases {
  serial0 = &uart_AO;
};

&uart_AO {
	status = "okay"; /* uart_AO включается */
};

В котором у нас есть ссылка на некий uart_AO, который очень напоминает нам наш единственный доступный в системе дебаговый UART. То есть dts для Banana Pi BPI-M5 просто включает uart_AO. Осталось найти где этот uart_AO описан, т. к. здесь просто ссылка на него.

Ну и у нас нет остальных UART-ов, поэтому открываем по очереди файлы из include и в конце концов натыкаемся на россыпь UART-ов в файле meson-g12-common.dtsi.

aobus: bus@ff800000 {          
    uart_AO: serial@3000 { /* <=== этот адрес мы видели в логе загрузки */
      ...
      status = "disabled";
    };

    uart_AO_B: serial@4000 {
      ...
      status = "disabled";
    };
}

cbus: bus@ffd00000 {
    uart_C: serial@22000 {
      ...
      status = "disabled";
    };

    uart_B: serial@23000 {
      ...
      status = "disabled";
    };

    uart_A: serial@24000 {
      ...
      fifo-size = <128>; /* в доке к чипу упоминалось что UART_A имеет буффер в 128k */
      status = "disabled";
    };
}

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

Так же видим, что все устройства в состоянии disabled. Включен (см. выше про meson-sm1-bananapi-m5.dts) только uart_AO который имеет адрес aobus: bus@ff800000 serial@3000, то есть то самое MMIO 0xff803000 из лога загрузки. Короче это точно наш дебаговый UART.

Надо попробовать включить uart_A. Для этого сохраняем декомпилированный оверлей в файл с расширением dts и меняем там адрес UART-а на обнаруженный нами, то есть получим что-то вот такое

# dtc -I dtb -O dts -f /boot/dtb/amlogic/overlay/meson-uartA.dtbo -o /root/meson-uartA.dts

Далее редактируем meson-uartA.dts

/dts-v1/;
/plugin/;  /* <=== это надо добавить т.к. у нас оверлей */

/ {
        compatible = "amlogic,meson-gxbb";

        fragment@0 {
                target-path = "/soc/bus@ffd00000/serial@24000";  /* <=== меняем адрес */

                __overlay__ {
                        status = "okay";
                };
        };
};

И устанавливаем, предварительно удалив старые uart оверлеи.

# armbian-add-overlay meson-uartA.dts
Compiling the overlay
Copying the compiled overlay file to /boot/overlay-user/
Reboot is required to apply the changes

Как вариант с помощью dtc можно скомпилировать и подменить файлы вручную, но так проще.

После перезагрузки видим 2 устройства. Работает!

% sudo dmesg | grep _uart
ff803000.serial: ttyAML0 at MMIO 0xff803000 (irq = 14, base_baud = 1500000) is a meson_uart
ffd24000.serial: ttyAML1 at MMIO 0xffd24000 (irq = 15, base_baud = 1500000) is a meson_uart

Но радость была недолгой. При подключении к порту реального устройства оказалось, что обмен идёт только в одну сторону. Короче RX работает, а TX — нет.

Разборки с пинами

Очевидно, что какая-то проблема с настройкой пинов. Подключаемая железка гарантировано работала. На пины я убил 3 вечера.

Проверим, что у нас с пинами. По счастью эта информация есть в нашем текущем devicetree

Итак начнём. Поищем какие пины и как назначены нашим устройствам. Конкретно нас интересует UART_A, который как мы выяснили имеет адрес ffd24000.

# cat /sys/kernel/debug/pinctrl/pinctrl-maps | grep ffd24000 -A 8
device ffd24000.serial
state default
type MUX_GROUP (2)
controlling device ff634400.bus:pinctrl@40  # <== вот это нам и надо
group uart_a_tx                             # <== и вот это
function uart_a

device ffd24000.serial
state default
type CONFIGS_GROUP (4)
controlling device ff634400.bus:pinctrl@40
group uart_a_tx
config 00000001

device ffd24000.serial
state default
type MUX_GROUP (2)
controlling device ff634400.bus:pinctrl@40
group uart_a_rx
function uart_a

device ffd24000.serial
state default
type CONFIGS_GROUP (4)
controlling device ff634400.bus:pinctrl@40
group uart_a_rx
config 00000001

device ffd24000.serial
state default
type MUX_GROUP (2)
controlling device ff634400.bus:pinctrl@40
group uart_a_tx
function uart_a

device ffd24000.serial
state default
type CONFIGS_GROUP (4)
controlling device ff634400.bus:pinctrl@40
group uart_a_tx
config 000fa00a
config 0000000c
config 00000112

Теперь мы знаем адрес устройства на шине, которое заведует нужными нам пинами и конкретные группы пинов. Теперь лезем обратно в dts meson-g12-common.dtsi и ищем это устройство.

soc {
	apb: bus@ff600000 {    /* <=== вот адрес шины */
    ...
	periphs: bus@34400 { /* <=== вот адрес внутри шины */
      ...
		periphs_pinctrl: pinctrl@40 { /* <=== устройство */
        ...
			uart_a_pins: uart-a {
				mux {
					groups = "uart_a_tx", "uart_a_rx"; /* <==== пины */
					function = "uart_a";
					bias-disable;
				};
			};

И что же мы тут видим? А видим мы, что и TX и RX объединены в одну группу и имеют общие настройки, что довольно странно.

Поищем ещё поглубже

# ls -la /sys/kernel/debug/pinctrl
total 0
drwxr-xr-x  2 ff634400.bus:pinctrl@40-pinctrl-meson  # <== вот эта папка что-то напоминает
drwxr-xr-x  2 ff800000.sys-ctrl:pinctrl@14-pinctrl-meson
-r--r--r--  1 pinctrl-devices
-r--r--r--  1 pinctrl-handles
-r--r--r--  1 pinctrl-maps  # <== это мы только что смотрели

Нас интересует файл pinconf-pins

# cat /sys/kernel/debug/pinctrl/ff634400.bus:pinctrl@40-pinctrl-meson/pinconf-pins | grep GPIOX_1
...
pin 77 (GPIOX_12): input bias disabled, output drive strength (2500 uA)
pin 78 (GPIOX_13): input bias disabled, output drive strength (2500 uA)
...

GPIOX_12 и GPIOX_13 упоминаются в распиновке по ссылке выше как соответственно UART_A_TX и UART_A_RX.

Вроде и всё бы ничего, но некоторые другие пины имеют среди прочего output enabled. Видимо стоит это как-то указать. Ну и забегая вперёд кроме добавления TX пину возможности работать на вывод, нужно ещё убрать ему возможность работать на вход. Оба условия оказались необходимы, иначе ничего не работало.

Полный набор возможных опций для пинов можно посмотреть тут pinconf-generic.c

В итоге наш финальный оверлей принял следующий вид.

/dts-v1/;
/plugin/;

/ {
    compatible = "amlogic,meson-gxbb";

    fragment@0 {
        target-path = "/soc/bus@ff600000/bus@34400/pinctrl@40"; /* для данного устройства */

        __overlay__ {
            uart_a_tx_pin: uart-a-tx { /* добавляем настройки пинов */
                mux {
                    groups = "uart_a_tx"; /* для группы пинов "uart_a_tx"
                    function = "uart_a";  /* это как было в оригинальной группе */
                    input-disable;        /* для TX выключаем input - обязательно! */
                    output-enable;        /* для TX включаем output - обязательно! */
                    drive-strength-microamp = <4000>; /* это наверно необязательно */
                };
            };
        };
    };

    fragment@1 {
        target-path = "/soc/bus@ffd00000/serial@24000";  /* <=== меняем адрес (см. выше) */

        __overlay__ {
            status = "okay";                             /* включаем UART */
            pinctrl-0 = <&uart_a_pins &uart_a_tx_pin>;   /* добавляем uart_a_tx_pin из блока выше */
            pinctrl-names = "default";                   /* это возможно необязательно */
        };
    };
};

Устанавливаем этот оверлей и после перезагрузки получаем полноценно работающий UART_A согласно официальной распиновке.

Настройки пинов при этом приняли следующий вид. Видим, что у TX (GPIOX_12) появился output-enabled

# cat /sys/kernel/debug/pinctrl/ff634400.bus:pinctrl@40-pinctrl-meson/pinconf-pins | grep GPIOX_1
...
pin 77 (GPIOX_12): input bias disabled, output drive strength (4000 uA), output enabled, pin output (1 level)
pin 78 (GPIOX_13): input bias disabled, output drive strength (2500 uA)
...

Итого

После всех злоключений удалось таки запустить этот чортов UART и успешно подключить к нему железяку. Я счастлив, особенно учитывая количество убитого времени. Надеюсь кому-нибудь будет полезно.

Понравилась статья? Поделить с друзьями:
  • Как найти скрытый профиль инстаграм
  • Как найти подругу в гта сан андреас
  • Разбито стекло на двери межкомнатные как исправить
  • Как составить бухгалтерскую отчетность некоммерческой организации
  • Как найти адрес компании по телефону