ELF -failivormingu mõistmine

Understanding Elf File Format



Alates lähtekoodist kuni binaarkoodini

Programmeerimine algab nutika ideega ja lähtekoodi kirjutamisega teie valitud programmeerimiskeeles, näiteks C, ja lähtekoodi salvestamisega faili. Sobiva kompilaatori, näiteks GCC abil teisendatakse teie lähtekood esmalt objektkoodiks. Lõpuks teisendab linkija objekti koodi kahendfailiks, mis seob objekti koodi viidatud teekidega. See fail sisaldab masina koodina üksikuid juhiseid, mida protsessor mõistab ja täidetakse kohe, kui kompileeritud programm käivitatakse.

Eespool mainitud binaarfail järgib kindlat struktuuri ja üks levinumaid on ELF, mis lühendab käivitatavat ja linkitavat vormingut. Seda kasutatakse laialdaselt käivitatavate failide, teisaldatavate objektifailide, jagatud teekide ja tuumakoopiate jaoks.







Kakskümmend aastat tagasi-1999. aastal-valis projekt 86open ELF-i standardseks binaarfailivorminguks Unixi ja Unixi-sarnaste süsteemide jaoks x86 protsessoritel. Õnneks oli ELF -vorming varem dokumenteeritud nii süsteemi V rakenduse binaarses liideses kui ka tööriistaliidese standardis [4]. See asjaolu lihtsustas tohutult standardimist käsitlevat kokkulepet Unix-põhiste operatsioonisüsteemide erinevate müüjate ja arendajate vahel.



Selle otsuse põhjuseks oli ELF-i disain-paindlikkus, laiendatavus ja platvormideülene tugi erinevatele endiaalsetele vormingutele ja aadressisuurustele. ELFi disain ei piirdu konkreetse protsessori, käskude komplekti või riistvara arhitektuuriga. Täidetavate failivormingute üksikasjalikku võrdlust leiate siit [3].



Sellest ajast alates on ELF -vormingut kasutanud mitmed erinevad operatsioonisüsteemid. Siia kuuluvad muu hulgas Linux, Solaris/Illumos, Free-, Net- ja OpenBSD, QNX, BeOS/Haiku ja Fuchsia OS [2]. Lisaks leiate selle mobiilseadmetest, milles töötab Android, Maemo või Meego OS/Sailfish OS, samuti mängukonsoolidest nagu PlayStation Portable, Dreamcast ja Wii.





Spetsifikatsioon ei selgita ELF -failide failinimelaiendit. Kasutusel on mitmesuguseid tähekombinatsioone, näiteks .axf, .bin, .elf, .o, .prx, .puff, .ko, .so ja .mod või üldse mitte.

ELF -faili struktuur

Linuxi terminalis annab käsk man elf teile käepärase kokkuvõtte ELF -faili struktuuri kohta:



Loend 1: ELFi struktuuri leht

$ mees üksteist

ELF (5) Linuxi programmeerija käsiraamat ELF (5)

NIMI
elf - käivitatava ja linkimisvormingu (ELF) failide vorming

SÜNOPSIS
#kaasake

KIRJELDUS
Päisefail määratleb ELF -i käivitatava binaarfaili vormingu
failid. Nende failide hulgas on tavalisi käivitatavaid faile, mida saab teisaldada
objektifaile, põhifaile ja jagatud teeke.

ELF -failivormingut kasutav käivitatav fail koosneb ELF -i päisest,
millele järgneb programmi päise tabel või sektsiooni päise tabel või mõlemad.
ELFi päis on alati faili nullist nihkega. Programm
päise tabel ja jaotise päise tabeli nihe failis on
määratletud ELFi päises. Kaks tabelit kirjeldavad ülejäänud osa
toimiku eripära.

...

Nagu ülaltoodud kirjeldusest näete, koosneb ELF -fail kahest osast - ELF -i päisest ja faili andmetest. Faili andmete jaotis võib koosneda programmi päise tabelist, mis kirjeldab nulli või enamat segmenti, sektsiooni päise tabelist, mis kirjeldab nulli või enamat jaotist, millele järgnevad andmed, millele viitavad programmi päise tabeli kirjed, ja sektsiooni päise tabelist. Iga segment sisaldab teavet, mis on vajalik faili käitusaja täitmiseks, samas kui sektsioonid sisaldavad olulisi andmeid linkimiseks ja ümberpaigutamiseks. Joonis 1 illustreerib seda skemaatiliselt.

ELFi päis

ELFi päis on 32 baiti pikk ja määrab kindlaks faili vormingu. See algab nelja unikaalse baidi jadaga, mis on 0x7F, millele järgnevad 0x45, 0x4c ja 0x46, mis tähendab kolme tähte E, L ja F. Muude väärtuste hulgas näitab päis ka seda, kas tegemist on ELF -failiga 32 või 64-bitine vorming, kasutab vähe või palju endiaansust, näitab ELF-i versiooni ja seda, millise operatsioonisüsteemi jaoks fail koostati, et koostalitlus oleks õige rakenduse binaarse liidese (ABI) ja protsessorikäskudega.

