Найти тему
BASH DAYS | Linux Factory

Zero bytes или magic нули в Linux

Оглавление

Сегодня будет про zero bytes. Скорее всего тут единицы про это знают и слышали, значит самое время. Будет интересно и познавательно, рекомендую почитать.

Термин Zero bytes / Magic zero bytes / Нулевые байты в Linux обычно относят к специальному значению байт 0x00, которое может использоваться для различных целей в контексте файловой системы и прочего.

Так, стоп, ничо не понятно и даже не интересно. Давай сразу на котиках, погнали в нашу лабораторию. Запускаем:

read < /dev/zero

Этой командой я читаю нулевые байты с помощью read. По дефолту read читает стандартный ввод. Передаем на стандартный ввод магические нули из устройства /dev/zero и генерим нулевые байты. Прекратить это безобразие можно комбинацией: CTRL+C

Вообще /dev/zero это фиктивный файл, который используется для создания файлов, заполненных нулями. А зачем он нужен? Ну например, чтобы отформатировать диск и забить его нулями, чтобы потом никто не смог восстановить данные которые ты удалил. Ну и для экспериментов всяких.

Так, теперь по нашей команде. Запустили, ничего не происходит. Но на самом деле происходит следующее: Оболочка с помощью системного вызова read читает в свой буфер нулевые байты из /dev/zero. Затем буфер обрабатывается по одному символу, а затем символы помещаются в массив.

Содержимое этого массива будет присвоено переменной заданной при запуске read. По умолчанию эта переменная называется REPLY. То есть если в read не передать название переменной, то все что ты введешь в нее, очутится в переменной REPLY.

read
echo "Ты ввел: $REPLY"


Вернемся к нашей бесконечной команде, которую запустили в начале поста. Команда так и будет выполняться, так как хочет встретить разделитель строк NL-ASCII или New Line ASCII. Новая строка или «\n».

А новой строки, то нет. Одни нулевые байты, а эти байты пропускаются. Ну и так, как оболочка не может найти конец строки, получается бесконечный цикл.

Есть такая штука, называется C-string

C-string - последовательность символов в языке Cи, завершающаяся нулевым символом `\0`. В языке Cи строки представлены массивами символов, где последний символ должен быть нулевым символом, чтобы указать конец строки.

Ну дак вот, для Си нулевой байт это конец строки. Например, функция печати строки выведет символы с начала массива до нулевого байта. Нулевой байт является неким стопером. Если вставить нулевой байт в середину строки, то все что после нулевого байта никогда не выведется на экран.

Ща покажу как это работает

cd /tmp
cp $(which true) .


Копируем утилиту true в папку /tmp, будем ее патчить нулевыми байтами.

Смотрим что она нам выводит:

./true --version

Выводит мого нвсего, меня интересует строка Jim Meyering. Теперь нужно узнать смещение этой строки в бинарном файле.

strings -dtx -n3 true | grep 'Jim Meyering'

Команда strings используется для извлечения читаемых строк из бинарных файлов.

Подпишись на BashDays в телеграм

d = не дублируем повторяющиеся строки
t = разделитель по умолчанию
x = выводим смещение строки
n = минимальная длина строки

Так, я получил смещение 4176

4176 Jim Meyering

Теперь патчим бинарник true:

dd if=/dev/zero of=./true seek=$((0x4176+3)) conv=notrunc count=1 bs=1

Тут я заменяю символ пробела на нулевой байт. Seek в данном контексте количество блоков, которое нужно пропустить перед началом записи. Берем смещение 4176 и добавляем к нему еще 3 (Jim), после него начинаем запись.

Команда dd скопирует один байт из /dev/zero и запишет его в файл по смещению 4176+3, не обрезая файл.

Теперь снова запускаем:

./true --version

И видим, что часть строки обрезалась нулевым байтом, на экран вывелось:

Written by Jim.

А в оригинале выводилось:

Written by Jim Meyering.

Вот такие вот магические нули и байты. Я не знаю зачем тебе это, но момент с патчингом и работой с strings можешь взять на вооружение, штука интересная, возможно где-нибудь применишь.

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

Рекомендую почитать