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

Стилизованный терминал Linux с линиями зеленого текста на ноутбуке.
фатмавати ахмад дзенури / Shutterstock

Есть тайный файл? Linux file Команда быстро скажет вам, какой это тип файла. Если это бинарный файл, вы можете узнать о нем еще больше. file имеет целый ряд стабильных товарищей, которые помогут вам проанализировать его. Мы покажем вам, как использовать некоторые из этих инструментов.

Определение типов файлов

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

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

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

Программы для Windows, мобильные приложения, игры - ВСЁ БЕСПЛАТНО, в нашем закрытом телеграмм канале - Подписывайтесь:)

Описанные здесь инструменты уже были установлены в дистрибутивах Manjaro 20, Fedora 21 и Ubuntu 20.04, которые мы использовали для исследования этой статьи. Давайте начнем наше расследование, используя file команда,

Использование файла Command

У нас есть коллекция файлов разных типов в нашем текущем каталоге. Это смесь документа, исходного кода, исполняемых и текстовых файлов.

ls Команда покажет нам, что находится в каталоге, и -hl Опция (удобочитаемые размеры, длинный список) покажет нам размер каждого файла:

ls -hl

ls -hl в окне терминала.

Давай попробуем file на несколько из них и посмотрим, что мы получим:

file build_instructions.odt
file build_instructions.pdf
file COBOL_Report_Apr60.djvu

файл build_instructions.odt в окне терминала.

Три формата файла определены правильно. Где возможно, file дает нам немного больше информации. Сообщается, что файл PDF находится в формат версии 1.5,

Даже если мы переименуем файл ODT, чтобы иметь расширение с произвольным значением XYZ, файл все равно будет правильно идентифицирован, как в пределах Files файловый браузер и в командной строке с помощью file,

Файл OpenDocument правильно определен в браузере файлов Files, даже если его расширение XYZ.

В пределах Files в браузере файлов указан правильный значок. В командной строке file игнорирует расширение и просматривает файл, чтобы определить его тип:

file build_instructions.xyz

файл build_instructions.xyz в окне терминала.

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

file screenshot.png
file screenshot.jpg
file Pachelbel_Canon_In_D.mp3

файл screenshot.png в окне терминала.

Интересно, что даже с простыми текстовыми файлами, file не судит файл по его расширению. Например, если у вас есть файл с расширением «.c», содержащий стандартный текст, но не исходный код, file не принимайте это за настоящий C файл исходного кода:

file function+headers.h
file makefile
file hello.c

Функция файла + заголовки.h в окне терминала.

file правильно идентифицирует заголовочный файл («.h») как часть коллекции файлов исходного кода на C и знает, что make-файл является скриптом.

Использование файла с двоичными файлами

Двоичные файлы — это больше «черный ящик», чем другие. Можно просматривать файлы изображений, воспроизводить звуковые файлы и открывать файлы документов с помощью соответствующего программного пакета. Двоичные файлы, тем не менее, являются более сложной задачей.

Например, файлы «hello» и «wd» являются двоичными исполняемыми файлами. Это программы. Файл с именем «wd.o» является объектным файлом. Когда исходный код компилируется компилятором, создается один или несколько объектных файлов. Они содержат машинный код, который компьютер в конечном итоге выполнит при запуске готовой программы, а также информацию для компоновщика. Компоновщик проверяет каждый объектный файл для вызовов функций в библиотеках. Он связывает их с любыми библиотеками, которые использует программа. Результатом этого процесса является исполняемый файл.

Файл «watch.exe» представляет собой двоичный исполняемый файл, который был скомпилирован для работы в Windows:

file wd
file wd.o
file hello
file watch.exe

файл wd в окне терминала.

Взять последний первым, file говорит нам, что файл «watch.exe» представляет собой исполняемую консольную программу PE32 + для семейства процессоров x86 в Microsoft Windows. PE обозначает переносимый исполняемый формат, который имеет 32- и 64-битные версии, PE32 — это 32-разрядная версия, а PE32 + — это 64-разрядная версия.

Все остальные три файла обозначены как Исполняемый и связываемый формат (ELF) файлы. Это стандарт для исполняемых файлов и общих объектных файлов, таких как библиотеки. Мы вскоре рассмотрим формат заголовка ELF.

Что может броситься в глаза, так это то, что два исполняемых файла («wd» и «hello») определены как Linux Standard Base (LSB) совместно используемые объекты, и объектный файл «wd.o» идентифицируется как перемещаемый LSB. Исполняемое слово очевидно при его отсутствии.

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

Это позволяет Рандомизация размещения адресного пространства (ASMR) система для загрузки исполняемых файлов в память по адресам по своему выбору. Стандартные исполняемые файлы имеют адрес загрузки, закодированный в их заголовках, которые определяют, где они загружены в память.

ASMR — это техника безопасности. Загрузка исполняемых файлов в память по предсказуемым адресам делает их уязвимыми для атак. Это связано с тем, что их точки входа и расположение их функций всегда будут известны злоумышленникам. Положение Независимых Исполняемых файлов (PIE), расположенный по случайному адресу, преодолевает эту восприимчивость.

Если мы составить нашу программу с gcc компилятор и предоставить -no-pie вариант, мы сгенерируем обычный исполняемый файл.

-o (выходной файл) опция позволяет нам указать имя для нашего исполняемого файла:

gcc -o hello -no-pie hello.c

Мы будем использовать file на новый исполняемый файл и посмотреть, что изменилось:

file hello

Размер исполняемого файла такой же, как и раньше (17 КБ):

ls -hl hello

gcc -o hello -no-pie hello.c в окне терминала.

