Forstå ELF -filformatet

Understanding Elf File Format



Fra kildekoden til den binære koden

Programmering starter med å ha en smart idé og skrive kildekoden på et programmeringsspråk du ønsker, for eksempel C, og lagre kildekoden i en fil. Ved hjelp av en tilstrekkelig kompilator, for eksempel GCC, blir kildekoden først oversatt til objektkode. Til slutt oversetter linkeren objektkoden til en binær fil som knytter objektkoden til de refererte bibliotekene. Denne filen inneholder de enkelte instruksjonene som maskinkode som forstås av CPU -en, og kjøres så snart det kompilerte programmet kjøres.

Den binære filen som er nevnt ovenfor følger en spesifikk struktur, og en av de vanligste heter ELF som forkorter kjørbart og sammenkoplingsbart format. Det er mye brukt for kjørbare filer, flyttbare objektfiler, delte biblioteker og kjernedumper.







For tjue år siden-i 1999-har 86open-prosjektet valgt ELF som standard binært filformat for Unix og Unix-lignende systemer på x86-prosessorer. Heldigvis hadde ELF -formatet tidligere blitt dokumentert i både System V Application Binary Interface og Tool Interface Standard [4]. Dette faktum forenklet avtalen om standardisering mellom de forskjellige leverandørene og utviklerne av Unix-baserte operativsystemer enormt.



Årsaken bak den beslutningen var utformingen av ELF-fleksibilitet, utvidbarhet og plattformstøtte for forskjellige endianformater og adressestørrelser. ELFs design er ikke begrenset til en bestemt prosessor, instruksjonssett eller maskinvarearkitektur. For en detaljert sammenligning av kjørbare filformater, se her [3].



Siden den gang har ELF -formatet blitt brukt av flere forskjellige operativsystemer. Blant annet inkluderer dette Linux, Solaris/Illumos, Free-, Net- og OpenBSD, QNX, BeOS/Haiku og Fuchsia OS [2]. Videre finner du den på mobile enheter som kjører Android, Maemo eller Meego OS/Sailfish OS, samt på spillkonsoller som PlayStation Portable, Dreamcast og Wii.





Spesifikasjonen tydeliggjør ikke filnavnutvidelsen for ELF -filer. I bruk er en rekke bokstavkombinasjoner, for eksempel .axf, .bin, .elf, .o, .prx, .puff, .ko, .so og .mod, eller ingen.

Strukturen til en ELF -fil

På en Linux -terminal gir kommandoen man elf deg en praktisk oppsummering om strukturen til en ELF -fil:



Oppføring 1: Mannssiden til ELF -strukturen

$ mann elleve

ELF (5) Linux Programmer's Manual ELF (5)

NAVN
elf - formatet på kjørbare og sammenkoblende format (ELF) -filer

SYNOPSIS
#inkludere

BESKRIVELSE
Hovedfilen definerer formatet til ELF -kjørbar binær
filer. Blant disse filene er normale kjørbare filer, som kan flyttes
objektfiler, kjernefiler og delte biblioteker.

En kjørbar fil som bruker ELF -filformatet består av en ELF -topptekst,
etterfulgt av en programoverskriftstabell eller en seksjonstabell, eller begge deler.
ELF -overskriften er alltid på nullpunktet for filen. Programmet
overskriftstabell og seksjonstabellens forskyvning i filen er
definert i ELF -overskriften. De to tabellene beskriver resten av
særtrekk ved filen.

...

Som du kan se fra beskrivelsen ovenfor, består en ELF -fil av to seksjoner - en ELF -topptekst og fildata. Fildataseksjonen kan bestå av en programoverskriftstabell som beskriver null eller flere segmenter, en seksjonstabell som beskriver null eller flere seksjoner, som etterfølges av data referert til av oppføringer fra programoverskriftstabellen og seksjonstabellen. Hvert segment inneholder informasjon som er nødvendig for kjøring av filen i løpetid, mens seksjoner inneholder viktige data for kobling og flytting. Figur 1 illustrerer dette skjematisk.

ELF -overskriften

ELF -overskriften er 32 byte lang, og identifiserer filformatet. Den starter med en sekvens på fire unike byte som er 0x7F etterfulgt av 0x45, 0x4c og 0x46 som oversetter til de tre bokstavene E, L og F. Blant andre verdier angir overskriften også om det er en ELF -fil for 32 eller 64-biters format, bruker liten eller stor endianness, viser ELF-versjonen samt for hvilket operativsystem filen ble kompilert for å samhandle med det riktige applikasjons binære grensesnittet (ABI) og cpu instruksjonssett.

Hexdumpen til den binære filberøringen ser slik ut:

.Liste 2: Heksdumpen til den binære filen

$ hd/usr/bin/touch | hode -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 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 | [e -postbeskyttet] @..... |
00000040 06 00 00 00 05 00 00 00 40 00 00 00 00 00 00 00 | [e -postbeskyttet] |

Debian GNU/Linux tilbyr readelf -kommandoen som er inkludert i GNU 'binutils' -pakken. Ledsaget av bryteren -h (kort versjon for –file -header) viser det pent overskriften til en ELF -fil. Oppføring 3 illustrerer dette for kommando -berøring.

.Liste 3: Viser toppteksten til en ELF -fil

$ readelf -h/usr/bin/touch
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Klasse: ELF64
Data: 2s komplement, lille endian
Versjon: 1 (nåværende)
OS / ABI: UNIX - System V
ABI -versjon: 0
Type: EXEC (kjørbar fil)
Maskin: Advanced Micro Devices X86-64
Versjon: 0x1
Oppføringsadresse: 0x4025e3
Start av programoverskrifter: 64 (byte i fil)
Start av seksjonsoverskrifter: 58408 (byte i fil)
Flagg: 0x0
Størrelsen på denne overskriften: 64 (byte)
Størrelse på programoverskrifter: 56 (byte)
Antall programoverskrifter: 9
Størrelse på seksjonsoverskrifter: 64 (byte)
Antall seksjonskoder: 27
Seksjonsoverskrift streng tabellindeks: 26

Programhodet

Programhodet viser segmentene som brukes ved kjøretid, og forteller systemet hvordan man lager et prosessbilde. Overskriften fra liste 2 viser at ELF -filen består av 9 programoverskrifter som har en størrelse på 56 byte hver, og den første overskriften starter med byte 64.

Igjen hjelper readelf -kommandoen med å trekke ut informasjonen fra ELF -filen. Bryteren -l (forkortelse for –program -overskrifter eller –segmenter) viser flere detaljer som vist i oppføring 4.

.Liste 4: Vis informasjon om programoverskriftene

$ readelf -l/usr/bin/touch

Elf -filtypen er EXEC (kjørbar fil)
Inngangspunkt 0x4025e3
Det er 9 programoverskrifter, som starter ved forskyvning 64

Programoverskrifter:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
PHDR 0x0000000000000040 0x0000000000400040 0x0000000000400040
0x00000000000001f8 0x00000000000001f8 R E 8
INTERP 0x0000000000000238 0x0000000000400238 0x0000000000400238
0x000000000000001c 0x000000000000001c R 1
[Be om programtolker: /lib64/ld-linux-x86-64.so.2]
LAST 0x0000000000000000 0x0000000000400000 0x0000000000400000
0x000000000000d494 0x000000000000d494 R E 200000
LAST 0x000000000000de10 0x000000000060de10 0x000000000060de10
0x0000000000000524 0x0000000000000748 RW 200000
DYNAMISK 0x000000000000de28 0x000000000060de28 0x000000000060de28
0x00000000000001d0 0x00000000000001d0 RW 8
MERK 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

Seksjon til segmentkartlegging:
Segmentseksjoner ...
00
01. Interp
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. Dynamisk
05 .note.ABI-tag .note.gnu.build-id
06 .eh_frame_hdr
07
08 .init_array .fini_array .jcr .dynamic .got

Seksjonsoverskriften

Den tredje delen av ELF -strukturen er seksjonsoverskriften. Det er ment å liste de enkelte delene av binæren. Bryteren -S (forkortelse for –seksjon -overskrifter eller –seksjoner) viser de forskjellige overskriftene. Når det gjelder berøringskommandoen, er det 27 seksjonsoverskrifter, og oppføring 5 viser bare de fire første pluss den siste. Hver linje dekker seksjonens størrelse, seksjonstype samt adresse og minneforskyvning.

.Liste 5: Seksjonsdetaljer avslørt av seg selv

$ readelf -S/usr/bin/touch
Det er 27 seksjonsoverskrifter, som starter ved forskyvning 0xe428:

Seksjonsoverskrifter:
[Nr] Navnetype Adresseforskyvning
Størrelse EntSize Flags Link Info Juster
[0] NULL 0000000000000000 00000000
0000000000000000 0000000000000000 0 0 0
[1] .interp PROGBITS 0000000000400238 00000238
000000000000001c 0000000000000000 A 0 0 1
[2] .note.ABI-tag NOTE 0000000000400254 00000254
0000000000000020 0000000000000000 A 0 0 4
[3] .note.gnu.build-i MERK 0000000000400274 00000274
...
...
[26] .shstrtab STRTAB 0000000000000000 0000e334
00000000000000ef 0000000000000000 0 0 1
Nøkkel til flagg:
W (skrive), A (fordel), X (utfør), M (flette), S (strenger), l (stor)
I (info), L (lenkerekkefølge), G (gruppe), T (TLS), E (ekskluder), x (ukjent)
O (ekstra OS -behandling nødvendig) o (OS -spesifikk), p (prosessorspesifikk)

