Мне всегда хотелось заполучить экран на электронных чернилах для своих будущих проектов. Я купил небольшой экранчик с платой расширения Raspberry Pi, однако потом понял, что можно просто воспользоваться старой «читалкой» Amazon Kindle.

Когда-то давно я уже экспериментировал с Kindle: портировал на него интерпретатор Infocom и приложение для чтения манги. Мне удалось заставить ПО Amazon загружать их как Kindlet и отображать их интегрированными в «читалку». Однако сейчас мне нужна была просто дешёвая и удобная платформа разработки под Linux с eink.

Дешёвый Kindle с Ebay (и причина его дешевизны)


Итак, я отправился на ebay! Нашёл там множество очень дешёвых лотов, помеченных как «Заблокирован Amazon». Я решил, что не стоит их брать, потому что, теоретически, они могут быть краденными. В конечном итоге я выбрал Kindle 4 без сенсорного экрана за 7 фунтов.

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

image

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

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

Физический доступ получен!


Всё оказалось довольно непросто! По периметру есть множество защёлок, а сам корпус приклеен к аккумуляторному отсеку, поэтому потребовалось вмешательство большого ножа. От клея устройство я отчистил ацетоном.

image

  • Красное: надоедливые защёлки
  • Фиолетовое: очень надоедливый клей.
  • Жёлтое: последовательный порт!

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

image

image

Не хочу оставлять болтающиеся провода, но в то же время понимаю, что рано или поздно что-нибудь напутаю и мне понадобится доступ к консоли последовательного порта, поэтому придумал следующее решение:

image

image

Я приклеил суперклеем к печатной плате Kindle кусок макетной платы, а затем припаял с одного конца проводники от крошечных контактов на печатной плате. Потом я припаял с другого конца более крупный и удобный разъём Dupont, чтобы можно легко было подключаться к нему. Верхний кабель на плате Kindle — это 0v/GND, а остальные — это TX и RX (я забыл, какой из них где).

Последняя проблема: последовательный порт Kindle работает от 1,8 В, поэтому мне нужен адаптер последовательного порта с поддержкой такого напряжения:

image

Купленный мной адаптер поддерживает 5 В, 3,3 В, 2,5 В и 1,8 В — очень удобно!

Root-доступ получен!


Далее я подключил адаптер последовательного порта к ноутбуку, запустил ПО последовательного порта minicom и перезапустил Kindle. Затем, поменяв местами провода TX и RX (это всегда неизбежно), я увидел следующую информацию!

U-Boot 2009.08-lab126 (Aug 29 2012 - 12:55:24)

CPU:   Freescale i.MX50 family 1.1V at 800 MHz
mx50 pll1: 800MHz
mx50 pll2: 400MHz
mx50 pll3: 216MHz
ipg clock     : 50000000Hz
ipg per clock : 50000000Hz
uart clock    : 24000000Hz
ahb clock     : 100000000Hz
axi_a clock   : 400000000Hz
axi_b clock   : 200000000Hz
weim_clock    : 100000000Hz
ddr clock     : 800000000Hz
esdhc1 clock  : 80000000Hz
esdhc2 clock  : 80000000Hz
esdhc3 clock  : 80000000Hz
esdhc4 clock  : 80000000Hz
MMC:  FSL_ESDHC: 0, FSL_ESDHC: 1
Board: Tequila
Boot Reason: [POR]
Boot Device: MMC
Board Id: 0031701123730Z56
S/N: B02317022392005M
Initing MDDR memory
ZQ calibration complete: 0x128=0xfffe0010 0x12C=0xffffffff
DRAM:  256 MB
Using default environment

In:    serial
Out:   logbuff
Err:   logbuff
Quick Memory Test 0x70000000, 0x10000000
POST done in 13 ms
Hit any key to stop autoboot:  0 
## Booting kernel from Legacy Image at 70800000 ...
   Image Name:   Linux-2.6.31-rt11-lab126
   Image Type:   ARM Linux Kernel Image (uncompressed)
   Data Size:    4777568 Bytes =  4.6 MB
   Load Address: 70008000
   Entry Point:  70008000
   Verifying Checksum ... OK
   Loading Kernel Image ... OK
OK
Starting kernel ...

[snip]

Welcome to Kindle!

kindle login: 

Отлично, это загрузка при помощи uboot-загрузчика, после чего происходит загрузка Linux и запрос логина.

Если попытаться войти как root, система запросит пароль, хм-м-м… Однако из предыдущего опыта работы с Kindle я знал, что пароль можно сгенерировать из серийного номера. Я нашёл этот веб-сайт, генерирующий несколько возможных паролей для конкретного устройства: мой пароль оказался третьим в списке.

На случай смерти сайта вот самый важный фрагмент кода на Javascript:

var md5 = hex_md5(serial);
document.getElementById("rootpw").innerHTML = "fiona" + md5.substring(7,11);
document.getElementById("rootpw2").innerHTML = "fiona" + md5.substring(7,10);
document.getElementById("rootpw3").innerHTML = "fiona" + md5.substr(13,3);

