Как найти время создания elf файла
Перейти к содержимому

Как найти время создания elf файла

  • автор:

Формат ELF-файла

В результате компиляции и компоновки ассемблером GAS создается файл формата ELF (Executable and Linkable Format), который содержит всю информацию, необходимую операционной системе для загрузки и запуска программы. Условно файл ELF состоит из трех частей:

  • Заголовок файла ELF
  • Заголовки программы
  • Заголовки разделов

Инструменты Arm GNU Toolchain предоставляют специальную утилиту для исследования ELF-файла — readelf . Мы ее можем найти в той же папке, где и располгааются исполняемые файлы компилятора gcc для arm64:

Утилита readelf в Arm GNU Toolchain

Например, в пакете Arm GNU Toolchain aarch64-none-elf эта утилита называется aarch64-none-elf-readelf . Передавая этой утилите различные параметры, можно получить представление различных частей файла в формате ELF. Для получения полной справки по данной утиилите ей надо передать опцию -H . Отмечу лишь некоторые основные опции, которые мы можем использовать для исследования файла в формате ELF:

  • -a или —all : вывод всей информации, аналогично применению опций -h -l -S -s -r -d -V -A -I
  • -h или —file-header : вывод заголовка файла
  • -l или —program-headers : вывод заголовков программы
  • -S или —section-headers (либо —sections ): вывод заголовков разделов
  • -g или —section-groups : вывод групп разделов
  • -t или —section-details : вывод информации о разделах
  • -e или —headers : вывод всех заголовков, эквивалентно набору опций -h -l -S
  • -s или —syms : вывод таблицы символов

Рассмотрим на примере простейшей программы, которая выводит приветственное соощение на консоль. Допустим, у нас есть файл hello.s со следующим кодом:

.global _start // устанавливаем стартовый адрес программы _start: mov X0, #1 // 1 = StdOut - поток вывода ldr X1, =hello // строка для вывода на экран mov X2, #19 // длина строки mov X8, #64 // устанавливаем функцию Linux svc 0 // вызываем функцию Linux для вывода строки mov X0, #0 // Устанавливаем 0 как код возврата mov X8, #93 // код 93 представляет завершение программы svc 0 // вызываем функцию Linux для выхода из программы .data hello: .ascii "Hello METANIT.COM!\n" // данные для вывода

Скомпилируем из этого файла объектный файл:

aarch64-none-elf-as hello.s -o hello.o

Затем из скомпилированного объектного файла hello.o создадим бинарный файл в формате ELF:

aarch64-none-elf-ld hello.o -o hello.so

Итак, мы получили бинарный исполныемый файл hello.so в формате ELF. Теперь проанализируем его.

Заголовок файла ELF

Для получения заголовка выполним команду

aarch64-none-elf-readelf -h hello.so

В результате мы должны получить вывод наподобие следующего:

c:\arm>aarch64-none-elf-readelf -h hello.so ELF Header: Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 Class: ELF64 Data: 2's complement, little endian Version: 1 (current) OS/ABI: UNIX - System V ABI Version: 0 Type: EXEC (Executable file) Machine: AArch64 Version: 0x1 Entry point address: 0x400000 Start of program headers: 64 (bytes into file) Start of section headers: 66152 (bytes into file) Flags: 0x0 Size of this header: 64 (bytes) Size of program headers: 56 (bytes) Number of program headers: 2 Size of section headers: 64 (bytes) Number of section headers: 6 Section header string table index: 5 c:\arm>

Это и есть заголовок программы. Разберем его.

Вначале идет поле Magic . Оно всегда имеет размер 16 байт и призван указать, что файл является корректным файлом ELF. Это поле всегда начинается с байта 0x7f , за которым следуют 3 байта, соответствующие символам «ELF» из таблицы ASCII .

Поле Class указывает на разрядность. Значение ELF64 говорит, что файл использует 64-разрядный формат. В 32-разрядных программах это поле имело бы значение ELF32 .

