В этой статье реализуем hexdump на PHP, изучим строение тегов ID3v2 с информацией о содержимом MP3-файлов и будем их менять базовыми средствами языка. Заодно освоишь и сам PHP, что для пентестера будет совсем не лишним.

Современные технологии позволяют держать всю аудиоколлекцию под рукой. Подкасты, лекции и аудиокниги всегда с собой. Но такая коллекция требует организации — нужно знать, где что находится. Для цифровых аудиозаписей ярлыками служат метаданные, записанные в медиафайлы. Музыка чаще всего хранится в MP3, а стандарт хранения метаданных в MP3 называется ID3.

Как FFmpeg подвел меня

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

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

Аудиоданные в MP3-файле представляют собой последовательность блоков, каждый со своим заголовком. Декодеры MP3 ищут в потоке данных корректные заголовки и обрабатывают соответствующие блоки, игнорируя все остальное. Поэтому фрагменты можно склеить в монолитный файл простой командой. В Windows:

COPY /B part1.mp3 + part2.mp3 + part3.mp3 all.mp3

В Linux:

cat part1.mp3 part2.mp3 part3.mp3 > all.mp3

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

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

Исходные тексты и бинарные файлы Mp3Wrap можешь загрузить с официального сайта. Для восстановления файлов из монолита понадобится утилита Mp3splt. В статье мы не будем ее использовать, но тебе могут пригодиться другие ее функции. Она позволяет разбивать MP3-, OGG- и FLAC-файлы на части фиксированной длительности, по заданным отметкам времени или с помощью встроенного детектора тишины. Далее покажу обработку MP3-файлов из альбома vintage исполнителя Robert80z.

Чтобы объединить треки в файл album_MP3WRAP.mp3, выполнил команду mp3wrap album_MP3WRAP.mp3 *Robert80z*.mp3

Созданный монолитный MP3-файл почти полностью меня устроил, если бы не один принципиальный момент. В файле начисто отсутствовали метаданные о записанных аудиоматериалах.

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

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

ffmpeg -i album_MP3WRAP.mp3 -c:a copy -id3v2_version 3 -metadata album='vintage' music_MP3WRAP.mp3

И проверил целостность результата командой mp3wrap -l music_MP3WRAP.mp3

Вместо списка файлов-фрагментов на экране появилось сообщение: Error: this is not a valid mp3wrap file!

Программа FFmpeg сочла данные, внедренные в файл утилитой Mp3Wrap, информационным мусором и вместе с исправлением метаданных произвела «уборку». Поэтому от привычного инструмента пришлось отказаться.

Выбор подхода

Быстрый поиск в интернете подсказал три подхода к решению задачи: онлайн-сервисы, специализированные утилиты, прямое редактирование MP3-файла.

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

Решил научиться редактировать описания MP3-файлов на самом низком уровне. Поскольку ручная работа байт за байтом в двоичном редакторе вряд ли доставила бы удовольствие, стал выбирать средство автоматизации.

Как оказалось, в стандартных библиотеках знакомых языков программирования нет средств работы с метаданными медиафайлов. Для Python обычно используют дополнительный модуль Mutagen.

Тогда почему бы не попробовать PHP? На мой взгляд, у некоторых специалистов сложилось к нему снисходительное отношение как к несерьезному языку. В управляющих структурах PHP действительно есть черты других языков. Но, как и они, PHP — универсальный язык программирования для решения любых задач обработки данных. Тебя, как хакера, не может не вооду­шевить, что PHP, в отличие от Python, можно обнаружить практически на любом веб-сервере — это стандартный компонент даже бесплатного shared-хостинга.

В этой статье будем использовать PHP в режиме командной строки, без привязки к веб-серверу. Проверь доступность PHP командой php -v: она должна отобразить его версию. На момент написания статьи актуальна версия 8.5.8, но описанные сценарии будут работать и в версии 5.5.38. Ну а если вместо номера версии появилось сообщение о неправильной команде, PHP надо установить и добавить в пути.

Подготовка инструмента

Для установки PHP в Linux на базе Debian или Ubuntu выполни команду sudo apt install php-cli php-mbstring

В Windows загрузи с официального сайта ZIP-архив с бинарными файлами для нужной архитектуры — x86 или x64. Там представлены два варианта: потокобезопасный Thread Safe и для выполнения в отдельных процессах Non Thread Safe. Если не знаешь, какой нужен, выбирай более универсальный Thread Safe. Для задач из этой статьи подойдет любой вариант.

Распакуй дистрибутивный ZIP-архив в каталог на диске, например C:\PHP, и скопируй конфиг php.ini-development в php.ini. Можешь добавить путь к этому каталогу в переменную среды PATH. Иначе для выполнения сценария script.php придется набирать в командной строке полный путь.

Чтобы выполнять описанные в статье сценарии, надо активировать модуль работы с текстом в многобайтовых кодировках. Для этого в конфиге php.ini надо раскомментировать строку ;extension=mbstring — удалить начальную точку с запятой. Возможно, придется указать путь к дополнительным модулям: extension_dir = 'ext'.

Если ты раньше не использовал PHP, нужны некоторые пояснения. Исходный текст сценария сохраняй в простом текстовом файле между тегами <?php и ?>. Все имена переменных в PHP начинаются со знака доллара. Это отличает их от других идентификаторов и ключевых слов и предотвращает множество ошибок. Константа PHP_EOL обозначает символ перевода строки, принятый в используемой операционной системе.

Проблем с отображением символов национальных алфавитов не возникнет, если кодировка файла соответствует локали операционной системы. Узнать кодировку локали в Linux можно командой locale | grep LANG=. Скорее всего, это будет UTF-8. В Windows команда MODE CON: CP обычно показывает CP866. Для единообразия проще переключить командную строку Windows на UTF-8 командой CHCP 65001.

Чтобы больше не возвращаться к настройке среды выполнения, создай текстовый файл start.php в кодировке UTF-8 без BOM с таким сценарием: <?php $intenc = mb_internal_encoding (); echo 'Внутренняя кодировка: $intenc', PHP_EOL; ?> Затем попробуй выполнить сценарий командой php start.php. Возможны несколько вариантов. На экране появилось сообщение о внутренней кодировке многобайтовых строк PHP. Она может отличаться от кодировки файлов и локали — пусть это тебя не смущает. Тест пройден, двигайся дальше. Появилось сообщение о вызове неопределенной функции mb_internal_encoding. PHP не смог подключить модуль mbstring. Проверь текст программы, настройки PHP и наличие модуля. Операционная система не смогла выполнить php. Либо PHP не установлен, либо путь к нему не прописан в переменной окружения PATH. Исправляй! Вместо сообщения о внутренней кодировке отобразилось содержимое файла start.php. Скорее всего, ты забыл или неправильно набрал префикс <?php, поэтому интерпретатор не выполнил файл. Отобразилось сообщение об ошибке, например PHP Parse error. Проверь все символы, исправь ошибку и попробуй снова.

Изготовление приспособления

Надеюсь, ты справился с установкой и настройкой PHP. Идем дальше.

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

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