А, я забыл сказать, как извлёк серийный номер устройства. Подключение по USB не «срабатывает» — такие демо-устройства нельзя монтировать как диски. Однако под Linux оно всё равно выводит серийный номер в вывод dmesg Linux (также его можно получить при помощи printenv в uboot, если нажать на Enter при отображении сообщения «Hit any key to stop autoboot»):

[128033.676587] usb 1-2: new high-speed USB device number 51 using xhci_hcd
[128033.829631] usb 1-2: New USB device found, idVendor=1949, idProduct=0004, bcdDevice= 1.00
[128033.829638] usb 1-2: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[128033.829642] usb 1-2: Product: Amazon Kindle
[128033.829645] usb 1-2: Manufacturer: Amazon
[128033.829648] usb 1-2: SerialNumber: XXXXXXXXXXXXXXXX

Отлично! У нас есть root и мы можем выполнить вход! Теперь разберёмся, как чуть упростить себе работу.

Выполняем дамп системы


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

Проверив /proc/mounts, мы увидим множество разделов основного диска на /dev/mmcblk0.

Выполнив fdisk /dev/mmcblk0, получим следующее:

Units = cylinders of 64 * 512 = 32768 bytes

        Device Boot      Start         End      Blocks  Id System
/dev/mmcblk0p1   *        1025       12224      358400  83 Linux
/dev/mmcblk0p2           12225       14272       65536  83 Linux
/dev/mmcblk0p3           14273       15296       32768  83 Linux
/dev/mmcblk0p4           15297       59776     1423360   b Win95 FAT32

  • Итак, есть четыре раздела — три Linux, один FAT32.
  • Первый диск начинается довольно далеко: оказалось, что в этой «отсутствующей» области хранится ядро.
  • После изучения становится ясно, что раздел 1 — это обычная система, 2 — что-то вроде раздела для инструментов диагностики, 3 — для хранения внутреннего приватного состояния Kindle (например, паролей WiFi). 4 — это тот раздел, который вы видите при подключении Kindle по USB: на нём хранятся все книги.
  • Раздел 4 смонтирован на /mnt/us.

С помощью dd я сдампил начало диска и разделы 1-3 на /mnt/us (мне нравится делать полный сырой образ, чтобы можно было его восстановить на случай, если что-то пойдёт не так):

dd if=/dev/mmcblk0 of=/mnt/us/kindle.img bs=32768 count=15297

Хотя этот Kindle не отображает диск по USB, поскольку у меня есть root, я могу просто заставить отобразить его:

rmmod g_file_storage
modprobe g_file_storage file=/dev/mmcblk0p4

После этого я скопировал всё на ноутбук.

Анализ системы


Далее я смонтировал разделы из kindle.img на свой ноутбук:

kpartx -v kindle.img

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

  • В качестве системы инициализации используется rc.d, поэтому там много скриптов, написанных обычным текстом.
  • Уровень инициализации 5 — это «обычная» система, запускающая ПО электронной книги
  • ПО электронной книги находится в /opt/amazon, оно написано на Java (я вроде бы уже знал это, но мне понадобилось освежить память).
  • Там есть целая куча интересных скриптов diag для тестирования, написанных обычным текстом.
  • Есть довольно удобный демон wifid для управления wifi-соединением: из скриптов diag я выяснил, как с ним общаться.
  • Можно выполнять запись на экран eink из командной строки с помощью команды /usr/sbin/eips (документация находится здесь).
  • Я не смог найти очевидного переключателя «отключить демо-режим»: похоже, он встроен в ПО электронной книги на Java.
  • Следующие системные сервисы связаны с неподдерживаемыми функциями, ПО электронной книги или общением с Amazon: S50wan S70wand S75phd S81usbnetd S93webreaderd S94browserd S95framework S96boot_finished.

Общение с Wifid


Можно использовать встроенный wifid для подключения к wifi и управления профилями wifi. О, и надо помнить о том, что многие Kindle поддерживают WiFi только на 2,4 ГГц, имейте это в виду, если что-то не будет работать.

Перечисление количества профилей WIFI:

lipc-get-prop com.lab126.wifid profileCount

Показ содержимого профиля WIFI:

echo "{index=(0)}" | lipc-hash-prop com.lab126.wifid profileData

Удаление профиля WIFI:

lipc-set-prop com.lab126.wifid deleteProfile WIFIESSID

Создание профиля WIFI:

echo '{essid="WIFIESSID", smethod="wpa2", secured="yes", psk="WIFIPSK"}' | lipc-hash-prop com.lab126.wifid createProfile

Возможные варианты smethod: open,wep,wpa,wpa2 (если вы выберете open, то задайте для secured значение «no»).

WIFIPSK — это WIFI PSK, сгенерированный утилитой wpa_passphrase (которая есть в Kindle): обычная «wifi passphrase» не сработает.

Подключение профиля WIFI:

lipc-set-prop com.lab126.wifid cmConnect WIFIESSID

