Razumevanje oblike datoteke ELF

Understanding Elf File Format



Od izvorne kode do binarne kode

Programiranje se začne s pametno idejo in pisanjem izvorne kode v programski jezik po vaši izbiri, na primer C, in shranjevanjem izvorne kode v datoteko. S pomočjo ustreznega prevajalnika, na primer GCC, se vaša izvorna koda najprej prevede v kodo objekta. Sčasoma povezovalnik prevede kodo objekta v binarno datoteko, ki kodo objekta poveže z referenčnimi knjižnicami. Ta datoteka vsebuje posamezna navodila kot strojno kodo, ki jih razume CPU, in se izvedejo takoj, ko se zažene prevedeni program.

Zgoraj omenjena binarna datoteka sledi določeni strukturi, ena najpogostejših pa se imenuje ELF, ki skrajša izvedljiv in povezljiv format. Široko se uporablja za izvedljive datoteke, premestljive predmetne datoteke, knjižnice v skupni rabi in odlagališča jedra.







Pred dvajsetimi leti-leta 1999-je projekt 86open izbral ELF za standardno binarno datotečno obliko za sisteme Unix in Unixu podobne na procesorjih x86. Na srečo je bil format ELF predhodno dokumentiran v binarnem vmesniku aplikacije System V in v standardu vmesnika orodja [4]. To dejstvo je močno poenostavilo dogovor o standardizaciji med različnimi prodajalci in razvijalci operacijskih sistemov, ki temeljijo na Unixu.



Razlog za to odločitev je bila zasnova ELF-prilagodljivost, razširljivost in podpora za različne platforme za različne formate in velikosti naslovov. Zasnova ELF ni omejena na poseben procesor, nabor navodil ali arhitekturo strojne opreme. Za podrobno primerjavo izvedljivih datotek, si oglejte tukaj [3].



Od takrat format ELF uporablja več različnih operacijskih sistemov. Med drugim to vključuje Linux, Solaris/Illumos, Free-, Net- in OpenBSD, QNX, BeOS/Haiku in Fuchsia OS [2]. Poleg tega ga boste našli na mobilnih napravah z operacijskim sistemom Android, Maemo ali Meego OS/Sailfish OS, pa tudi na igralnih konzolah, kot so PlayStation Portable, Dreamcast in Wii.





Specifikacija ne pojasnjuje razširitve imena datotek ELF. V uporabi so različne kombinacije črk, kot so .axf, .bin, .elf, .o, .prx, .puff, .ko, .so in .mod ali nobena.

Struktura datoteke ELF

Na terminalu Linux vam ukaz man elf poda priročen povzetek o strukturi datoteke ELF:



Oglas 1: Priročna stran strukture ELF

$ enajst

ELF (5) Priročnik za programerje za Linux ELF (5)

NAME
elf - format datotek izvedljivega in povezovalnega formata (ELF)

POVZETEK
#vključi

OPIS
Naslovna datoteka določa obliko izvedljive binarne datoteke ELF
datoteke. Med temi datotekami so običajne izvedljive datoteke, ki jih je mogoče premakniti
predmetne datoteke, osnovne datoteke in knjižnice v skupni rabi.

Izvedljiva datoteka v obliki zapisa datoteke ELF je sestavljena iz glave ELF,
sledi tabela glave programa ali tabela glave razdelka ali oboje.
Glava ELF je vedno pri odmiku nič datoteke. Program
tabela glave in odmik tabele glave razdelka v datoteki sta
opredeljeno v glavi ELF. Dve tabeli opisujeta preostanek
posebnosti datoteke.

...