Поле Data сообщает операционной системе и загрузчику, в каком порядке должны считываться поля файла ELF — big-endian (обратный порядок) или little-endian (прямой порядок). Файлы ELF на Arm обычно используют кодировку little-endian для самого формата файла ELF.

Поле Version указывает на версию файла.

Поле Type указывает на тип файла

Поле Machine сообщает загрузчику, для какого типа процессоров предназначена программа. Наша 64-битная программа устанавливает в этом поле значение AArch64, указывая, что файл ELF будет работать только на 64-битных процессорах Arm. В случае с 32-разрядной программой это поле имело бы значение ARM , что означало бы, что она работает только на 32-разрядных процессорах Arm.

Поле Entry point address сообщает загрузчику, где находится точка входа программы. Когда программа была подготовлена в памяти операционной системой или загрузчиком и готова начать выполнение, это поле указывает, откуда начинать выполнение программы. В данном случае это адрес 0x400000 — стандартный адрес для ARM64.

Поле Flags указывает дополнительную информацию, которая может понадобиться загрузчику. Это поле зависит от архитектуры. В 64-битной программе, например, не определены флаги, зависящие от архитектуры, и это поле всегда будет содержать нулевое значение 0x0 . Для 32-битной программы это поле может принимать ряд значений, которые информируют, что программа ожидает аппаратную поддержку операций с плавающей запятой:

  • EF_ARM_ABIMASK (0xff000000) : старшие 8 бит значения содержат версию ABI, которая применяется файлом ELF. В настоящее время этот старший байт должен содержать значение 5 (т. е. 0x05000000), что означает, что файл ELF использует версию EABI 5.
  • EF_ARM_BE8 (0x00800000) : файл ELF содержит код BE-8 для выполнения на процессоре Arm v6. Этот флаг должен быть установлен только для исполняемого файла.
  • EF_ARM_ABI_FLOAT_HARD (0x00000400) : указывает, что файл соответствует стандарту вызова аппаратных процедур с плавающей точкой и что процессор будет Armv7 или выше и будет поддерживать аппаратное расширение VFP3-D16 с плавающей точкой.
  • EF_ARM_ABI_FLOAT_SOFT (0x00000200) : указывает, что файл соответствует стандарту программного вызова процедур с плавающей точкой. Операции с плавающей точкой обрабатываются через вызовы библиотечных функций.

Поле Size of this header описывает размер заголовка файла.

Остальные поля описывают расположение и количество заголовков программы и разделов в файле:

  • Start of program headers : начало заголовков программы
  • Start of section headers : начало заголовков разделов
  • Size of program headers : размер заголовков программы
  • Number of program headers : количество заголовков программы
  • Size of section headers : размер заголовков разделов
  • Number of section headers : количество заголовков разделов

Загрузчик использует эти поля для подготовки ELF-файла в памяти к выполнению.

Вопросы с меткой [elf]

Используйте данную метку в вопросах, связанных с форматом файлов ELF.

45 вопросов
Конкурсные
Неотвеченные

  • Конкурсные 0
  • Неотвеченные
  • Цитируемые
  • Рейтинг
  • Неотвеченные (мои метки)

86 показов

Место хранения статических локальных переменных зависит от уровня оптимизации?

Иногда в Compiler Explorer одни и те же статические локальные переменные функций показываются до функций, их использующих (-O0), а иногда — после, в конце ассемблера (-O2). Означает ли это, что они .

задан 15 окт в 9:17
28 показов

Как создать elf с большим количеством сегментов?

По работе понадобилось пропатчить elf файл так, чтоб в нем было большое количество сегментов. Любой файл,хоть hello world. Какими способами это можно сделать?

задан 20 дек 2022 в 12:11
365 показов

Как «запустить» приложение в ELF формате в Ubuntu?

Разработчик выложил старую версию своего приложения, скачав этот файл без расширения, я решил узнать, в каком он формате. Просмотрев его я обнаружил, что он в ELF формате. Как запустить, либо .

задан 15 янв 2022 в 21:03
49 показов

Как превратить ELF файл в питоновский код?

У меня есть исполняемый файл формата elf32-i386. Как мне восстановить исходный код?
задан 5 янв 2022 в 23:35

