Comprensió del format de fitxer ELF

Understanding Elf File Format



Del codi font al codi binari

La programació comença per tenir una idea intel·ligent i escriure codi font en un llenguatge de programació que trieu, per exemple C, i desar el codi font en un fitxer. Amb l'ajut d'un compilador adequat, per exemple GCC, el vostre codi font es tradueix primer en codi objecte. Finalment, l'enllaçador tradueix el codi de l'objecte en un fitxer binari que enllaça el codi de l'objecte amb les biblioteques de referència. Aquest fitxer conté les instruccions individuals com a codi de màquina que la CPU entén i que s’executen tan aviat com s’executa el programa compilat.

El fitxer binari esmentat anteriorment segueix una estructura específica i un dels més comuns s’anomena ELF que abrevia Executable and Linkable Format. S'utilitza àmpliament per a fitxers executables, fitxers d'objectes reubicables, biblioteques compartides i abocaments bàsics.







Fa vint anys, el 1999, el projecte 86open ha escollit ELF com a format de fitxer binari estàndard per a sistemes Unix i sistemes similars a Unix en processadors x86. Per sort, el format ELF s’havia documentat prèviament tant a la interfície binària d’aplicacions del sistema V com a la norma d’interfície d’eines [4]. Aquest fet va simplificar enormement l’acord d’estandardització entre els diferents proveïdors i desenvolupadors de sistemes operatius basats en Unix.



La raó darrere d’aquesta decisió va ser el disseny d’ELF: flexibilitat, extensibilitat i suport multiplataforma per a diferents formats i mides d’adreces endianes. El disseny d’ELF no es limita a un processador, conjunt d’instruccions o arquitectura de maquinari específics. Per obtenir una comparació detallada dels formats de fitxers executables, consulteu aquí [3].



Des de llavors, el format ELF és utilitzat per diversos sistemes operatius diferents. Entre d’altres, inclou Linux, Solaris / Illumos, Free-, Net- i OpenBSD, QNX, BeOS / Haiku i Fuchsia OS [2]. A més, el trobareu en dispositius mòbils amb Android, Maemo o Meego OS / Sailfish OS, així com en consoles de jocs com PlayStation Portable, Dreamcast i Wii.





L'especificació no aclareix l'extensió del nom de fitxer per als fitxers ELF. En ús hi ha diverses combinacions de lletres, com ara .axf, .bin, .elf, .o, .prx, .puff, .ko, .so i .mod, o cap.

L'estructura d'un fitxer ELF

En un terminal Linux, l'ordre man elf us proporciona un resum pràctic sobre l'estructura d'un fitxer ELF:



Llistat 1: la pàgina de manual de l'estructura ELF

$ home onze

ELF (5) Manual del programador de Linux ELF (5)

NOM
elf: format de fitxers executables i de format d'enllaç (ELF)

SINOPSI
#incloure

DESCRIPCIÓ
El fitxer de capçalera defineix el format del fitxer executable ELF
Fitxers. Entre aquests fitxers hi ha fitxers executables normals, reubicables
fitxers objecte, fitxers bàsics i biblioteques compartides.

Un fitxer executable que utilitza el format de fitxer ELF consisteix en una capçalera ELF,
seguit d'una taula de capçalera de programa o una taula de capçalera de secció, o ambdues coses.
La capçalera ELF sempre es troba a zero del fitxer. El programa
La taula de capçalera i la compensació de la taula de capçalera de la secció al fitxer són
definit a la capçalera ELF. Les dues taules descriuen la resta de fitxers
particularitats del fitxer.

...

Com podeu veure a la descripció anterior, un fitxer ELF consta de dues seccions: una capçalera ELF i dades de fitxer. La secció de dades de fitxers pot consistir en una taula de capçalera de programa que descriu zero o més segments, una taula de capçalera de secció que descriu zero o més seccions, seguida de dades referides per les entrades de la taula de capçaleres del programa i la taula de capçalera de secció. Cada segment conté informació necessària per a l'execució del fitxer en temps d'execució, mentre que les seccions contenen dades importants per enllaçar i reubicar. La figura 1 ho il·lustra esquemàticament.

La capçalera ELF

La capçalera ELF té una longitud de 32 bytes i identifica el format del fitxer. Comença amb una seqüència de quatre bytes únics que són 0x7F seguits de 0x45, 0x4c i 0x46 que es tradueixen en les tres lletres E, L i F. Entre altres valors, la capçalera també indica si es tracta d’un fitxer ELF per a 32 o El format de 64 bits, utilitza poc o molt d’endianisme, mostra la versió ELF, així com per a quin sistema operatiu s’ha compilat el fitxer per tal d’interoperar amb la interfície binària d’aplicació (ABI) i el conjunt d’instruccions de la CPU adequats.

La descàrrega hexadecimal del fitxer binari tàctil té el següent aspecte:

Llista 2: descàrrega hexadecimal del fitxer binari