Binaarfaili puudutuse kuuskant näeb välja järgmine:

.Nimekiri 2: binaarfaili kuuskant

$ hd/usr/bin/touch | pea -5
00000000 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 | .ESIN ........... |
00000010 02 00 3e 00 01 00 00 00 e3 25 40 00 00 00 00 | ..> ......% @ ..... |
00000020 40 00 00 00 00 00 00 00 28 e4 00 00 00 00 00 | @ ....... (....... |
00000030 00 00 00 00 40 00 38 00 09 00 40 00 1b 00 1a 00 | [e -post kaitstud] @..... |
00000040 06 00 00 00 05 00 00 00 40 00 00 00 00 00 00 | | [e -post kaitstud] |

Debian GNU/Linux pakub käsku readelf, mis on pakendis GNU binutils. Koos lülitiga -h (lühiversioon –file -header) kuvab see kenasti ELF -faili päise. Loend 3 illustreerib seda käsu puudutamisel.

.Listing 3: ELF -faili päise kuvamine

$ readelf -h/usr/bin/touch
ELFi päis:
Maagia: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Klass: ELF64
Andmed: 2 täiend, väike endiaan
Versioon: 1 (praegune)
OS / ABI: UNIX - süsteem V
ABI versioon: 0
Tüüp: EXEC (käivitatav fail)
Masin: täiustatud mikroseadmed X86-64
Versioon: 0x1
Sisenemiskoha aadress: 0x4025e3
Programmi päiste algus: 64 (baiti faili)
Jaotise päiste algus: 58408 (baiti faili)
Lipud: 0x0
Selle päise suurus: 64 (baiti)
Programmi päiste suurus: 56 (baiti)
Programmi päiste arv: 9
Sektsiooni päiste suurus: 64 (baiti)
Sektsioonide päiste arv: 27
Sektsiooni päise stringitabeli indeks: 26

Programmi päis

Programmi päises kuvatakse käitamise ajal kasutatavad segmendid ja süsteemile kirjeldatakse, kuidas protsessipilti luua. Loendi 2 päis näitab, et ELF -fail koosneb 9 programmi päisest, mille suurus on 56 baiti, ja esimene päis algab baidist 64.

Jällegi aitab käsk readelf ELF -failist teavet välja võtta. Lüliti -l (lühend -programm -päised või –segmendid) näitab rohkem üksikasju, nagu on näidatud loendis 4.

.Nimekiri 4: kuvab teavet programmi päiste kohta

$ readelf -l/usr/bin/touch

Elfi failitüüp on EXEC (käivitatav fail)
Sisenemispunkt 0x4025e3
Programmide päiseid on 9, alates nihkega 64

Programmi päised:
Tüüp Offset VirtAddr PhysAddr
FileSiz MemSizi lipud joonduvad
PHDR 0x0000000000000040 0x0000000000400040 0x0000000000400040
0x00000000000001f8 0x00000000000001f8 R E 8
INTERP 0x0000000000000238 0x0000000000400238 0x0000000000400238
0x000000000000001c 0x000000000000001c R 1
[Taotlev programmi tõlk: /lib64/ld-linux-x86-64.so.2]
LAADI 0x0000000000000000 0x0000000000400000 0x0000000000400000
0x000000000000d494 0x000000000000d494 R E 200000
LAADI 0x000000000000de10 0x000000000060de10 0x000000000060de10
0x0000000000000524 0x0000000000000748 RW 200000
Dünaamiline 0x000000000000de28 0x000000000060de28 0x0000000000606028
0x00000000000001d0 0x00000000000001d0 RW 8
MÄRKUS 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

Jaotis segmentide kaardistamiseks:
Segmentide jaotised ...
00
01 .vahepala
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 .dünaamiline
05 .märkus.ABI-silt .note.gnu.build-id
06 .eh_frame_hdr
07
08 .init_array .fini_array .jcr .dynamic .got

Jaotise päis

ELFi struktuuri kolmas osa on sektsiooni päis. See on mõeldud binaarfaili üksikute osade loetlemiseks. Lüliti -S (lühend -jao -päised või –osad) loetleb erinevad päised. Puutekäsu osas on 27 sektsiooni päist ja loendis 5 on näidatud ainult neli esimest neist ja viimane. Iga rida hõlmab sektsiooni suurust, jaotise tüüpi, aadressi ja mälu nihet.

.Nimekiri 5: jao üksikasjad, mis on ilmutatud ise

$ readelf -S/usr/bin/touch
Seal on 27 sektsiooni päist, alates nihkega 0xe428:

Jaotiste päised:
[Nr] Nimi Tüüp Aadress Nihe
Suurus EntSize Lipud Link Info Align
[0] NULL 0000000000000000 00000000
0000000000000000 0000000000000000 0 0 0
[1] .interp PROBITID 0000000000400238 00000238
000000000000001c 0000000000000000 A 0 0 1
[2] .märkus. ABI-märkus MÄRKUS 0000000000400254 00000254
0000000000000020 0000000000000000 A 0 0 4
[3] .note.gnu.build-i MÄRKUS 0000000000400274 00000274
...
...
[26] .shstrtab STRTAB 0000000000000000 0000e334
00000000000000ef 0000000000000000 0 0 1
Lippude võti:
W (kirjutamine), A (eraldamine), X (täitmine), M (ühendamine), S (stringid), l (suur)
I (info), L (linkide järjekord), G (rühm), T (TLS), E (välista), x (teadmata)
O (vajalik operatsioonisüsteemi täiendav töötlemine) o (operatsioonisüsteemi spetsiifiline), p (protsessorispetsiifiline)

Tööriistad ELF -faili analüüsimiseks

Nagu ülaltoodud näidetest olete märganud, on GNU/Linuxis kasutatud mitmeid kasulikke tööriistu, mis aitavad teil ELF -faili analüüsida. Esimene kandidaat, keda me vaatame, on faili utiliit.

fail kuvab põhiteavet ELF -failide kohta, sealhulgas käsukomplekti arhitektuuri, mille jaoks on ette nähtud teisaldatava, käivitatava või jagatud objektifaili kood. Loendis 6 ütleb see teile, et/bin/touch on 64-bitine käivitatav fail, mis järgib Linuxi standardbaasi (LSB), on dünaamiliselt lingitud ja loodud GNU/Linuxi kerneli versiooni 2.6.32 jaoks.

.Listing 6: Põhiteave faili abil

$ file /bin /touch
/bin/touch: ELF 64-bitine käivitatav LSB, x86-64, versioon 1 (SYSV), dünaamiliselt lingitud, interpreter/lib64/l,
GNU/Linuxi 2.6.32 jaoks, BuildID [sha1] = ec08d609e9e8e73d4be6134541a472ad0ea34502, eemaldatud
$

Teine kandidaat on ise. See kuvab üksikasjalikku teavet ELF -faili kohta. Lülitite loend on suhteliselt pikk ja hõlmab kõiki ELF -vormingu aspekte. Lüliti -n (lühend –notes) kasutamine Loendis 7 kuvatakse ainult failipuudutuses olevad märkmete osad -ABI versiooni silt ja järgu ID bitstring.

.Listing 7: Kuva ELF -faili valitud osad

$ readelf -n/usr/bin/touch

Kuvatakse failide nihkega 0x00000254 leitud märkmed pikkusega 0x00000020:
Omaniku andmete suurus Kirjeldus
GNU 0x00000010 NT_GNU_ABI_TAG (ABI versioonimärgend)
OS: Linux, ABI: 2.6.32

Kuvatakse failide nihkega 0x00000274 leitud märkmed pikkusega 0x00000024:
Omaniku andmete suurus Kirjeldus
GNU 0x00000014 NT_GNU_BUILD_ID (kordumatu järgu ID bitstring)
Ehitise ID: ec08d609e9e8e73d4be6134541a472ad0ea34502

Pange tähele, et Solarise ja FreeBSD all vastab utiliit elfdump [7] readelfile. Alates 2019. aastast pole alates 2003. aastast ühtegi uut väljalaset ega värskendust ilmunud.

Number kolm on pakett nimega elfutils [6], mis on puhtalt Linuxi jaoks saadaval. See pakub GNU Binutilsile alternatiivseid tööriistu ja võimaldab ka ELF -failide valideerimist. Pange tähele, et kõik paketis sisalduvate utiliitide nimed algavad tähega „elf utils”.

Lõpuks mainime objdumpit. See tööriist on sarnane lugemisfunktsiooniga, kuid keskendub objektifailidele. See pakub sarnast teavet ELF -failide ja muude objektivormingute kohta.

.Nimekiri 8: objdumpi ekstraheeritud failiteave

$ objdump -f /bin /touch

/bin/touch: failivorming elf64-x86-64
arhitektuur: i386: x86-64, lipud 0x00000112:
EXEC_P, HAS_SYMS, D_PAGED
stardiaadress 0x00000000004025e3

$

Samuti on olemas tarkvarapakett nimega „elfkickers” [9], mis sisaldab tööriistu ELF -faili sisu lugemiseks ja sellega manipuleerimiseks. Kahjuks on väljaannete arv üsna madal ja sellepärast me lihtsalt mainime seda ja ei näita täiendavaid näiteid.

Arendajana võite selle asemel vaadata „pax-utils” [10,11]. See utiliitide komplekt pakub mitmeid tööriistu, mis aitavad ELF -faile kinnitada. Näiteks analüüsib dumpelf ELF -faili ja tagastab C -päisefaili, mis sisaldab üksikasju - vt joonis 2.

Järeldus

Tänu nutika disaini ja suurepärase dokumentatsiooni kombinatsioonile töötab ELF -vorming väga hästi ja seda kasutatakse ka 20 aasta pärast. Ülaltoodud utiliidid võimaldavad teil saada ülevaate ELF -failist ja saate aru, mida programm teeb. Need on esimesed sammud tarkvara analüüsimiseks - head häkkimist!

Viited ja viited
Tänuavaldused

Kirjanik tänab Axel Beckerti toetuse eest selle artikli ettevalmistamisel.