Как компилируется динамическая библиотека .so?

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

задан 20 мая 2021 в 21:18

Кодирование названия секции .text

Почему в elf-файлах названия секций кодируются по-разному? Я видел (так считает парсер), что секция .text может кодироваться как 146 (0x92) и 155 (0x9B). И есть ли где-нибудь описание того, как должны .

задан 16 мая 2021 в 19:55

несколько файлов в один исполняемый linux

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

задан 24 окт 2020 в 20:00
147 показов

Почему появилась ошибка сегментирования NASM

Не могу понять, что не так с кодом Ошибка на строке «cmp [rax+rbx],byte 0» (проверял в gdb), но ведь для 64 архитектуры такая команда дозволена(?) Заранее спасибо segment .text global _start .

задан 19 сен 2020 в 14:02
95 показов

Как скомпилить NASM

Недавно задавал вопрос про ошибку сегментирования. Нашлись проблемы в коде, но их решения не дало результата. Полез в инет и понял, что любой онлайн IDE для 64 битного NASM-а компилит код без проблем (.

задан 15 сен 2020 в 14:56
45 показов

Ошибка сегментирования NASM

Делал подпрограмму для NASM, которая должна была считать длину строки ну и собственно выводить её. Код взял из видео, но у меня ошибка. Код такой: _strlen: push rdx xor rdx,rdx _strlen_loop_start: .

задан 14 сен 2020 в 17:58
48 показов

Почему неверный результат умножения NASM

Начал недавно учить NASM, сижу под Arch x86_64 , NASM version 2.15.04. Нашел недавно следующий код: section .text global _start _start: mov al,’3′ sub al, ‘0’ mov .

задан 14 сен 2020 в 15:22
148 показов

Как собрать elf и запустить пример из репозитория?

Я нашёл в репозитории гитхаба пример elf-loader’а, который я хочу запустить,чтобы создать blob. Но я не могу понять, как собрать пример. В ELF creation, где указаны папки moduleexample and .

задан 14 апр 2020 в 16:33
124 показа

Генераця ELF файлов

K примеру у меня есть байтовый массив готовых опкодов. Как мне сгенерировать ELF файл вместе с этими опкодами? Есть ли какая-то готовая библиотека для этого на С?

задан 1 фев 2020 в 15:41
65 показов

Компоновка с бинарным файлом ELF

Есть ли возможность скомпоновать программу с бинарным файлом и как это сделать? В моем случае есть исполняемый бинарный ELF файл /bin/btrfs (интерфейс для администрирования файловой системы). Из него &.

задан 31 янв 2020 в 18:17
97 показов

имена переменных в elf файле

Я разобрался с elf заголовком, но не полностью. В elf заголовке есть указатели на секции и т.д. Но я не пойму где хранятся указатели на переменные. Я пишу дизассемблер и мне бы хотелось ещё иметь .

user302477
задан 26 ноя 2019 в 11:52
15 30 50 на странице

    Важное на Мете

Связанные метки

Подписаться на ленту

Лента новых вопросов с меткой [elf]

Для подписки на ленту скопируйте и вставьте эту ссылку в вашу программу для чтения RSS.

Дизайн сайта / логотип © 2023 Stack Exchange Inc; пользовательские материалы лицензированы в соответствии с CC BY-SA . rev 2023.10.27.43697

Нажимая «Принять все файлы cookie» вы соглашаетесь, что Stack Exchange может хранить файлы cookie на вашем устройстве и раскрывать информацию в соответствии с нашей Политикой в отношении файлов cookie.

Анатомия эльфов. Разбираемся с внутренним устройством ELF-файлов

Ес­ли в мире Windows исполня­емые фай­лы пред­став­лены в фор­мате Portable Executable (PE), то в Linux эта роль отве­дена фай­лам в фор­мате Executable and Linkable Format (ELF). Сегод­ня мы заг­лянем внутрь таких фай­лов, нем­ного поис­сле­дуем их струк­туру и узна­ем, как они устро­ены.

Сра­зу отме­чу, что в отли­чие от Windows в Linux от рас­ширения фай­ла не зависит прак­тичес­ки ничего (за сов­сем неболь­шим исклю­чени­ем). Тип и фор­мат фай­ла опре­деля­ется его внут­ренним содер­жимым и наличи­ем тех или иных атри­бутов, поэто­му фай­лы в фор­мате Executable and Linkable Format могут иметь любое рас­ширение.

Что нам понадобится

Во­обще, мож­но позави­довать людям, оби­тающим в мире Linux, — как пра­вило, в сис­теме «из короб­ки» идет боль­шое чис­ло ути­лит и прог­рамм, которые в Windows необ­ходимо где‑то искать и уста­нав­ливать допол­нитель­но, да еще и не всег­да бес­плат­но. В нашем слу­чае для ана­лиза ELF-фай­лов в Linux при­сутс­тву­ет впол­не сос­тоятель­ный арсе­нал встро­енных средств и ути­лит:

  • readelf — с помощью этой ути­литы мож­но прак­тичес­ки пол­ностью прос­матри­вать все пота­енные мес­та ELF-фай­лов в удо­бочи­таемом виде;
  • hexdump — прос­той прос­мот­рщик фай­лов в шес­тнад­цатерич­ном пред­став­лении (конеч­но, до hiew из мира Windows ему далеко, но, во‑пер­вых, он при­сутс­тву­ет в сис­теме по умол­чанию, а во‑вто­рых, дела­ет это совер­шенно бес­плат­но);
  • strings — с помощью этой извес­тной ути­литы мож­но уви­деть име­на всех импорти­руемых (или экспор­тиру­емых) фун­кций, а так­же биб­лиотек, из которых эти фун­кции импорти­рова­ны, наз­вания сек­ций и еще мно­го чего инте­рес­ного;
  • ldd — поз­воля­ет выводить име­на раз­деля­емых биб­лиотек, из которых импорти­руют­ся те или иные фун­кции, исполь­зуемые иссле­дуемой прог­раммой;
  • nm — может показы­вать таб­лицу имен из сос­тава отла­доч­ной информа­ции, которая добав­ляет­ся в ELF-фай­лы при их ком­пиляции (эта отла­доч­ная информа­ция с помощью коман­ды strip может быть уда­лена из фай­ла, и в этом слу­чае ути­лита nm ничем не поможет);
  • objdump — спо­соб­на вывес­ти информа­цию и содер­жимое всех эле­мен­тов иссле­дуемо­го фай­ла, в том чис­ле и в дизас­сем­бли­рован­ном виде.

Часть перечис­ленно­го (кро­ме hexdump и ldd) вхо­дит в сос­тав пакета GNU Binutils. Если это­го пакета в тво­ей сис­теме нет, его лег­ко уста­новить. К при­меру, в Ubuntu это выг­лядит сле­дующим обра­зом:

sudo apt install binutils

В прин­ципе, имея все перечис­ленное, мож­но уже прис­тупать к ана­лизу и иссле­дова­нию ELF-фай­лов без прив­лечения допол­нитель­ных средств. Для боль­шего удобс­тва и наг­ляднос­ти мож­но добавить к нашему инс­тру­мен­тарию извес­тный в кру­гах реверс‑инже­неров дизас­сем­блер IDA в вер­сии Freeware (этой вер­сии для наших целей будет более чем дос­таточ­но, хотя ник­то не зап­реща­ет вос­поль­зовать­ся вер­сиями Home или Pro, если есть воз­можность за них зап­латить).

Анализ заголовка ELF-файла в IDA Freeware

Так­же неп­лохо было бы исполь­зовать вмес­то hexdump что‑то поудоб­нее, нап­ример 010 Editor или wxHex Editor. Пер­вый hex-редак­тор — дос­той­ная аль­тер­натива Hiew для Linux (в том чис­ле и бла­года­ря воз­можнос­ти исполь­зовать в нем боль­шое количес­тво шаб­лонов для раз­личных типов фай­лов, сре­ди них и шаб­лон для пар­синга ELF-фай­лов). Одна­ко он небес­плат­ный (сто­имость лицен­зии начина­ется с 49,95 дол­лара, при этом есть 30-днев­ный три­аль­ный пери­од).

Анализ заголовка ELF-файла в 010 Editor

Го­воря о допол­нитель­ных инс­тру­мен­тах, которые облегча­ют ана­лиз ELF-фай­лов, нель­зя не упо­мянуть Python-пакет lief. Исполь­зуя этот пакет, мож­но писать Python-скрип­ты для ана­лиза и модифи­кации не толь­ко ELF-фай­лов, но и фай­лов PE и MachO. Ска­чать и уста­новить этот пакет получит­ся тра­дици­онным для Python-пакетов спо­собом:

pip install lief

Подопытные экземпляры

В Linux (да и во мно­гих дру­гих сов­ремен­ных UNIX-подоб­ных опе­раци­онных сис­темах) фор­мат ELF исполь­зует­ся в нес­коль­ких типах фай­лов.

  • Ис­полня­емый файл — содер­жит все необ­ходимое для соз­дания сис­темой обра­за про­цес­са и запус­ка это­го про­цес­са. В общем слу­чае это инс­трук­ции и дан­ные. Так­же в фай­ле может при­сутс­тво­вать опи­сание необ­ходимых раз­деля­емых объ­ектных фай­лов, а так­же сим­воль­ная и отла­доч­ная информа­ция. Исполня­емый файл может быть позици­онно зависи­мым (в этом слу­чае он гру­зит­ся всег­да по одно­му и тому же адре­су, для 32-раз­рядных прог­рамм обыч­но это 0x8048000 , для 64-раз­рядных — 0x400000 ) и позици­онно незави­симым исполня­емым фай­лом (PIE — Position Independent Execution или PIC — Position Independent Code). В этом слу­чае адрес заг­рузки фай­ла может менять­ся при каж­дой заг­рузке. При пос­тро­ении позици­онно незави­симо­го исполня­емо­го фай­ла исполь­зуют­ся такие же прин­ципы, как и при пос­тро­ении раз­деля­емых объ­ектных фай­лов.
  • Пе­реме­щаемый файл — содер­жит инс­трук­ции и дан­ные, при этом они могут быть ста­тичес­ки свя­заны с дру­гими объ­ектны­ми фай­лами, в резуль­тате чего получа­ется раз­деля­емый объ­ектный или исполня­емый файл. К это­му типу отно­сят­ся объ­ектные фай­лы ста­тичес­ких биб­лиотек (как пра­вило, для ста­тичес­ких биб­лиотек имя начина­ется с lib и при­меня­ется рас­ширение *. a ), одна­ко, как мы уже говори­ли, рас­ширение в Linux прак­тичес­ки ничего не опре­деля­ет. В слу­чае ста­тичес­ких биб­лиотек это прос­то дань тра­диции, а работос­пособ­ность биб­лиоте­ки будет обес­печена с любым име­нем и любым рас­ширени­ем.
  • Раз­деля­емый объ­ектный файл — содер­жит инс­трук­ции и дан­ные, может быть свя­зан с дру­гими переме­щаемы­ми фай­лами или раз­деля­емы­ми объ­ектны­ми фай­лами, в резуль­тате чего будет соз­дан новый объ­ектный файл. Такие фай­лы могут выпол­нять фун­кции раз­деля­емых биб­лиотек (по ана­логии с DLL-биб­лиоте­ками Windows). При этом в момент запус­ка прог­раммы на выпол­нение опе­раци­онная сис­тема динами­чес­ки свя­зыва­ет эту раз­деля­емую биб­лиоте­ку с исполня­емым фай­лом прог­раммы, и соз­дает­ся исполня­емый образ при­ложе­ния. Опять же тра­дици­онно раз­деля­емые биб­лиоте­ки име­ют рас­ширение *. so (от англий­ско­го Shared Object).
  • Файл дам­па памяти — файл, который содер­жит образ памяти того или ино­го про­цес­са на момент его завер­шения. В опре­делен­ных ситу­ациях ядро может соз­давать файл с обра­зом памяти ава­рий­но завер­шивше­гося про­цес­са. Этот файл так­же соз­дает­ся в фор­мате ELF, одна­ко мы о такого рода фай­лах говорить не будем, пос­коль­ку задача иссле­дова­ния дам­пов и содер­жимого памяти дос­таточ­но объ­емна и тре­бует отдель­ной статьи.

Для наших изыс­каний нам желатель­но иметь все воз­можные вари­анты исполня­емых фай­лов из перечис­ленных выше, чем мы сей­час и зай­мем­ся.

Делаем исполняемые файлы

Не будем выдумы­вать что‑то свер­хориги­наль­ное, а оста­новим­ся на клас­сичес­ком хел­ловор­лде на С:

int main ( int argc , char * argv [] ) < printf ( "Hello world" ) ;

Ком­пилиро­вать это дело мы будем с помощью GCC. Сов­ремен­ные вер­сии Linux, как пра­вило, 64-раз­рядные, и вхо­дящие в их сос­тав по умол­чанию средс­тва раз­работ­ки (в том чис­ле и ком­пилятор GCC) генери­руют 64-раз­рядные при­ложе­ния. Мы в сво­их иссле­дова­ниях не будем отдель­но вни­кать в 32-раз­рядные ELF-фай­лы (по боль­шому сче­ту отли­чий от 64-раз­рядных ELF-фай­лов в них не очень мно­го) и основные уси­лия сос­редото­чим имен­но на 64-раз­рядных вер­сиях прог­рамм. Если у тебя воз­никнет желание поэк­спе­римен­тировать с 32-раз­рядны­ми фай­лами, то при ком­пиляции в GCC нуж­но добавить опцию -m32 , при этом, воз­можно, пот­ребу­ется уста­новить биб­лиоте­ку gcc-multilib. Сде­лать это мож­но при­мер­но вот так:

sudo apt- get install gcc- multilib

Итак, назовем наш хел­ловорлд example. c (кста­ти, здесь как раз один из нем­ногих слу­чаев, ког­да в Linux рас­ширение име­ет зна­чение) и нач­нем с исполня­емо­го позици­онно зависи­мого кода:

gcc -no-pie example. c -o example_ no_ pie

Как ты уже догадал­ся, опция -no-pie как раз и говорит ком­пилято­ру соб­рать не позици­онно незави­симый код.

Во­обще, если говорить пра­виль­но, то GCC — это не сов­сем ком­пилятор. Это ком­плексная ути­лита, которая в зависи­мос­ти от рас­ширения вход­ного фай­ла и опций вызыва­ет нуж­ный ком­пилятор или ком­понов­щик с соот­ветс­тву­ющи­ми вход­ными дан­ными. При­чем из С или дру­гого высоко­уров­невого язы­ка сна­чала исходник тран­сли­рует­ся в ассем­блер­ный код, а уже затем все это окон­чатель­но пре­обра­зует­ся в объ­ектный код и собира­ется в нуж­ный нам ELF-файл.

В целом мож­но выделить четыре эта­па работы GCC:

  • преп­роцес­сирова­ние;
  • тран­сля­ция в ассем­блер­ный код;
  • пре­обра­зова­ние ассем­блер­ного кода в объ­ектный;
  • ком­понов­ка объ­ектно­го кода.

Что­бы пос­мотреть на про­межу­точ­ный резуль­тат, к при­меру в виде ассем­блер­ного кода, исполь­зуй в GCC опцию -S :

gcc -S -masm = intel example. c

Об­рати вни­мание на два момен­та. Пер­вый — мы в дан­ном слу­чае не зада­ем имя выход­ного фай­ла с помощью опции -o (GCC сам опре­делит его из исходно­го, добавив рас­ширение *. s , что и озна­чает при­сутс­твие в фай­ле ассем­блер­ного кода). Вто­рой момент — опция -masm=intel , которая говорит о том, что ассем­блер­ный код в выход­ном фай­ле необ­ходимо генери­ровать с исполь­зовани­ем син­такси­са Intel (по умол­чанию будет син­таксис AT&T, мне же, как и, навер­ное, боль­шинс­тву, син­таксис Intel бли­же). Так­же в этом слу­чае опция -no-pie не име­ет смыс­ла, пос­коль­ку ассем­блер­ный код в любом слу­чае будет оди­нако­вый, а перено­симость обес­печива­ется на эта­пе получе­ния объ­ектно­го фай­ла и сбор­ки прог­раммы.

На выходе получим файл example. s с таким вот содер­жимым (пол­ностью весь файл показы­вать не будем, что­бы не занимать мно­го мес­та):

Строение ELF-файлов⚓︎

ELF — сокращение от «Executable and Lincable Format» — формат исполняемых и связываемых файлов. ELF определяет их структуру. Данная спецификация позволяет UNIX-подобным(/образным) системам правильно интерпретировать содержащиеся в файле машинные команды. Используется во многих операционных системах: GNU/Linux, FreeBSD, Solaris, etc.

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

Начальное строение⚓︎

ELF файл

Для начала создадим директорию, в которой будут расположены тестовые программы, на которых будем «упражняться»:

 mkdir ~/LinuxPrograms cd ~/LinuxPrograms 

Типы⚓︎

Есть несколько типов ELF файлов (см. таблицы в конце статьи): * Перемещаемый файл — хранит инструкции (и данные), которые могут быть связаны с другими объектными файлами. Результатом может быть объектный или исполняемый файл. Так же к этому типу относятся объектные файлы статических библиотек. * Разделяемый объектный файл — также как и первый тип, содержит инструкции и данные, может быть связан с другими перемещаемыми и разделяемыми объектными файлами, в результате чего будет создан новый объектный файл, либо же при запуске программы ОС может динамически связывать его с исполняемым файлом программы , в результате чего будет создан исполняемый образ программы (в посл. случае речь идёт о разделяемых библиотеках). * Исполняемый файл — содержит полное описание, позволяющее ОС создать образ процесса. В т.ч.: инструкции, данные, описания необходимых разделяемых объектных файлов и др.

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

 vim simple.c int main()  return(0); > 

И скомпилируйте её:

 gcc -o simple simple.c 

Убедитесь в том, что это ELF файл:

 file simple 

Структура у каждого файла может различаться. Грубо говоря, ELF файл состоит из: * Заголовка * Данных

Подробнее: * Таблица заголовков программы: 0 или более сегментов памяти (только в исполняемом файле). Сообщает, как исполняемый файл должен быть помещён в виртуальную память процесса. Это необходимо для образа процесса, исполняемых файлов и общих объектов. Для перемещаемых объектных файлов это не требуется. * Таблица заголовков разделов: 0 или более разделов. Сообщает, как и куда нужно загрузить раздел. Каждая запись раздела в таблице содержит название и размер раздела. Таблица заголовков раздела должна использоваться для файлов, используемых при редактировании ссылок. * Данные: тпблицы заголовка программы или раздела * Заголовок ELF (54/64 байта для 32/64 бит): определяет использование 32/64 бит (смотреть struct Elf32_Ehdr / struct Elf64_Ehdr в /usr/include/elf.h ) * Заголовок программы: как создать образ процесса. Используются во время выполнения. Сообщают ядру или компоновщику время выполнения ld.so , что загружать в память и как найти информацию о динамической компоновке. * Заголовок разделов: используются во время компоновки или компиляции. Сообщают редактору ссылок ld , как разрашать символы и как группировать похожие потоки байтов из разных двоичных объектов ELF.

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

Разделы и сегменты не имеют определённого порядка в ELF. Только заголовок имеет фиксированную позицию.

При помощи утилиты readelf можно просмотреть основную информацию о файле.

Эта утилита входит в состав пакета binutils , поэтому ничего доустанавливать не надо.

Основные возможности readelf :

    Просмотр заголовка файла:

 readelf -h simple 
 readelf -S -W simple 
 readelf -s -W simple 

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

Ваш адрес email не будет опубликован. Обязательные поля помечены *