Kot lahko vidite iz zgornjega opisa, je datoteka ELF sestavljena iz dveh razdelkov - glave ELF in podatkov o datoteki. Odsek podatkovnih datotek je lahko sestavljen iz tabele glave programa, ki opisuje nič ali več segmentov, tabele glave razdelka, ki opisuje nič ali več odsekov, ki ji sledijo podatki, na katere se nanašajo vnosi iz tabele glave programa, in tabele glave razdelka. Vsak segment vsebuje informacije, ki so potrebne za izvajanje datoteke med izvajanjem, medtem ko odseki vsebujejo pomembne podatke za povezovanje in premestitev. Slika 1 to shematično prikazuje.

Glava ELF

Glava ELF je dolga 32 bajtov in označuje obliko datoteke. Začne se z zaporedjem štirih edinstvenih bajtov, ki so 0x7F, ki jim sledijo 0x45, 0x4c in 0x46, kar pomeni tri črke E, L in F. Med drugimi vrednostmi glava označuje tudi, ali gre za datoteko ELF za 32 ali 64-bitni format, ki uporablja malo ali veliko endianness, prikazuje različico ELF in tudi, za kateri operacijski sistem je bila datoteka sestavljena, da bi lahko delovala z desnim aplikacijskim binarnim vmesnikom (ABI) in nizom navodil za procesor.

Šestnajstni zapis binarne datoteke na dotik izgleda tako:

.Listing 2: šestnajstiški zapis binarne datoteke

$ hd/usr/bin/touch | glava -5
00000000 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 |. SAMO ........... |
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 | [zaščiteno po e -pošti] @..... |
00000040 06 00 00 00 05 00 00 40 00 00 00 00 00 00 | [zaščiteno po e -pošti] |

Debian GNU/Linux ponuja ukaz readelf, ki je na voljo v paketu 'binutils' GNU. V spremstvu stikala -h (kratka različica za –file -header) lepo prikaže glavo datoteke ELF. V razdelku 3 je prikazano to za ukaz touch.

.Listing 3: Prikaz glave datoteke ELF

$ readelf -h/usr/bin/touch
Glava ELF:
Čarobno: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Razred: ELF64
Podatki: 2 -je dopolnilo, mali endian
Različica: 1 (trenutna)
OS / ABI: UNIX - sistem V
Različica ABI: 0
Vrsta: EXEC (izvedljiva datoteka)
Stroj: Napredne mikro naprave X86-64
Različica: 0x1
Naslov vstopne točke: 0x4025e3
Začetek glav programa: 64 (bajtov v datoteko)
Začetek glave razdelka: 58408 (bajtov v datoteko)
Zastave: 0x0
Velikost te glave: 64 (bajtov)
Velikost programskih glav: 56 (bajtov)
Število naslovov programa: 9
Velikost glav razdelkov: 64 (bajtov)
Število glav razdelkov: 27
Indeks tabele nizov glave razdelka: 26

Glava programa

Glava programa prikazuje segmente, ki se uporabljajo med izvajanjem, in sistemu pove, kako ustvari sliko procesa. Glava iz seznama 2 prikazuje, da je datoteka ELF sestavljena iz 9 programskih glav, ki imajo velikost 56 bajtov vsak, prva glava pa se začne pri 64 bajtih.

Ponovno ukaz readelf pomaga izvleči podatke iz datoteke ELF. Stikalo -l (okrajšava za –programske glave ali –segmente) razkrije več podrobnosti, kot je prikazano v razvrstitvi 4.

.Listing 4: Prikaz informacij o glavah programa

$ readelf -l/usr/bin/touch

Vrsta datoteke Elf je EXEC (izvedljiva datoteka)
Vstopna točka 0x4025e3
Obstaja 9 naslovov programov, ki se začnejo pri odmiku 64