Двоичный файл теперь определяется как стандартный исполняемый файл. Мы делаем это только в демонстрационных целях. Если вы компилируете приложения таким способом, вы потеряете все преимущества ASMR.

Почему исполняемый файл такой большой?

Наш пример hello Программа занимает 17 КБ, поэтому ее вряд ли можно назвать большой, но при этом все относительно. Исходный код составляет 120 байт:

cat hello.c

Что мешает двоичному файлу, если все, что он делает, это печатает одну строку в окне терминала? Мы знаем, что есть заголовок ELF, но для 64-битного двоичного файла это всего 64 байта. Проще говоря, это должно быть что-то еще:

ls -hl hello

кот hello.c в терминальном окне.

Давайте сканировать двоичный файл с помощью strings Команда как простой первый шаг, чтобы узнать, что внутри него. Мы доставим это в less:

strings hello | less

струны привет | меньше в окне терминала.

Есть много строк внутри двоичного файла, кроме «Привет, Geek мир!» из нашего исходного кода. Большинство из них являются метками для областей в двоичном файле, а также именами и связующей информацией общих объектов. К ним относятся библиотеки и функции внутри этих библиотек, от которых зависит двоичный файл.

ldd команда показывает нам зависимости общего объекта двоичного файла:

ldd hello

Лдд привет в окне терминала.

В выводе есть три записи, и две из них содержат путь к каталогу (первая — нет):

  • linux-vdso.so: Виртуальный динамический общий объект (VDSO) это механизм ядра, который позволяет получить доступ к набору подпрограмм пространства ядра через двоичный файл пространства пользователя. Эта избегает накладных расходов на переключение контекста из режима ядра пользователя. Общие объекты VDSO придерживаются формата исполняемого и связанного формата (ELF), что позволяет динамически связывать их с двоичным файлом во время выполнения. VDSO выделяется динамически и использует преимущества ASMR. Возможность VDSO обеспечивается стандартом Библиотека GNU C если ядро ​​поддерживает схему ASMR.
  • libc.so.6: Библиотека GNU C общий объект.
  • /lib64/ld-linux-x86-64.so.2: Это динамический компоновщик, который двоичный файл хочет использовать. Динамический компоновщик опрашивает двоичный файл, чтобы выяснить, какие у него зависимости, Он запускает эти общие объекты в память. Он готовит двоичный файл к запуску и сможет найти и получить доступ к зависимостям в памяти. Затем он запускает программу.

Заголовок ELF

Мы можем изучить и расшифровать заголовок ELF с использованием readelf утилита и -h (заголовок файла) опция:

readelf -h hello

readelf -h привет в окне терминала.

Заголовок интерпретируется для нас.

Выведите из readelf -h привет в окне терминала.

Первый байт всех двоичных файлов ELF установлен в шестнадцатеричное значение 0x7F. Следующие три байта установлены в 0x45, 0x4C и 0x46. Первый байт — это флаг, который идентифицирует файл как двоичный файл ELF. Чтобы сделать этот кристалл прозрачным, следующие три байта обозначают «ELF» в ASCII:

  • Учебный класс: Указывает, является ли двоичный файл 32- или 64-разрядным исполняемым файлом (1 = 32, 2 = 64).
  • Данные: Указывает на порядок байт в использовании. Кодировка Endian определяет способ хранения многобайтовых чисел. В кодировании с прямым порядком байтов число сохраняется первым с его старшими значащими битами. При кодировании с прямым порядком байтов число сохраняется первым с его младшими значащими битами.
  • Версия: Версия ELF (в настоящее время это 1).
  • OS / ABI: Представляет тип двоичный интерфейс приложения в использовании. Это определяет интерфейс между двумя двоичными модулями, такими как программа и разделяемая библиотека.
  • Версия ABI: Версия ABI.
  • Тип: Тип двоичного файла ELF. Общие значения ET_REL для перемещаемого ресурса (такого как объектный файл), ET_EXEC для исполняемого файла, скомпилированного с -no-pie флаг и ET_DYN для исполняемого файла с поддержкой ASMR.
  • Машина: архитектура набора команд, Это указывает целевую платформу, для которой был создан двоичный файл.
  • Версия: Всегда установлен на 1, для этой версии ELF.
  • Адрес пункта въезда: Адрес памяти в двоичном файле, с которого начинается выполнение.

Другие записи — это размеры и количество областей и разделов в двоичном файле, чтобы можно было рассчитать их местоположение.

Быстрый взгляд на первые восемь байтов двоичного файла с hexdump покажет сигнатурный байт и строку «ELF» в первых четырех байтах файла. -C (каноническая) опция дает нам представление ASCII байтов вместе с их шестнадцатеричными значениями, и -n Параметр (число) позволяет нам указать, сколько байтов мы хотим видеть:

hexdump -C -n 8 hello

hexdump -C -n 8 привет в окне терминала.

objdump и гранулярный вид

Если вы хотите увидеть мельчайшие детали, вы можете использовать objdumpкоманда с -d (разбирать) вариант:

objdump -d hello | less

objdump -d привет | меньше в окне терминала.

Это разбирает исполняемый машинный код и отображает его в шестнадцатеричных байтах вместе с эквивалентом языка ассемблера. Расположение адреса первого пока в каждой строке показано слева.

Это полезно, только если вы можете читать на ассемблере или вам интересно, что происходит за кулисами. Выводов много, поэтому мы передали less,

Putput из objdump -d привет | меньше в окне терминала.

Компиляция и связывание

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

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

Программы для Windows, мобильные приложения, игры - ВСЁ БЕСПЛАТНО, в нашем закрытом телеграмм канале - Подписывайтесь:)

Похожие записи

Добавить комментарий

Ваш адрес email не будет опубликован.