Я давно уже интересовался темой авторизации медиа приставок в портале Stalker, но было не до этого. Однажды ко мне случайно попала приставка MAG250 от Infomir и я решил занятся этим вопросом.
Первым делом я разобрал приставку, припаял к разьёму кабель и соединил с компом. Запустив терминал программу, меня порадовал знакомый U-Boot. Процесс загрузки можно было также прервать, нажав любую клавишу (обычно такие фишки производитель отключает и приходится тратить много времени, чтобы привести U-Boot в нужное состояние). Доступ с правами root был тоже доступен по ssh.
Приставка оборудована 256МБ DRAM и двумя флешками, NOR 1 МБ и NAND 256МБ. С NOR по-ходу грузится U-Boot, который загружает с NAND ядро и файловую систему.
Приставка авторизирует себя в портале Stalker, посылая кучу всякои информации, такой как, например, тип, версия прошивки, версия оборудования, серийный номер и т.д. Но меня интересовал конкретно параметр device_id, который выдавала функция gSTB.GetUID(). На первый взгляд это был хэш типа SHA256 или MD5. Ссылаясь на официальную документацию soft.infomir.com/stbapi/JS/v343/gSTB.html#.GetUID, функция может принимать до двух параметров, но первым делом интересовал вариант без параметров. Загрузив stbapp в IDA, без труда находим эту функцию.
Пройдя немного дальше, видим интересный момент
Здесь программа выделяет 0x41 байт памяти, обнуляет его и вызывает функцию драйвера /dev/stapi/stevt_ioctl, передав ей этот участок памяти и параметр 0xC004C919. Стало быть, за генерацию UID отвечает некий драйвер stevt_ioctl. Чтобы проверить это, я быстро набросал такой код:
Запустив его на приставке, я увидел знакомый UID.
Следующим этапом будет разборка драйвера stapi_ioctl_stripped.ko, который находится в /root/modules. Загружаем драйвер в IDA и находим обработчик 0xC004C919 ioctl (я назвал эту функцию calcHash).
Здесь есть три интересных момента. Сначала копируется 0x41 байта памяти из пространства пользователя в пространство ядра (это как раз и есть то, что передаётся пользователем и в нашем случае состит из нулей), вызывается функция get_mem_type (по ходу дела в самом ядре) и результат (опять же 0x41 байт) копируется затем в адресную область пользователя. Для поиска адреса функции get_mem_type я видел две возможности: просто посмотреть файл /proc/kallsysms, надеясь что доступ не был ограничен, ну или в противном случае написать на ассемблере для самого драйвера вставку, которая в нужном месте выдаст значение регистра r0. Заглянув в /proc/kallsysms, я был приятно удивлён и нашёл адрес функции get_mem_type 0x8080E380.
Для дальнешего анализа нужно будет анализировать ядро. Само ядро можно найти в прошивке производителя, либо снять дамп, используя U-Boot
ну или же смонтировать нужный раздел.
Исходя из информации U-Boot, ядро грузится по адресу 0x80800000, а точка входа находится в 0x80801000. Загружаем ядро в IDA и находим функцию get_mem_type.
Проанализировав код, я выявил этот участок, который предположительно возвращял UID.
Стало быть UID хранится по адресу 0х80D635EC. Далее ищём в IDA, где формируется это значение. Это было в функции init_board_extra (полный листинг я преводить не буду)
Вот стало быть то самое неизвестное значение по адресу регистра r4, из которого вычисляется интересующий хэш (fill_hash кстати вырешивал SHA256). Мне очень не терпелось узнать что же это такое и я быстренько написал вставку на ассемблере, которая через функцию printk выдавала содержимое памяти по адресу регистра r2. Модифицировав таким образом ядро я сделал новый uImage и закунул его на USB накопитель. И в терминале U-Boot задал:
Но после последний команды меня ждала такая печалька
U-Boot вежливо отказался грузить моё новое ядро.
Чтобы убедить U-Boot загружать моё ядро, я решил патчить его в памяти его же командой mw. Для начала я сделал полный дамп NOR флэш, который находится по адресу 0xA0000000. Загнав дамп в IDA я выявил адрес памяти, куда U-Boot сам себя копировал. Это был 0x8FD00000. Опять же сделав дамп этога участка памяти и запустив IDA, я без труда нашёл функцию которая проверяла сигнатуру. Если всё было правильно, она возвращяла 0. Причем вызывалась она в двух разных местах.
Что конкретно делала эта фукция мне было не интересно. Ей нужно было просто возвращать 0 вот так:
Соответвующий код для U-Boot был теперь таким:
Тут U-Boot с радостью загрузил моё ядро, которое выдало
И так, из чего же состоял UID? Это было какой-то неизвестный номер из 8 байт, серийный номер приставки, МАС адрес, тип приставки и кусок мусора. Осталось выяснить, что это был за неизвестный номер и откуда брался мусор. Я снова вернулся к функции init_board_extra.
Неизвестный номер брался из этого участка кода:
Здесь при помощи функции __ioremap ядро получало доступ к физической памяти по адресу 0x00000000 (что являлось адресом NOR флеша), записывало 0x0F в адрес 0x00000000, затем 0x98 в адрес 0x000000AA и читало 8 байт, начиная с адреса 0x000000C2. И что же это такое? Это команды протокола CFI, с которым ядро общалось с NOR. 0x0F приводило NOR в исходное состояние, а командой 0x98 переключалов модус CFI. В этом модуле по адресу 0x000000C2 находится Security Code Area или 64-bit unique device number. Т.е. неизвестный номер-это уникальный номер NOR флеша. Ниже приведён дамп CFI идентификации.
Свой дамп можно сделать прямо в U-Boot'е, задав
Кусок мусора был просто обыкновенным набором символов в 32 байта, которые были вшиты в само ядро
Причём этот мусор обрабатывался перед использованием шифровальной фунцией swap_pairs, которая просто меняла положение байт
Изходя из полученой информации осмелюсь предположить, что в базе данных производителя имеется информация каждого ID NOR флэша и соответствующие серийный номер и МАС адрес.
Подобрать всё это конечно невозможно, но можно будет написать свой софт, который будет полностью эмулировать приставку.
Подготовка
Первым делом я разобрал приставку, припаял к разьёму кабель и соединил с компом. Запустив терминал программу, меня порадовал знакомый U-Boot. Процесс загрузки можно было также прервать, нажав любую клавишу (обычно такие фишки производитель отключает и приходится тратить много времени, чтобы привести U-Boot в нужное состояние). Доступ с правами root был тоже доступен по ssh.
Приставка оборудована 256МБ DRAM и двумя флешками, NOR 1 МБ и NAND 256МБ. С NOR по-ходу грузится U-Boot, который загружает с NAND ядро и файловую систему.
Функция GetUID()
Приставка авторизирует себя в портале Stalker, посылая кучу всякои информации, такой как, например, тип, версия прошивки, версия оборудования, серийный номер и т.д. Но меня интересовал конкретно параметр device_id, который выдавала функция gSTB.GetUID(). На первый взгляд это был хэш типа SHA256 или MD5. Ссылаясь на официальную документацию soft.infomir.com/stbapi/JS/v343/gSTB.html#.GetUID, функция может принимать до двух параметров, но первым делом интересовал вариант без параметров. Загрузив stbapp в IDA, без труда находим эту функцию.
Пройдя немного дальше, видим интересный момент
Здесь программа выделяет 0x41 байт памяти, обнуляет его и вызывает функцию драйвера /dev/stapi/stevt_ioctl, передав ей этот участок памяти и параметр 0xC004C919. Стало быть, за генерацию UID отвечает некий драйвер stevt_ioctl. Чтобы проверить это, я быстро набросал такой код:
Запустив его на приставке, я увидел знакомый UID.
stevt_ioctl
Следующим этапом будет разборка драйвера stapi_ioctl_stripped.ko, который находится в /root/modules. Загружаем драйвер в IDA и находим обработчик 0xC004C919 ioctl (я назвал эту функцию calcHash).
Здесь есть три интересных момента. Сначала копируется 0x41 байта памяти из пространства пользователя в пространство ядра (это как раз и есть то, что передаётся пользователем и в нашем случае состит из нулей), вызывается функция get_mem_type (по ходу дела в самом ядре) и результат (опять же 0x41 байт) копируется затем в адресную область пользователя. Для поиска адреса функции get_mem_type я видел две возможности: просто посмотреть файл /proc/kallsysms, надеясь что доступ не был ограничен, ну или в противном случае написать на ассемблере для самого драйвера вставку, которая в нужном месте выдаст значение регистра r0. Заглянув в /proc/kallsysms, я был приятно удивлён и нашёл адрес функции get_mem_type 0x8080E380.
Ядро
Для дальнешего анализа нужно будет анализировать ядро. Само ядро можно найти в прошивке производителя, либо снять дамп, используя U-Boot
ну или же смонтировать нужный раздел.
Исходя из информации U-Boot, ядро грузится по адресу 0x80800000, а точка входа находится в 0x80801000. Загружаем ядро в IDA и находим функцию get_mem_type.
Проанализировав код, я выявил этот участок, который предположительно возвращял UID.
Стало быть UID хранится по адресу 0х80D635EC. Далее ищём в IDA, где формируется это значение. Это было в функции init_board_extra (полный листинг я преводить не буду)
Вот стало быть то самое неизвестное значение по адресу регистра r4, из которого вычисляется интересующий хэш (fill_hash кстати вырешивал SHA256). Мне очень не терпелось узнать что же это такое и я быстренько написал вставку на ассемблере, которая через функцию printk выдавала содержимое памяти по адресу регистра r2. Модифицировав таким образом ядро я сделал новый uImage и закунул его на USB накопитель. И в терминале U-Boot задал:
usb start
fatload usb 0:1 80000000 uImage
bootm
Но после последний команды меня ждала такая печалька
U-Boot вежливо отказался грузить моё новое ядро.
Правка U-Boot
Чтобы убедить U-Boot загружать моё ядро, я решил патчить его в памяти его же командой mw. Для начала я сделал полный дамп NOR флэш, который находится по адресу 0xA0000000. Загнав дамп в IDA я выявил адрес памяти, куда U-Boot сам себя копировал. Это был 0x8FD00000. Опять же сделав дамп этога участка памяти и запустив IDA, я без труда нашёл функцию которая проверяла сигнатуру. Если всё было правильно, она возвращяла 0. Причем вызывалась она в двух разных местах.
Что конкретно делала эта фукция мне было не интересно. Ей нужно было просто возвращать 0 вот так:
mov #0x0, r0
rts
nop
Соответвующий код для U-Boot был теперь таким:
usb start
mw.l 8fd0ec08 000b200a;
mw.l 8fd0ec0c 00900009
fatload usb 0:1 80000000 uImage
bootm
Тут U-Boot с радостью загрузил моё ядро, которое выдало
EF0F3A38FF7FD567012016J04501200:1a:79:23:7e:а2MAG250pq8UK0DAOQD1JzpmBx1Vwdb58f9jP7SN
Полный анализ
И так, из чего же состоял UID? Это было какой-то неизвестный номер из 8 байт, серийный номер приставки, МАС адрес, тип приставки и кусок мусора. Осталось выяснить, что это был за неизвестный номер и откуда брался мусор. Я снова вернулся к функции init_board_extra.
Неизвестный номер брался из этого участка кода:
Здесь при помощи функции __ioremap ядро получало доступ к физической памяти по адресу 0x00000000 (что являлось адресом NOR флеша), записывало 0x0F в адрес 0x00000000, затем 0x98 в адрес 0x000000AA и читало 8 байт, начиная с адреса 0x000000C2. И что же это такое? Это команды протокола CFI, с которым ядро общалось с NOR. 0x0F приводило NOR в исходное состояние, а командой 0x98 переключалов модус CFI. В этом модуле по адресу 0x000000C2 находится Security Code Area или 64-bit unique device number. Т.е. неизвестный номер-это уникальный номер NOR флеша. Ниже приведён дамп CFI идентификации.
Свой дамп можно сделать прямо в U-Boot'е, задав
mw.w a0000000 f0
mw.w a00000aa 98
md.b a1000000 100
Кусок мусора был просто обыкновенным набором символов в 32 байта, которые были вшиты в само ядро
Причём этот мусор обрабатывался перед использованием шифровальной фунцией swap_pairs, которая просто меняла положение байт
[0x00000003]<->[0x0000000F]
[0x00000005]<->[0x0000001F]
[0x00000009]<->[0x00000002]
[0x0000000A]<->[0x0000001D]
[0x00000010]<->[0x00000015]
[0x00000004]<->[0x00000013]
[0x0000000D]<->[0x00000018]
Изходя из полученой информации осмелюсь предположить, что в базе данных производителя имеется информация каждого ID NOR флэша и соответствующие серийный номер и МАС адрес.
Подобрать всё это конечно невозможно, но можно будет написать свой софт, который будет полностью эмулировать приставку.
Fregl
Я так и не понял собственно говоря что автор конкретно хотел в этом посте написать? Какая приставка, зачем ему UID, т.е. входные данные и для чего конечный результат
Nick_Maverick
ИМХО, автор упомянул Stalker в заголовке — это такой портал для IPTV. А авторизация в нем построена в том числе и на номерах дозволенных устройств. Т.е если сделать устройство, которое бы забирало контент с этого портала — надо как то подставлять серийник. Вот и описано как это и откуда.