Verktøy for å analysere en ELF -fil

Som du kanskje har nevnt fra eksemplene ovenfor, er GNU/Linux utstyrt med en rekke nyttige verktøy som hjelper deg med å analysere en ELF -fil. Den første kandidaten vi vil se på er filverktøyet.

filen viser grunnleggende informasjon om ELF -filer, inkludert instruksjonsarkitekturen som koden i en flyttbar, kjørbar eller delt objektfil er beregnet på. I oppføring 6 forteller den deg at/bin/touch er en 64-biters kjørbar fil som følger Linux Standard Base (LSB), dynamisk koblet og bygget for GNU/Linux-kjernen versjon 2.6.32.

.Liste 6: Grunnleggende informasjon ved bruk av fil

$ file /bin /touch
/bin/touch: ELF 64-biters LSB kjørbar, x86-64, versjon 1 (SYSV), dynamisk koblet, tolk/lib64/l,
for GNU/Linux 2.6.32, BuildID [sha1] = ec08d609e9e8e73d4be6134541a472ad0ea34502, strippet
$

Den andre kandidaten er selv. Den viser detaljert informasjon om en ELF -fil. Listen over brytere er relativt lang, og dekker alle aspektene ved ELF -formatet. Ved å bruke bryteren -n (forkortelse for –notes) Oppføring 7 viser bare notatseksjonene som finnes i filberøringen -ABI -versjonskoden og build -ID -bitstrengen.

.Liste 7: Vis utvalgte deler av en ELF -fil

$ readelf -n/usr/bin/touch

Viser notater funnet på filforskyvning 0x00000254 med lengde 0x00000020:
Eier Datastørrelse Beskrivelse
GNU 0x00000010 NT_GNU_ABI_TAG (ABI versjonskode)
OS: Linux, ABI: 2.6.32

Viser notater funnet på filforskyvning 0x00000274 med lengde 0x00000024:
Eier Datastørrelse Beskrivelse
GNU 0x00000014 NT_GNU_BUILD_ID (unik bygg -ID bitstreng)
Bygg -ID: ec08d609e9e8e73d4be6134541a472ad0ea34502

Vær oppmerksom på at under Solaris og FreeBSD samsvarer verktøyet elfdump [7] med readelf. Fra og med 2019 har det ikke vært en ny utgivelse eller oppdatering siden 2003.

Nummer tre er pakken elfutils [6] som er rent tilgjengelig for Linux. Den gir alternative verktøy til GNU Binutils, og tillater også validering av ELF -filer. Vær oppmerksom på at alle navnene på verktøyene som følger med i pakken starter med eu for 'elf utils'.

Sist men ikke minst vil vi nevne objdump. Dette verktøyet ligner på readelf, men fokuserer på objektfiler. Den gir et lignende informasjonsområde om ELF -filer og andre objektformater.

.Liste 8: Filinformasjon hentet ut av objdump

$ objdump -f /bin /touch

/bin/touch: filformat elf64-x86-64
arkitektur: i386: x86-64, flagg 0x00000112:
EXEC_P, HAS_SYMS, D_PAGED
startadresse 0x00000000004025e3

$

Det er også en programvarepakke kalt 'elfkickers' [9] som inneholder verktøy for å lese innholdet i en ELF -fil, så vel som å manipulere den. Dessverre er antallet utgivelser ganske lavt, og det er derfor vi bare nevner det og ikke viser flere eksempler.

Som utvikler kan du se på ‘pax-utils’ [10,11] i stedet. Dette settet med verktøy gir en rekke verktøy som hjelper til med å validere ELF -filer. Som et eksempel analyserer dumpelf ELF -filen og returnerer en C -toppfil som inneholder detaljene - se figur 2.

Konklusjon

Takket være en kombinasjon av smart design og utmerket dokumentasjon fungerer ELF -formatet veldig bra, og er fortsatt i bruk etter 20 år. Verktøyene vist ovenfor gir deg et innblikk i en ELF -fil, og lar deg finne ut hva et program gjør. Dette er de første trinnene for å analysere programvare - lykkelig hacking!

Lenker og referanser
Anerkjennelser

Forfatteren vil takke Axel Beckert for støtten til utarbeidelsen av denne artikkelen.