$ hd / usr / bin / touch | cap -5
00000000 7f 45 4c 46 02 01 01 00 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 | [correu electrònic protegit] @ ..... |
00000040 06 00 00 00 05 00 00 00 40 00 00 00 00 00 00 00 00 | [correu electrònic protegit] |

Debian GNU / Linux ofereix l’ordre readelf que es proporciona al paquet ‘binutils’ de GNU. Acompanyat del commutador -h (versió curta de –file-header), mostra bé la capçalera d’un fitxer ELF. El llistat 3 il·lustra això per al comandament tàctil.

Llista 3: mostra la capçalera d’un fitxer ELF

$ readelf -h / usr / bin / touch
Capçalera ELF:
Màgia: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 00 00
Classe: ELF64
Dades: complement de 2, poc endian
Versió: 1 (actual)
OS / ABI: UNIX - Sistema V
Versió ABI: 0
Tipus: EXEC (fitxer executable)
Màquina: Advanced Micro Devices X86-64
Versió: 0x1
Adreça del punt d’entrada: 0x4025e3
Inici de les capçaleres del programa: 64 (bytes al fitxer)
Inici de les capçaleres de secció: 58408 (bytes al fitxer)
Banderes: 0x0
Mida d'aquesta capçalera: 64 (bytes)
Mida de capçaleres del programa: 56 (bytes)
Nombre de capçaleres del programa: 9
Mida de capçaleres de secció: 64 (bytes)
Nombre de capçaleres de secció: 27
Índex de taula de cadenes de capçalera de secció: 26

La capçalera del programa

La capçalera del programa mostra els segments utilitzats en temps d'execució i indica al sistema com crear una imatge de procés. La capçalera del llistat 2 mostra que el fitxer ELF consta de 9 capçaleres de programa que tenen una mida de 56 bytes cadascun, i la primera capçalera comença al byte 64.

De nou, l'ordre readelf ajuda a extreure la informació del fitxer ELF. El commutador -l (abreviatura de –program-headers o –segments) revela més detalls tal com es mostra al llistat 4.

Llista 4: mostra informació sobre les capçaleres del programa

$ readelf -l / usr / bin / touch

El tipus de fitxer ELF és EXEC (fitxer executable)
Punt d’entrada 0x4025e3
Hi ha 9 capçaleres de programa, que comencen per l’ofset 64

Capçaleres del programa:
Escriviu Offset VirtAddr PhysAddr
Alineació de banderes MemSiz de FileSiz
PHDR 0x0000000000000040 0x0000000000400040 0x0000000000400040
0x00000000000001f8 0x00000000000001f8 R E 8
INTERP 0x0000000000000238 0x0000000000400238 0x0000000000400238
0x000000000000001c 0x000000000000001c R 1
[Sol·licitud d’intèrpret de programa: /lib64/ld-linux-x86-64.so.2]
CÀRREGA 0x0000000000000000 0x0000000000400000 0x0000000000400000
0x000000000000d494 0x000000000000d494 R E 200000
CÀRREGA 0x000000000000de10 0x000000000060de10 0x000000000060de10
0x0000000000000524 0x0000000000000748 RW 200000
DINÀMICA 0x000000000000de28 0x000000000060de28 0x000000000060de28
0x00000000000001d0 0x00000000000001d0 RW 8
NOTA 0x0000000000000254 0x0000000000400254 0x0000000000400254
0x0000000000000044 0x0000000000000044 R 4
GNU_EH_FRAME 0x000000000000bc40 0x000000000040bc40 0x000000000040bc40
0x00000000000003a4 0x00000000000003a4 R 4
GNU_STACK 0x0000000000000000 0x000000000000000000 0x0000000000000000
0x0000000000000000 0x0000000000000000 RW 10
GNU_RELRO 0x000000000000de10 0x000000000060de10 0x000000000060de10
0x00000000000001f0 0x00000000000001f0 R 1

Secció al mapatge de segments:
Segmenta seccions ...
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 .dinàmic
05 .note.ABI-tag .note.gnu.build-id
06 .eh_frame_hdr
07
08 .init_array .fini_array .jcr .dynamic .got

La capçalera de la secció

La tercera part de l’estructura ELF és la capçalera de secció. Està destinat a enumerar les seccions individuals del binari. El commutador -S (abreviatura de –section-headers o –sections) llista els diferents encapçalaments. Pel que fa a l'ordre tàctil, hi ha 27 capçaleres de secció, i el llistat 5 mostra les quatre primeres més l'última, només. Cada línia cobreix la mida de la secció, el tipus de secció, així com la seva adreça i desplaçament de memòria.

Llista 5: detalls de la secció revelats per ell mateix

$ readelf -S / usr / bin / touch
Hi ha 27 capçaleres de secció, a partir del desplaçament 0xe428:

