Описание
Это утилита для для распаковки и упаковки прошивок IP-телефонов Cisco, которые основываются на формате, который сам себя называет CNU_File_Archive_3.0. Среди них прошивки для телефонов серии 79XX, в частности, 7911/7906, 7941/7961, 7970/7971.
Прошивки серий 3911, 7931 и других более новых моделей имеют другой формат, и не могут быть распакованы этой утилитой.
История создания
В далеком 2007 году моя работа была связана с инсталляцией PBX-систем и разных интеллектуальных и не очень сервисов на базе Asterisk, и через мои руки прошло некоторое количество SIP-телефонов, в том числе Cisco. Изначально телефоны Cisco ориентированы на работу в окружении Cisco Call Manager, и, соответственно, все решения по конфигурированию и провиженингу телефонов спрятаны в нем. Некоторые телефоны 79xx серии даже не имеют средств редактирования конфигурации через веб-интерфейс или меню телефона, их конфигурирование осуществляется только через TFTP или другие системные интерфейсы.
Смена прошивки осуществляется также через TFTP. Усилиями коллективного интернетного разума был разобран формат файлов конфигурации, и найдены настройки, необходимые для работы этих телефонов с Asterisk. См. http://www.voip-info.org/wiki/view/Asterisk+phone+cisco+79xx. Если честно, я не совсем понимаю, что за сложности люди испытывали в том, чтобы снять полный дамп этих конфигов с телефонов или перехватить их по сети при провиженинге с Call Manager-a. И почему до сих пор не выложена XML-схема конфигурационных файлов, которую из самого Call Manager-a наверняка тоже вытащить можно. Ну да ладно, это сейчас к делу не относится.
В целом, все работает, все довольны. И все было бы хорошо, но во-первых, средства удаленного управления этими телефонами на тот момент отсутствовали, а получить root-доступ к консоли не представлялось возможным, т. к. в прошивке имелось всего два пользователя - manager/viewer и debug. Вход под ними хоть и позволял проконтролировать какие-то параметры или увидеть отладочную информацию, но сделать какую-либо более тонкую настройку телефона было невозможно. Еще есть возможность задать эккаунт из конфигурационного файла, но по сути дела это обычный бесправный пользователь со специальным программным шеллом, что нас не устраивает. Ну и во-вторых, хотелось понять, на чем же работает это устройство, тем более что внутри крутится интерфейс пользователя, написанный на Java.
На различных форумах любознательные граждане пытались выяснить root-пароль к ним, но это, естественно, ни к чему не привело - кто ж вам его даст, чтобы вы ковыряли их новенькие телефоны своими грязными руками. Тогда стало понятно, что нужно расширить и углубить, так сказать, а значит, разобрать саму прошивку.
Анализ файлов прошивки
Прошивка распространяется в виде .sbn- или .zip-архива. Собственно еще до поисков информации об этих телефонах в сети первым делом я попробовал посмотреть на .sbn-файл. Беглый осмотр и поиск известных сигнатур файлов показал, что это просто tar.gz с присобаченной цифровой подписью. Цифровая подпись нам пока неинтересна, сначала надо разобрать сам файл. Безжалостно вырезав ее в vi, я распаковал получившийся .tar.gz.
Внутри некоторое количество .sbn- и .loads-файлов. Последние предназначены для того чтобы указать телефону, какие файлы прошивки грузить при загрузке с TFTP, когда прошивка выкладывается на Cisco Call Manager или TFTP-сервер в случае работы с Asterisk. Это просто текстовые файлы с именами файлов прошивки. Нам же нужно разбирать .sbn. Теперь уже понятно, что это такой же подписанный контейнер непонятного пока формата.
С чего православно начинать анализ незнакомого файла? Я не знаю, но начал с открытия файла с прошивкой в vi :). Беглый осмотр показал наличие текстов, характерных для несжатого и незашифрованного файла - видны заголовки PNG-файлов, системные сообщения внутри каких-то бинарных модулей. Но самое главное - похоже есть список файлов, и он не зашифрован. Я до cих пор не знаю, возможно, это какой-то известный формат контейнера, но сразу я аналогов не нашел, а искать и перебирать форматы мне было лень, поэтому я решил написать распаковщик.
Так как в файле наверняка хранятся смещения или абсолютные адреса частей содержимого, то нужно было правильно определить начало заголовка. Примерно посмотрев где заканчивается подпись в основном архиве прошивки, я понял куда надо смотреть, и без особых колебаний ее обрезал.
Дальнейшие копания в файле показали, что после zerofill-дыры за началом файла существует набор небольших секций с повторяющейся структурой. Я решил, что это таблица размещения файлов и начал анализировать пары и четверки байт, полагая, что вряд ли в файловом контейнере смещения или указатели длины файлов будут однобайтовыми. Выбрав файлы известного формата (несколько .png), следующие друг за другом в списке файлов в тексте прошивки, я записал смещения их заголовков, и начал сравнивать записи в таблице размещения.
В общем, впоследствии все мои догадки подтвердились, это действительно оказалась таблица смещений, а точнее абсолютных адресов в файле. Что меня затормозило, так это неправильный выбор начала файла прошивки, в результате я получал неверные данные по адресам, указанным в таблице адресов, но потом я обратил внимание, что адреса почти правильные, плюс-минус каких-то тридцать байт =) И В сответствии с этим скорректировал свои представления о действительном начале файла с прошивкой. Теперь я знал где начинается сам файл с прошивкой и имел представление о формате хранения.
После написания пары пробных версий программы для распаковки со всякими автоматическими попытками найти начало первого хранимого файла я заметил, что количество файлов и информация об адресе первого файла тоже есть в заголовке, просто в азарте разбора секции размещения файлов я их пропустил =) Кроме того, оказалось, что под Linux нет нормального консольного hex-редактора, поэтому приходилось использовать всякие там hexdump-ы, biew-ы и другую малоюзабельную хуеторию, хотя может я просто недостаточно хорошо искал.
Формат оказался на редкость странным - в заголовке какая-то дыра, не то для future use, не то для загрузчика или распаковщика, который возможно планировалось реализовать. Размещение некоторых элементов данных тоже странное, и есть некоторая избыточность хранимых смещений, но возможно так сделано для скорейшей идентификации и проверки прошивки на корректность загрузчиком при обновлении.
Возможно также, что это как-то связано с потенциальной работой прошивки непосредственно с flash, без загрузки ее в память, но я не специалист по встраиваемым системам и контроллерам. Кроме того, гадать, почему в кружке китайско-индийской дружбы имени Cisco (о чем красноречиво свидетельствуют имена в цифровых подписях и скриптах в прошивке) решили сделать так, а не иначе, бессмысленно - сказывается различие наших культур, хаха.
Ладно, дальше даю формат, смотрите сами.
Формат прошивки
Это удивительно, но прошивка начинается там, где заканчивается подпись файла.
0x0D 0x0D - разделитель после цифровой подписи, это два перевода строки, дальше идет прошивка. Иногда они отсутствуют, подпись отделяется от файла просто нулевым байтом.
Я описываю смещения в файле прошивки исходя из того, что подпись из файла удалена.
Подписи на английском, кому нужно, тот разберется, а зарубежным товарищам возможно тоже будет интересно.
| Begin | End | Data Type | Item | Description |
| 0x00 | 0x13 | bytes | Signature | CNU_File_Archive_3.0 |
| 0x14 | 0x31 | bytes | Hole | Unused/Reserved (zerofill) |
| 0x32 | 0x33 | dword | FileCount | Number of files in archive |
| 0x34 | 0x37 | dword | ContentOffset | First byte of first file |
| 0x38 | 0x4B | bytes | Signature | Copy of file signature (for compatibility?) |
| 0x4C | 0x247 | bytes | Hole | Unused/Reserved (zerofill) |
| 0x248 | 0x248+SizeOf(FileRec)*FileCount - 1 | records of dwords | FileTable | File table (see File table record format) |
| 0x248+SizeOf(FileRec)*FileCount | ContentOffset-1 | strings | FilenameList | List of file names |
| ContentOffset | EOF | bytes | Content | Archived Files |
Формат записи в таблице файлов
| Begin | End | Data Type | Item | Description |
| 0x00 | 0x03 | dword | FlagA | Can be 6 or 7. 6 seems to be kernel/loader file, 7 - usual file |
| 0x04 | 0x07 | dword | FlagB | 2. File type or mode? |
| 0x08 | 0x0B | dword | Size | Size of file |
| 0x0C | 0x0F | dword | Timestamp | File UNIX timestamp |
| 0x10 | 0x13 | dword | FilenameOffset | Absolute offset to file name string |
Таким образом, одна запись в таблице файлов имеет размер 20 байт, это 5 чисел в dword-ах. Таких записей в этой таблице по числу файлов в архиве.
После таблицы файлов следует список имен файлов, содержащихся в архиве. Это просто строки C, содержащие полный путь к каждому файлу, заканчиваются нулевым байтом, других разделителей нет. На начало каждой из строк указывает FilenameOffset в соответствующей файлу записи в таблице файлов. Названий каталогов в прошивке нет, они получаются из путей файлов, или указываются флагами.
После последнего имени файла начинается непосредственно контент - содержимое файлов архива без разделителей, подряд.
