Tuesday, July 17, 2012

DSL-модем

История мелкого разбора протокола

Решил немного проверить свои знания Linux/GNU философии. По идее все что создано руками человека может быть другим человеком понято и изменено, не будем рассматривать вариант разрушено, оставим на волю природы разрушать и очищать от неудачных творений человеческой разумности. И так есть устройство гордо именуемое как ADSL роутер обладающее очень важной особенностью признанной людьми в развитых странах осуществлять важнейшую потребность людей в глобальной общении и обладающий гигантским недостатком это изобретено не нами, нужно обязательно изучить и понять как же оно работает и восполнить жажду новой интересной, но совершенно не нужной информацией. Оно базируется на разработках которые вот уже лет десять воплощаются в серии устройство состоящих из множества интересных возможностей и технологий созданных на базе RISC архитектуры используемой во многих высокопроизводительных компьютерах.

Устройство содержит созданный на базе референсного дизайна adsl модема содержащего процессор с поддержкой usb, pci, rs232 портов, jtag дебаг интерфейсом, eth/wlan сетевым интерфейсом, adsl/vdsl модемами(отдельный DSP процессор). Система обычно содержит, если судить по известной мне информации вне процессора дополнительные сетевой маршрутизатор на 4 порта, внешний wifi модуль того-же производителя и дополнительный логику преобразования сигналов для dsl(ADSL2+ 5V Line Driver - похоже на каку-то трансформаторную развязку). Производители модемов в разной степени меняют эту реализации под свои нужды - но без значительны изменений между моделями различных производителей, и прошивку от одного модема при желании можно поставить на другой. Состав поддерживаемых интерфейсов/реализация элементов(внутри основного чипа/вне) изменяется между сериями, но тоже не значительно - в основном, как обычно, по пути расположения в основной чипе всей логики.

Из этого списка компонентов только dsl интерфейс не поддерживаться сторонними прошивками остальные части достаточно стандартные и благодаря открытой документации или реверс-инженерингу поддерживаются. Основным недостатком является отсутствие существенных обновлений прошивки даже самые новые прошивки одного производителя используют ядро 2.6.9 и для сборки требуют старые дистрибутивы (на fedora 9 - можно собирать DSL-2650U, 2640 - RedHat 9.0).

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

Но сначала нужно посмотреть что происходит на реальном оборудовании, когда мы пытаемся получить информацию о соединении, для случая с модема с usb это просто - на флешку отформатированую в fat32 скидываем откомпилированый strace и смотрим что происходит. strace выводит что adslcrl открывает файл устройства со стандартными флагами без каких-то нестандартных особенностей открытия и через ioctl передает первым параметром какую-то магическую константу, вторым параметром что-то похожее на адрес. Ничего туда не пишет и не читает. Делаем несколько запусков и убеждаемся что он всегда делает одни и те же действия с одинаковой константой и близкими значениями адреса.

Дальше мы уже можем переключиться на эмулятор чтобы получить больше подробностей.

Непосредственно брать образ файловой системы из образа прошивки не нужно - формат опять таки закрытый, но есть частичная документация получения реверс-инженерингом, можно поступить проще и взять этот образ из дерева исходных кодов при сборке. Он представляет собой обычный образ сжатой файловой системы Squashfs(targets/DSL-2650U/rootfs.img) старой версии(version 2.0) поэтому непосредственно открыть на новых дистрибутивах его нельзя, они уже эту версию не поддерживают - поэтому нужно создать образ с использованием более распространенной файловой системы:

  1. dd if=/dev/zero of=empty.img count=32768 
  2. mkfs.ext3 empty.img 

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

Далее качаем, если еще этого не сделали образ дебиана для mips мальта. И запускаем с нашим новым пользовательским окружением.

Если почитать блог можно подтвердить предположение, что для других модемов тоже используется магическая константа и адрес. Значит нужно создать модуль для того чтобы посмотреть что же все-же передается. В ранее указанном блоге делается подмена системных функций - более похожая на создании вируса c сокрытием процессов. Проще создать модуль который будет выдавать все что ему приходит и пробует вернуть похожее на реальный ответ назад. В ранее указанном блоге используется дамп 256 байт области переданной как второй параметр. Дампим пока этот объем - и видим что по этому адресу расположены выравненные по слову числа похожие на 3 адреса и пара констант. Далее пишем программу которая создает такой буфер с тремя выделениями памяти и смотрим, что записалось по этим адресам, если запустить программу на реальном оборудовании - сначала ставим размер буферов в 256 байт - видим что память по всем адресам изменилась, память выделенная под входные параметры не изменилась. Пробуем увеличивать размеры буферов до 512, 1024, 2048 - видим что значения записываемые модулем ядра на реальном оборудовании не влазят в буферы меньше 2k байт - похоже нужно использовать буферы в 2048. И сделав так видим что заполняется только первый буфер и так как мы используем выделение данных в куче адреса у нас немного отличаются от оригинальной программы. Поэтому предполагаем что она выделяет память в стеке, и мы просто видим дамп стека.

Далее инициализируем память для первого буфера в 0, смотрим на дамп, инициализируем в -1 смотрим в дамп и видим что в реальности меняется только примерно 1.5k байт, можем предположить, что это и есть реальный размер. Смотрим в дамп переданных ядру данных, и видим что одна константа совпадает с полученным размером, можно предположить, что именно так передается размер выделенной памяти. Уменьшаем размер передаваемых данных до 0x20 и видим что ничего не поменялось - можно предположить что это есть примерный размер входного буфера.

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

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