Glave programa:
Vnesite Offset VirtAddr PhysAddr
FileSiz MemSiz zastavice Poravnajte
PHDR 0x0000000000000040 0x0000000000400040 0x0000000000400040
0x00000000000001f8 0x00000000000001f8 R E 8
INTERP 0x0000000000000238 0x0000000000400238 0x0000000000400238
0x000000000000001c 0x000000000000001c R 1
[Zahtevanje tolmača programa: /lib64/ld-linux-x86-64.so.2]
NALOŽI 0x0000000000000000 0x0000000000400000 0x0000000000400000
0x000000000000d494 0x000000000000d494 R E 200000
LOAD 0x000000000000dede 0x000000000060de10 0x000000000060de10
0x0000000000000524 0x0000000000000748 RW 200000
DYNAMIC 0x000000000000dede28 0x000000000060de28 0x000000000060de28
0x00000000000001d0 0x00000000000001d0 RW 8
OPOMBA 0x0000000000000254 0x0000000000400254 0x0000000000400254
0x00000000000000444 0x0000000000000044 R 4
GNU_EH_FRAME 0x000000000000bc40 0x000000000040bc40 0x00000000004040bc40
0x00000000000003a4 0x00000000000003a4 R 4
GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x000000000000000000 0x0000000000000000 RW 10
GNU_RELRO 0x000000000000de10 0x000000000060de10 0x000000000060de10
0x00000000000001f0 0x00000000000001f0 R 1

Preslikava odseka do segmenta:
Odseki segmentov ...
00
01 .poseg
02 .interp .note.ABI-tag .note.gnu.build-id .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt .init .plt .text .fini. rodata .eh_frame_hdr .eh_frame
03 .init_array .fini_array .jcr .dynamic .got .got.plt .data .bss
04 .dinamična
05 .note.ABI-tag .note.gnu.build-id
06 .eh_frame_hdr
07
08 .init_array .fini_array .jcr .dynamic .got

Glava razdelka

Tretji del strukture ELF je glava razdelka. Namenjen je seznamu posameznih odsekov binarne datoteke. Stikalo -S (okrajšava za –sections -headers ali –sections) navaja različne glave. Kar zadeva ukaz na dotik, je 27 glav razdelkov, v seznamu 5 pa so prikazani samo prvi štirje in zadnji. Vsaka vrstica zajema velikost odseka, vrsto odseka ter naslov in zamik pomnilnika.

.Uvrstitev 5: Readelf razkriva podrobnosti oddelka

$ readelf -S/usr/bin/touch
Obstaja 27 glav razdelkov, ki se začnejo pri odmiku 0xe428:

Glave razdelkov:
[Št.] Vrsta imena Naslov Odmik
Velikost EntSize zastavice Podatki o povezavi Poravnaj
[0] NULL 0000000000000000 00000000
0000000000000000 0000000000000000 0 0 0
[1] .zamesni PROGBITI 0000000000400238 00000238
000000000000001c 0000000000000000 A 0 0 1
[2] .opomba.ABI-oznaka OPOMBA 0000000000400254 00000254
0000000000000020 0000000000000000 A 0 0 4
[3] .note.gnu.build-i OPOMBA 0000000000400274 00000274
...
...
[26] .shstrtab STRTAB 000000000000000000 0000e334
00000000000000ef 0000000000000000 0 0 1
Ključ do zastav:
W (pisanje), A (dodelitev), X (izvajanje), M (združevanje), S (nizovi), l (veliko)
I (info), L (vrstni red povezav), G (skupina), T (TLS), E (izključi), x (neznano)
O (potrebna je dodatna obdelava OS) o (specifična za OS), p (specifična za procesor)

Orodja za analizo datoteke ELF

Kot ste morda zapisali iz zgornjih primerov, je GNU/Linux dopolnjen s številnimi uporabnimi orodji, ki vam pomagajo analizirati datoteko ELF. Prvi kandidat, ki si ga bomo ogledali, je pripomoček za datoteke.

file prikazuje osnovne podatke o datotekah ELF, vključno z arhitekturo nabora navodil, za katero je namenjena koda v datoteki predmeta, ki jo je mogoče premestiti, izvršljivo ali v skupni rabi. V seznamu 6 vam pove, da je/bin/touch 64-bitna izvedljiva datoteka, ki sledi Linux Standard Base (LSB), dinamično povezana in zgrajena za različico jedra GNU/Linux 2.6.32.