Отображение состояния подключения WIFI:

echo "{index = (0)}" | lipc-hash-prop -n com.lab126.wifid currentEssid

Внесение изменений в Root


Во многих из представленных ниже инструкций требуется изменение root-диска в kindle. Однако по умолчанию он монтируется в режиме read only. Чтобы решить эту проблему, запустим на kindle следующую команду:

mntroot rw

После завершения верните диск в режим read only, чтобы избежать нежелательных изменений:

mntroot ro

Установка Dropbear SSH


Я хотел иметь возможность подключения к kindle по ssh, поэтому решил установить ssh-демон dropbear. Разумеется, это устройство на ARM, поэтому мне нужно было или скомпилировать его самостоятельно, или где-то найти. К счастью, существует поддерживаемый разработчиками хак USBNET для kindle: я решил не использовать этот хак у себя, потому что хотел полностью контролировать своё устройство, но всё равно смог позаимствовать из него двоичный файл dropbear.

К сожалению, USBNET поставляется в собственном странном формате обновления Kindle, поэтому нужно извлечь из него двоичный файл:

На компьютере:

  • Скачать этот репозиторий git и скомпилировать его — это позволит нам декодировать обновления kindle.
  • Скачать kindle-usbnetwork-0.57.N-k4.zip отсюда и скопировать его в KindleTool/Release/.
  • cd KindleTool/Release/
  • Распаковать kindle-usbnetwork-0.57.N-k4.zip
  • ./kindletool extract Update_usbnetwork_0.57.N_k4_install.bin usbnet
  • cd usbnet
  • tar Jxf usbnet.tar.xz
  • Скопировать src/usbnet/bin/dropbearmulti на Kindle (я перемонтировал его как USB-устройство и скопировал файлы).

В Kindle:

  • cd /
  • mv /mnt/us/dropbearmulti /
  • chmod a+x /dropbearmulti
  • ln -sf /dropbear /dropbearmulti
  • ln -sf /dropbearkey /dropbearmulti
  • ln -sf /bin/scp /dropbearmulti
  • /dropbearkey -t rsa /dropbear_rsa_host_key

Преобразуем всё под мои проекты


Я переименовал все ненужные системные сервисы:

cd /etc/rc5.d; mv S95framework DISABLED.S95framework

Добавил собственный скрипт инициализации в /etc/rc5.d/S99adq, чтобы вносить свои изменения:

#!/bin/sh
NAME="adq"

case "$1" in

   start)
        # display some stuff!
        /usr/sbin/eips -c 20 20 "HELLO ADQ"
        IP=`ifconfig wlan0 | awk '/t addr:/{gsub(/.*:/,"",$2);print$2}'`
        /usr/sbin/eips 1 1 "IP Address: $IP"
        /usr/sbin/eips 1 2 "Root Password: <MY ROOT PASSWORD>"
        /usr/sbin/eips ""

        # connect to wifi and allow ssh in
        lipc-set-prop com.lab126.wifid cmConnect MYWIFISSID
        iptables -A INPUT -i wlan0 -p tcp --dport 22 -j ACCEPT
        /dropbear -r /dropbear_rsa_host_key
        mkdir -p /mnt/us/usbnet/etc
        echo "<MY SSH PUBKEY>" > /mnt/us/usbnet/etc/authorized_keys

        # expose shell over usb
        modprobe -r g_file_storage
        modprobe g_serial
        /sbin/getty -L 115200 ttyGS0 -l /bin/login &
        ;;

   stop)
        ;;
    *)
        msg "Usage: /etc/init.d/$NAME {start|stop}" W >&2
        exit 1
        ;;
esac

exit 0

Теперь устройство может:

  • При загрузке отображать на экране полезную информацию
  • Подключаться к wifi.
  • Использовать SSH через файрвол.
  • Запускать ssh-демон dropbear.
  • Добавлять мой публичный ключ ssh в нужное для dropbear место.
  • Удалять USB-функцию «притворяемся диском»
  • Заставлять его «притворяться последовательным устройством» через USB и отображать запрос логина: если подключить его через USB и использовать minicom, я получу запрос логина на случай, если что-то пойдёт не так.

Теперь при загрузке мой kindle выглядит так и я могу подключаться как root по ssh.

image

Всё практически готово: теперь я могу подключаться по ssh к kindle и у меня есть несколько уровней последовательной консоли на случай, если что-то пойдёт не так. Это довольно удобная система разработки под Linux с e-ink, подключением по wifi и с работой от аккумулятора.

Последнее улучшение — я убрал некоторые защёлки с задней крышки и установил её на место.

Дальнейшее развитие


Похоже, что эта библиотека (FBInk) сможет заменить ПО Amazon eips; вероятно, оно будет удобнее, если я захочу интегрировать дисплей с моим собственным ПО.



На правах рекламы


Эпичные серверы — это надёжные серверы на Linux или Windows с мощными процессорами семейства AMD EPYC и очень быстрой файловой системой, используем исключительно NVMe диски от Intel. Попробуйте как можно быстрее!