Capçaleres de secció:
[Núm.] Tipus de nom Adreça Offset
Mida EntSize Banderes Informació de l'enllaç Alinea
[0] NUL 0000000000000000 00000000
0000000000000000 0000000000000000 0 0 0
[ 1] .interp PROGBITS 0000000000400238 00000238
000000000000001c 0000000000000000 A 0 0 1
[2] .note.ABI-tag NOTA 0000000000400254 00000254
0000000000000020 0000000000000000 A 0 0 4
[3] .note.gnu.build-i NOTA 0000000000400274 00000274
...
...
[26] .shstrtab STRTAB 0000000000000000 0000e334
00000000000000ef 0000000000000000 0 0 1
Clau de banderes:
W (escriptura), A (assignació), X (execució), M (combinació), S (cadenes), l (gran)
I (informació), L (ordre d'enllaç), G (grup), T (TLS), E (excloure), x (desconegut)
O (es requereix processament de SO addicional) o (específic del SO), p (específic del processador)

Eines per analitzar un fitxer ELF

Com haureu assenyalat en els exemples anteriors, GNU / Linux conté diverses eines útils que us ajudaran a analitzar un fitxer ELF. El primer candidat que veurem és la utilitat de fitxers.

El fitxer mostra informació bàsica sobre fitxers ELF, inclosa l'arquitectura del conjunt d'instruccions a la qual està destinat el codi d'un fitxer objecte compartit, executable o reubicable. A la llista 6, us indica que / bin / touch és un fitxer executable de 64 bits que segueix la Linux Standard Base (LSB), vinculat dinàmicament i construït per al nucli GNU / Linux versió 2.6.32.

Llista 6: informació bàsica mitjançant fitxers

$ file / bin / touch
/ bin / touch: executable ELS de 64 bits LSB, x86-64, versió 1 (SYSV), vinculat dinàmicament, intèrpret / lib64 / l,
per a GNU / Linux 2.6.32, BuildID [sha1] = ec08d609e9e8e73d4be6134541a472ad0ea34502, eliminat
$

El segon candidat és un mateix. Mostra informació detallada sobre un fitxer ELF. La llista de commutadors és relativament llarga i cobreix tots els aspectes del format ELF. Utilitzant el commutador -n (abreviatura de –notes) El llistat 7 mostra només les seccions de notes que existeixen al fitxer tàctil: l'etiqueta de versió ABI i la cadena de bits de l'ID de compilació.

Llista 7: mostra les seccions seleccionades d’un fitxer ELF

$ readelf -n / usr / bin / touch

Es mostren les notes trobades a la compensació del fitxer 0x00000254 amb la longitud 0x00000020:
Propietari Mida de dades Descripció
GNU 0x00000010 NT_GNU_ABI_TAG (etiqueta de versió ABI)
Sistema operatiu: Linux, ABI: 2.6.32

Es mostren les notes trobades a la compensació del fitxer 0x00000274 amb la longitud 0x00000024:
Propietari Mida de dades Descripció
GNU 0x00000014 NT_GNU_BUILD_ID (cadena de bits ID de compilació única)
Identificador de compilació: ec08d609e9e8e73d4be6134541a472ad0ea34502

Tingueu en compte que sota Solaris i FreeBSD, la utilitat elfdump [7] es correspon amb readelf. A partir del 2019, no hi ha hagut cap versió o actualització nova des del 2003.

El número tres és el paquet anomenat elfutils [6] que només està disponible per a Linux. Proporciona eines alternatives a GNU Binutils i també permet validar fitxers ELF. Tingueu en compte que tots els noms de les utilitats proporcionades al paquet comencen per eu per a 'elf utils'.

Per últim, però no menys important, esmentarem objdump. Aquesta eina és similar a la de lectura pròpia, però se centra en els fitxers objecte. Proporciona una gamma similar d'informació sobre fitxers ELF i altres formats d'objecte.

Llista 8: informació del fitxer extreta per objdump

$ objdump -f / bin / touch

/ bin / touch: format de fitxer elf64-x86-64
arquitectura: i386: x86-64, banderes 0x00000112:
EXEC_P, HAS_SYMS, D_PAGED
adreça inicial 0x00000000004025e3

$

També hi ha un paquet de programari anomenat ‘elfkickers’ [9] que conté eines per llegir el contingut d’un fitxer ELF i manipular-lo. Malauradament, el nombre de llançaments és força baix i per això només l’esmentem i no mostrem més exemples.

Com a desenvolupador, podeu fer una ullada a 'pax-utils' [10,11]. Aquest conjunt d’utilitats proporciona una sèrie d’eines que ajuden a validar fitxers ELF. Com a exemple, dumpelf analitza el fitxer ELF i retorna un fitxer de capçalera C que conté els detalls (vegeu la figura 2).

Conclusió

Gràcies a una combinació de disseny intel·ligent i una excel·lent documentació, el format ELF funciona molt bé i encara s’utilitza després de 20 anys. Les utilitats que es mostren més amunt us permeten una visió detallada d’un fitxer ELF i us permeten esbrinar què fa un programa. Aquests són els primers passos per analitzar el programari: feliç hacking.

Enllaços i referències
Agraïments

L’escriptor vol agrair a Axel Beckert el seu suport en la preparació d’aquest article.