.Listing 6: Osnovni podatki z uporabo datoteke

$ file /bin /touch
/bin/touch: 64-bitna izvedljiva datoteka LSB ELF, x86-64, različica 1 (SYSV), dinamično povezana, tolmač/lib64/l,
za GNU/Linux 2.6.32, BuildID [sha1] = ec08d609e9e8e73d4be6134541a472ad0ea34502, odstranjen
$

Drugi kandidat se prebere sam. Prikazuje podrobne informacije o datoteki ELF. Seznam stikal je primerljivo dolg in zajema vse vidike formata ELF. Z uporabo stikala -n (okrajšava za –notes) V seznamu 7 so prikazani samo odseki opomb, ki obstajajo v dotiku datoteke -oznaka različice ABI in bitni niz nizov gradnje.

.Listing 7: Prikaz izbranih odsekov datoteke ELF

$ readelf -n/usr/bin/touch

Prikaz opomb pri odmiku datoteke 0x00000254 z dolžino 0x00000020:
Lastnik Velikost podatkov Opis
GNU 0x00000010 NT_GNU_ABI_TAG (oznaka različice ABI)
OS: Linux, ABI: 2.6.32

Prikaz opomb pri odmiku datoteke 0x00000274 z dolžino 0x00000024:
Lastnik Velikost podatkov Opis
GNU 0x00000014 NT_GNU_BUILD_ID (bitni niz edinstvenega ID -ja gradnje)
ID zgradbe: ec08d609e9e8e73d4be6134541a472ad0ea34502

Upoštevajte, da pod Solarisom in FreeBSD pripomoček elfdump [7] ustreza readelf. Od leta 2019 ni bilo nove izdaje ali posodobitve od leta 2003.

Tretji je paket z imenom elfutils [6], ki je izključno na voljo za Linux. Ponuja alternativna orodja za GNU Binutils in omogoča tudi preverjanje datotek ELF. Upoštevajte, da se vsa imena pripomočkov, navedenih v paketu, začnejo z eu za „elf utils“.

Ne nazadnje bomo omenili objdump. To orodje je podobno readelfu, vendar se osredotoča na predmetne datoteke. Zagotavlja podoben obseg informacij o datotekah ELF in drugih oblikah objektov.

.Listing 8: Podatki o datoteki, pridobljeni s strani objdump

$ objdump -f /bin /touch

/bin/touch: oblika datoteke elf64-x86-64
arhitektura: i386: x86-64, zastavice 0x00000112:
EXEC_P, HAS_SYMS, D_PAGED
začetni naslov 0x00000000004025e3

$

Obstaja tudi programski paket, imenovan „elfkickers“ [9], ki vsebuje orodja za branje vsebine datoteke ELF in njeno upravljanje. Žal je število izdaj precej nizko, zato ga le omenjamo in ne prikazujemo nadaljnjih primerov.

Kot razvijalec si lahko namesto tega ogledate 'pax-utils' [10,11]. Ta nabor pripomočkov ponuja številna orodja, ki pomagajo potrditi datoteke ELF. Dumpelf na primer analizira datoteko ELF in vrne datoteko glave C, ki vsebuje podrobnosti - glej sliko 2.

Zaključek

Zahvaljujoč kombinaciji pametnega oblikovanja in odlične dokumentacije, format ELF deluje zelo dobro in je še vedno v uporabi po 20 letih. Zgoraj prikazani pripomočki vam omogočajo vpogled v datoteko ELF in vam omogočajo, da ugotovite, kaj počne program. To so prvi koraki za analizo programske opreme - veselo vdiranje!

Povezave in reference
Zahvala

Pisatelj se zahvaljuje Axel Beckert za podporo pri pripravi tega članka.