ELF

Zrozumienie formatu pliku ELF

Zrozumienie formatu pliku ELF

Od kodu źródłowego do kodu binarnego

Programowanie zaczyna się od sprytnego pomysłu i napisania kodu źródłowego w wybranym języku programowania, na przykład C, i zapisania kodu źródłowego w pliku. Za pomocą odpowiedniego kompilatora, na przykład GCC, Twój kod źródłowy jest najpierw tłumaczony na kod wynikowy. Ostatecznie, linker tłumaczy kod wynikowy na plik binarny, który łączy kod wynikowy z przywoływanymi bibliotekami. Ten plik zawiera pojedyncze instrukcje jako kod maszynowy, które są rozumiane przez procesor i są wykonywane zaraz po uruchomieniu skompilowanego programu.

Wspomniany powyżej plik binarny ma określoną strukturę, a jeden z najczęstszych nosi nazwę ELF, co oznacza format wykonywalny i z możliwością łączenia. Jest szeroko stosowany w przypadku plików wykonywalnych, relokowalnych plików obiektowych, bibliotek współdzielonych i zrzutów pamięci.

Dwadzieścia lat temu - w 1999 - projekt 86open wybrał ELF jako standardowy format pliku binarnego dla systemów Unix i Unix-like na procesorach x86. Na szczęście format ELF został wcześniej udokumentowany zarówno w interfejsie binarnym aplikacji System V, jak i w standardzie interfejsu narzędziowego [4]. Fakt ten ogromnie uprościł porozumienie w sprawie standaryzacji między różnymi dostawcami i programistami systemów operacyjnych opartych na systemie Unix.

Powodem tej decyzji był projekt ELF - elastyczność, rozszerzalność i wieloplatformowa obsługa różnych formatów endian i rozmiarów adresów. Projekt ELF nie ogranicza się do konkretnego procesora, zestawu instrukcji lub architektury sprzętowej. Szczegółowe porównanie formatów plików wykonywalnych znajdziesz tutaj [3].

Od tego czasu format ELF jest używany przez kilka różnych systemów operacyjnych. Obejmuje to między innymi Linux, Solaris/Illumos, Free-, Net- i OpenBSD, QNX, BeOS/Haiku i Fuchsia OS [2]. Co więcej, znajdziesz go na urządzeniach mobilnych z systemem Android, Maemo lub Meego OS/Sailfish OS, a także na konsolach do gier, takich jak PlayStation Portable, Dreamcast i Wii.

Specyfikacja nie wyjaśnia rozszerzenia nazwy pliku dla plików ELF. W użyciu są różne kombinacje liter, takie jak .axf, .kosz, .elf, .o, .prx, .ptyś, .ko, .tak i .mod lub żaden.

Struktura pliku ELF

Na terminalu Linux polecenie man elf daje przydatne podsumowanie dotyczące struktury pliku ELF:

Listing 1: Strona podręcznika struktury ELF

$ mężczyzna elf
ELF(5) Podręcznik programisty Linuksa ELF(5)
NAZWA
elf - format plików Executable i Linking Format (ELF)
STRESZCZENIE
#zawierać
OPIS
Plik nagłówkowy definiuje format wykonywalnego pliku binarnego ELF
akta. Wśród tych plików są normalne pliki wykonywalne, relokowalne
pliki obiektowe, pliki podstawowe i biblioteki współdzielone.
Plik wykonywalny w formacie ELF składa się z nagłówka ELF,
po którym następuje tablica nagłówków programu lub tablica nagłówków sekcji, lub obie te rzeczy.
Nagłówek ELF jest zawsze w przesunięciu zerowym pliku. Program
tabela nagłówków i przesunięcie tabeli nagłówków sekcji w pliku są
zdefiniowane w nagłówku ELFLF. Dwie tabele opisują resztę
specyfika pliku.

Jak widać z powyższego opisu, plik ELF składa się z dwóch sekcji - nagłówka ELF i danych pliku. Sekcja danych pliku może składać się z tablicy nagłówka programu opisującej zero lub więcej segmentów, tablicy nagłówka sekcji opisującej zero lub więcej sekcji, po której następują dane, do których odnoszą się wpisy z tablicy nagłówka programu, oraz tablica nagłówka sekcji. Każdy segment zawiera informacje niezbędne do wykonania pliku w czasie wykonywania, podczas gdy sekcje zawierają ważne dane do łączenia i relokacji. Rysunek 1 ilustruje to schematycznie.

Nagłówek ELF

Nagłówek ELF ma długość 32 bajtów i identyfikuje format pliku. Zaczyna się od sekwencji czterech unikalnych bajtów, które są 0x7F, po których następują 0x45, 0x4c i 0x46, co przekłada się na trzy litery E, L i F. Między innymi nagłówek wskazuje również, czy jest to plik ELF w formacie 32- lub 64-bitowym, używa małej lub dużej endianowości, pokazuje wersję ELF, a także dla jakiego systemu operacyjnego plik został skompilowany w celu współpracy z odpowiedni interfejs binarny aplikacji (ABI) i zestaw instrukcji procesora.

Zrzut heksowy dotyku pliku binarnego wygląda następująco:

.Listing 2: Zrzut heksowy pliku binarnego

$ hd /usr/bin/touch | głowa -5
00000000 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 |.ELF… |
00000010 02 00 3e 00 01 00 00 00 e3 25 40 00 00 00 00 00 |… >… %@… |
00000020 40 00 00 00 00 00 00 00 28 e4 00 00 00 00 00 00 |@… (… |
00000030 00 00 00 00 40 00 38 00 09 00 40 00 1b 00 1a 00 |[ochrona poczty elektronicznej]@… |
00000040 06 00 00 00 05 00 00 00 40 00 00 00 00 00 00 00 |[ochrona poczty elektronicznej]|

Debian GNU/Linux oferuje polecenie readelf, które jest dostarczane w pakiecie GNU 'binutils'. W towarzystwie przełącznika -h (krótka wersja dla „-file-header”) ładnie wyświetla nagłówek pliku ELF. Listing 3 ilustruje to dla polecenia touch.

.Listing 3: Wyświetlanie nagłówka pliku ELF

$ readelf -h /usr/bin/touch
Nagłówek ELF:
Magia: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Klasa: ELF64
Dane: uzupełnienie do 2, little endian
Wersja: 1 (aktualna)
OS/ABI: UNIX — System V
Wersja ABI: 0
Typ: EXEC (plik wykonywalny)
Maszyna: Zaawansowane mikrourządzenia X86-64
Wersja: 0x1
Adres punktu wejścia: 0x4025e3
Początek nagłówków programu: 64 (bajty do pliku)
Początek nagłówków sekcji: 58408 (bajty do pliku)
Flagi: 0x0
Rozmiar tego nagłówka: 64 (bajty)
Rozmiar nagłówków programu: 56 (bajtów)
Liczba nagłówków programu: 9
Rozmiar nagłówków sekcji: 64 (bajty)
Liczba nagłówków sekcji: 27
Indeks tabeli ciągów nagłówków sekcji: 26

Nagłówek programu

Nagłówek programu pokazuje segmenty używane w czasie wykonywania i mówi systemowi, jak utworzyć obraz procesu. Nagłówek z Listingu 2 pokazuje, że plik ELF składa się z 9 nagłówków programu, każdy o rozmiarze 56 bajtów, a pierwszy nagłówek zaczyna się od 64 bajtu.

Ponownie, polecenie readelf pomaga wyodrębnić informacje z pliku ELF. Przełącznik -l (skrót od -program-headers lub -segments) ujawnia więcej szczegółów, jak pokazano na Listingu 4.

.Listing 4: Wyświetlanie informacji o nagłówkach programu

$ readelf -l /usr/bin/touch
Typ pliku Elf to EXEC (plik wykonywalny)
Punkt wejścia 0x4025e3
Istnieje 9 nagłówków programu, zaczynając od przesunięcia 64
Nagłówki programu:
Wpisz Przesunięcie VirtAddr PhysAddr
Wyrównaj flagi FileSiz MemSiz
PHDR 0x0000000000000040 0x000000000400040 0x000000000400040
0x00000000000001f8 0x00000000000001f8 R E 8
INTERP 0x0000000000000238 0x0000000000400238 0x0000000000400238
0x000000000000001c 0x000000000000001c R 1
[Prośba o interpreter programu: /lib64/ld-linux-x86-64.więc.2]
LOAD 0x0000000000000000 0x0000000000400000 0x0000000000400000
0x000000000000d494 0x000000000000d494 R E 200000
LOAD 0x000000000000de10 0x000000000060de10 0x000000000060de10
0x00000000000000524 0x00000000000000748 RW 200000
DYNAMICZNY 0x000000000000de28 0x000000000060de28 0x000000000060de28
0x00000000000001d0 0x00000000000001d0 RW 8
UWAGA 0x0000000000000254 0x0000000000400254 0x0000000000400254
0x0000000000000044 0x0000000000000044 R 4
GNU_EH_FRAME 0x000000000000bc40 0x000000000040bc40 0x000000000040bc40
0x00000000000003a4 0x00000000000003a4 R 4
GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000000 0x0000000000000000 RW 10
GNU_RELRO 0x000000000000de10 0x000000000060de10 0x000000000060de10
0x00000000000001f0 0x00000000000001f0 R 1
Mapowanie sekcji do segmentu:
Sekcje segmentów…
00
01 .interp
02 .interp .Uwaga.Tag ABIBI .Uwaga.gnu antylopa.identyfikator kompilacji .gnu antylopa.haszysz .dynamika .dynstra .gnu antylopa.wersja .gnu antylopa.wersja_r .rela.dyna .rela.plt .w tym .plt .tekst .skończony .rodata .eh_frame_hdr .eh_ramka
03 .init_array .fini_array .JCRc .dynamiczny .dostał .dostał.plt .dane .bss
04 .dynamiczny
05 .Uwaga.Tag ABIBI .Uwaga.gnu antylopa.identyfikator kompilacji
06 .eh_frame_hdr
07
08 .init_array .fini_array .JCRc .dynamiczny .dostał

Nagłówek sekcji

Trzecią częścią struktury ELF jest nagłówek sekcji. Ma na celu wypisanie pojedynczych sekcji pliku binarnego. Przełącznik -S (skrót od -section-headers lub -sections) wyświetla różne nagłówki. Jeśli chodzi o polecenie dotykowe, jest 27 nagłówków sekcji, a Listing 5 pokazuje pierwsze cztery z nich plus ostatni, tylko. Każda linia obejmuje rozmiar sekcji, typ sekcji oraz jej adres i przesunięcie pamięci.

.Listing 5: Szczegóły sekcji ujawnione przez readelf

$ readelf -S /usr/bin/touch
Istnieje 27 nagłówków sekcji, zaczynając od offsetu 0xe428:
Nagłówki sekcji:
[Nr] Nazwa Typ Adres Przesunięcie
Rozmiar EntSize Flagi Informacje o łączu Wyrównaj
[ 0] NULL 0000000000000000 00000000
000000000000000 000000000000000 0 0 0
[1] .interp PROGBITY 000000000400238 00000238
000000000000001c 0000000000000000 A 0 0 1
[2] .Uwaga.Tag ABI UWAGA 000000000400254 00000254
0000000000000020 000000000000000 A 0 0 4
[3] .Uwaga.gnu antylopa.build-i UWAGA 000000000400274 00000274


[26] .shstrtab STRTAB 0000000000000000 0000e334
00000000000000ef 0000000000000000 0 0 1
Klucz do flag:
W (zapis), A (alokacja), X (wykonanie), M (scalanie), S (ciągi), l (duże)
I (informacje), L (kolejność linków), G (grupa), T (TLS), E (wyklucz), x (nieznane)
O (wymagane dodatkowe przetwarzanie systemu operacyjnego) o (specyficzne dla systemu operacyjnego), p (specyficzne dla procesora)

Narzędzia do analizy pliku ELF

Jak mogłeś zauważyć na powyższych przykładach, GNU/Linux jest wzbogacony o szereg przydatnych narzędzi, które pomagają analizować plik ELF. Pierwszym kandydatem, któremu przyjrzymy się, jest narzędzie do plików.

plik wyświetla podstawowe informacje o plikach ELF, w tym architekturze zestawu instrukcji, dla której przeznaczony jest kod w relokowalnym, wykonywalnym lub współdzielonym pliku obiektowym. Na liście 6 mówi, że /bin/touch jest 64-bitowym plikiem wykonywalnym zgodnym z Linux Standard Base (LSB), dynamicznie połączonym i zbudowanym dla jądra GNU/Linux w wersji 2.6.32.

.Listing 6: Podstawowe informacje o użyciu pliku

$ plik / kosz / dotyk
/bin/touch: 64-bitowy plik wykonywalny ELF LSB, x86-64, wersja 1 (SYSV), łączony dynamicznie, interpreter /lib64/l,
dla GNU/Linuksa 2.6.32, ID kompilacji[sha1]=ec08d609e9e8e73d4be6134541a472ad0ea34502, usunięte
$

Drugi kandydat to readelf. Wyświetla szczegółowe informacje o pliku ELF. Lista przełączników jest stosunkowo długa i obejmuje wszystkie aspekty formatu ELF. Użycie przełącznika -n (skrót od -notes) Listing 7 pokazuje tylko sekcje notatek, które istnieją w pliku touch - znacznik wersji ABI i ciąg bitów identyfikatora kompilacji.

.Listing 7: Wyświetl wybrane sekcje pliku ELF

$ readelf -n /usr/bin/touch
Wyświetlanie notatek znalezionych pod przesunięciem pliku 0x00000254 o długości 0x00000020:
Właściciel Wielkość danych Opis
GNU 0x00000010 NT_GNU_ABI_TAG (znacznik wersji ABI)
System operacyjny: Linux, ABI: 2.6.32
Wyświetlanie notatek znalezionych pod przesunięciem pliku 0x00000274 o długości 0x00000024:
Właściciel Wielkość danych Opis
GNU 0x00000014 NT_GNU_BUILD_ID (unikalny identyfikator kompilacji bitstring)
Identyfikator kompilacji: ec08d609e9e8e73d4be6134541a472ad0ea34502

Zauważ, że pod Solarisem i FreeBSD narzędzie elfdump [7] odpowiada readelf. Od 2019 r. nie było nowej wersji ani aktualizacji od 2003 r.

Numer trzeci to pakiet o nazwie elfutils [6], który jest dostępny wyłącznie dla Linuksa. Zapewnia alternatywne narzędzia do GNU Binutils, a także umożliwia walidację plików ELF. Zauważ, że wszystkie nazwy narzędzi dostarczonych w pakiecie zaczynają się od eu dla 'elf utils'.

Na koniec wspomnimy o objdump. To narzędzie jest podobne do readelf, ale skupia się na plikach obiektowych. Zapewnia podobny zakres informacji o plikach ELF i innych formatach obiektów.

.Listing 8: Informacje o pliku wyodrębnione przez objdump

$ objdump -f /bin/touch
/bin/touch: format pliku elf64-x86-64
architektura: i386:x86-64, flagi 0x00000112:
EXEC_P, HAS_SYMS, D_PAGED
adres początkowy 0x00000000004025e3
$

Istnieje również pakiet oprogramowania o nazwie „elfkickers” [9], który zawiera narzędzia do odczytywania zawartości pliku ELF oraz manipulowania nim. Niestety liczba wydań jest raczej niewielka, dlatego po prostu o tym wspominamy i nie podajemy dalszych przykładów.

Jako programista możesz zamiast tego spojrzeć na „pax-utils” [10,11]. Ten zestaw narzędzi zawiera szereg narzędzi, które pomagają w walidacji plików ELF. Jako przykład, dumpelf analizuje plik ELF i zwraca plik nagłówkowy C zawierający szczegóły - patrz Rysunek 2.

Wniosek

Dzięki połączeniu sprytnego projektu i doskonałej dokumentacji format ELF działa bardzo dobrze i jest nadal używany po 20 latach. Narzędzia pokazane powyżej umożliwiają wgląd w plik ELF i pozwalają dowiedzieć się, co robi program. To są pierwsze kroki do analizy oprogramowania - szczęśliwego hakowania!

Linki i referencje
  • [1] Format wykonywalny i z możliwością łączenia (ELF), Wikipedia
  • [2] Fuksja OS
  • [3] Porównanie formatów plików wykonywalnych, Wikipedia
  • [4] Linux Foundation, specyfikacje referencyjne
  • [5] Ciro Santilli: samouczek ELF Hello World
  • [6] elfutils pakiet Debiana
  • [7] elfdump
  • [8] Michael Boelen: 101 plików ELF w systemie Linux: zrozumienie i analiza
  • [9] elfkickers
  • [10] Narzędzia utwardzane/PaX U
  • [11] pax-utils, pakiet Debiana
Podziękowanie

Autor dziękuje Axelowi Beckertowi za wsparcie w przygotowaniu tego artykułu.

Jak używać Xdotool do stymulacji kliknięć myszą i naciśnięć klawiszy w systemie Linux?
Xdotool to darmowe i otwarte narzędzie wiersza poleceń do symulacji kliknięć myszą i naciśnięć klawiszy. Ten artykuł zawiera krótki przewodnik dotyczą...
5 najlepszych ergonomicznych myszy komputerowych dla systemu Linux
Czy długotrwałe korzystanie z komputera powoduje ból nadgarstka lub palców?? Cierpisz na sztywne stawy i ciągle musisz uścisnąć dłonie? Czy czujesz pa...
Jak zmienić ustawienia myszy i touchpada za pomocą Xinput w systemie Linux?
Większość dystrybucji Linuksa jest domyślnie dostarczana z biblioteką „libinput” do obsługi zdarzeń wejściowych w systemie. Może przetwarzać zdarzenia...