Comprensione del formato del file elfo

Comprensione del formato del file elfo

Dal codice sorgente al codice binario

La programmazione inizia con un'idea intelligente e scrivendo il codice sorgente in un linguaggio di programmazione di tua scelta, ad esempio C e salvare il codice sorgente in un file. Con l'aiuto di un compilatore adeguato, ad esempio GCC, il codice sorgente viene tradotto in codice oggetto, prima. Alla fine, il linker traduce il codice oggetto in un file binario che collega il codice oggetto con le librerie di riferimento. Questo file contiene le singole istruzioni come codice macchina compreso dalla CPU e viene eseguito non appena viene eseguito il programma compilato.

Il file binario sopra menzionato segue una struttura specifica e uno dei più comuni è chiamato elfo che abbrevia il formato eseguibile e collegabile. È ampiamente utilizzato per file eseguibili, file di oggetti trasferibili, librerie condivise e dump core.

Venti anni fa - Nel 1999 - Il progetto 86open ha scelto ELF come formato di file binario standard per sistemi unix e unix su processori X86. Fortunatamente, il formato ELF era stato precedentemente documentato sia nell'interfaccia binaria dell'applicazione di System V, sia nello standard dell'interfaccia dello strumento [4]. Questo fatto ha semplificato enormemente l'accordo sulla standardizzazione tra i diversi fornitori e gli sviluppatori di sistemi operativi basati su Unix.

Il motivo alla base di tale decisione è stato la progettazione di elfo: flessibilità, estensibilità e supporto multipiattaforma per diversi formati endian e dimensioni degli indirizzi. La progettazione di Elf non si limita a un processore specifico, set di istruzioni o architettura hardware. Per un confronto dettagliato dei formati di file eseguibili, dai un'occhiata qui [3].

Da allora, il formato ELF è in uso da diversi sistemi operativi. Tra gli altri, questo include Linux, Solaris/Illumos, Free-, Net- e OpenBSD, QNX, BeoS/Haiku e Fuchsia OS [2]. Inoltre, lo troverai su dispositivi mobili che eseguono Android, Maemo o Meego OS/Sailfish OS, nonché su console di gioco come PlayStation Portable, Dreamcast e Wii.

La specifica non chiarisce l'estensione del nome file per i file ELF. In uso è una varietà di combinazioni di lettere, come .axf, .bidone, .elfo, .o, .PRX, .sbuffo, .ko, .così e .mod o nessuno.

La struttura di un file elfo

Su un terminal Linux, il comando elfo ti dà un utile riassunto sulla struttura di un file ELF:

Elenco 1: la manpazza della struttura degli elfi

$ uomo elfo
ELF (5) MANUALE LINUX MANUALE ELF (5)
NOME
ELF - Format dei file ELF (Esecutable and Linking Formato (ELF)
SINOSSI
#includere
DESCRIZIONE
Il file di intestazione definisce il formato del binario eseguibile ELF
File. Tra questi file ci sono i normali file eseguibili, trasferibili
file di oggetti, file core e librerie condivise.
Un file eseguibile che utilizza il formato del file ELF è costituito da un'intestazione ELF,
seguito da una tabella di intestazione del programma o da una tabella di intestazione di sezione o entrambi.
L'intestazione ELF è sempre all'offset zero del file. Il programma
La tabella dell'intestazione e la tabella di intestazione della sezione nel file sono
definito nell'intestazione degli elfi. Le due tabelle descrivono il resto del
particolarità del file.
..

Come puoi vedere dalla descrizione sopra, un file ELF è costituito da due sezioni: un'intestazione ELF e dati di file. La sezione dei dati dei file può essere costituita da una tabella di intestazione del programma che descrive zero o più segmenti, una tabella di intestazione della sezione che descrive zero o più sezioni, seguite da dati a cui si fa riferimento dalle voci dalla tabella dell'intestazione del programma e dalla tabella dell'intestazione della sezione. Ogni segmento contiene informazioni necessarie per l'esecuzione del tempo del file, mentre le sezioni contengono dati importanti per il collegamento e il trasferimento. La Figura 1 lo illustra schematicamente.

L'intestazione degli elfi

L'intestazione ELF è lunga 32 byte e identifica il formato del file. Si inizia con una sequenza di quattro byte unici che sono 0x7f seguiti da 0x45, 0x4c e 0x46 che si traduce nelle tre lettere E, L e F. Tra gli altri valori, l'intestazione indica anche se si tratta di un file ELF per un formato a 32 o 64 bit, utilizza poca o grande endianness, mostra la versione ELF e per il quale il sistema operativo è stato compilato per interagire con il Set di istruzioni binarie per applicazioni destra (ABI) e CPU.

L'esdump del tocco binario sembra segue:

.Elenco 2: L'hexdump del file binario

$ hd/usr/bin/touch | Testa -5
00000000 7F 45 4C 46 02 01 01 00 00 00 00 00 00 00 00 00 |.Elfo ... |
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 |… @.8… @… |
00000040 06 00 00 00 05 00 00 00 40 00 00 00 00 00 00 00 |… @… |

Debian GNU/Linux offre il comando readelf fornito nel pacchetto GNU "Binutils". Accompagnato da Switch -H (versione breve per "-File-Header") Visualizza bene l'intestazione di un file ELF. La lista 3 lo illustra per il comando.

.Elenco 3: visualizzazione dell'intestazione di un file ELF

$ readelf -h/usr/bin/touch
Elfo Weader:
Magic: 7f 45 4C 46 02 01 01 00 00 00 00 00 00 00 00 00
Classe: elf64
Dati: complemento 2, piccolo endian
Versione: 1 (corrente)
OS/ABI: Unix - System V
Versione ABI: 0
Tipo: Exec (File eseguibile)
Macchina: micro dispositivi avanzati x86-64
Versione: 0x1
Indirizzo del punto di ingresso: 0x4025e3
Inizio delle intestazioni del programma: 64 (byte in file)
Inizio delle intestazioni di sezione: 58408 (byte nel file)
Flag: 0x0
Dimensione di questa intestazione: 64 (byte)
Dimensioni delle intestazioni del programma: 56 (byte)
Numero di intestazioni del programma: 9
Dimensione delle intestazioni di sezione: 64 (byte)
Numero di intestazioni di sezione: 27
Sezione Intestazione della stringa Indice: 26

L'intestazione del programma

L'intestazione del programma mostra i segmenti utilizzati in fase di esecuzione e indica al sistema come creare un'immagine di processo. L'intestazione dall'elenco 2 mostra che il file elfo è composto da 9 intestazioni del programma che hanno una dimensione di 56 byte ciascuno e la prima intestazione inizia al byte 64.

Ancora una volta, il comando Readelf aiuta a estrarre le informazioni dal file ELF. Lo switch -L (corto per -program -headers o -segments) rivela maggiori dettagli come mostrato nell'elenco 4.

.Elenco 4: visualizzare le informazioni sulle intestazioni del programma

$ readelf -l/usr/bin/touch
Il tipo di file ELF è Exec (file eseguibile)
Punto di ingresso 0x4025e3
Ci sono 9 intestazioni del programma, a partire dall'offset 64
Intestazioni del programma:
Digitare Offset Virtadddra PhasAddr
Flag Filesiz MEMSIZ Flags Allinea
PHDR 0x00000000000040 0x00000000400040 0x0000000000400040
0x00000000000001f8 0x000000000001f8 R E 8
Interp 0x00000000000238 0x00000000400238 0x0000000000400238
0x000000000000001C 0x0000000000001C R 1
[Interprete di programma di richiesta: /lib64 /ld-linux-x86-64.COSÌ.2]
Carica 0x0000000000000000 0x00000000400000 0x0000000000400000
0x000000000000d494 0x0000000000d494 R E 200000
Carica 0x0000000000DE10 0x0000000060DE10 0x000000000060DE10
0x0000000000000524 0x00000000000748 RW 200000
Dinamico 0x0000000000de28 0x000000000060DE28 0x000000000060DE28
0x00000000000001D0 0x000000000001D0 RW 8
Nota 0x0000000000000254 0x00000000400254 0x0000000000400254
0x0000000000000044 0x00000000000044 R 4
Gnu_eh_frame 0x0000000000bc40 0x000000000040bc40 0x00000000000040bc40
0x00000000000003A4 0x000000000003A4 R 4
GNU_STACK 0x00000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000000 0x00000000000000 RW 10
GNU_RELRO 0x0000000000DE10 0x000000000060DE10 0x000000000060DE10
0x00000000000001F0 0x000000000001F0 R 1
Sezione per mappatura dei segmenti:
Sezioni di segmento ..
00
01 .interp
02 .interp .Nota.Abi-tag .Nota.gnu.ID build .gnu.hash .Dynsym .Dynstr .gnu.versione .gnu.versione_r .Rela.Dyn .Rela.Plt .dentro .Plt .testo .Fini .Rodata .EH_FRAME_HDR .eh_frame
03 .init_array .Fini_array .jcr .dinamico .avuto .avuto.Plt .dati .BSS
04 .dinamico
05 .Nota.Abi-tag .Nota.gnu.ID build
06 .EH_FRAME_HDR
07
08 .init_array .Fini_array .jcr .dinamico .avuto

L'intestazione della sezione

La terza parte della struttura degli elfo è l'intestazione della sezione. Ha lo scopo di elencare le singole sezioni del binario. Lo switch -s (corto per le sezioni di sezione o -sezioni) elenca le diverse intestazioni. Per quanto riguarda il comando touch, ci sono 27 intestazioni di sezione e l'elenco 5 mostra i primi quattro più l'ultimo, solo. Ogni riga copre la dimensione della sezione, il tipo di sezione, nonché il suo indirizzo e offset di memoria.

.Elenco 5: Dettagli della sezione rivelati da Readelf

$ readelf -s/usr/bin/touch
Ci sono 27 intestazioni di sezione, a partire dall'offset 0xe428:
Intestazioni di sezione:
[NR] Nome Tipo Indirizzo Offset
Dimensione Entize Flags Link Info Allinea
[0] NULL 0000000000000000 00000000
0000000000000000 0000000000000000 0 0 0
[1] .PROGBITS interp 0000000000400238 00000238
000000000000001C 00000000000000 A 0 0 1
[2] .Nota.Nota ABI-TAG 0000000000400254 00000254
0000000000000020 00000000000000 A 0 0 4
[3] .Nota.gnu.Build-I Note 0000000000400274 00000274
..
..
[26] .SHSTRTAB STRTAB 0000000000000000 0000E334
00000000000000EF 0000000000000000 0 0 1
Chiave per le bandiere:
W (scrittura), A (alloc), x (esecuzione), m (unione), s (stringhe), l (grande)
I (info), l (ordine di collegamento), g (gruppo), t (tls), e (escludere), x (sconosciuto)
O (elaborazione aggiuntiva del sistema operativo richiesto) O (sistema operativo), P (processore specifico)

Strumenti per analizzare un file elfo

Come avrai notato dagli esempi sopra, GNU/Linux è arricchito con una serie di strumenti utili che ti aiutano ad analizzare un file ELF. Il primo candidato che daremo un'occhiata è l'utilità del file.

Il file visualizza le informazioni di base sui file ELF, inclusa l'architettura impostata per le istruzioni per la quale il codice in un file di oggetti trasferibile, eseguibile o condiviso è previsto. Nell'elenco 6 dice che/bin/touch è un file eseguibile a 64 bit seguendo la base standard Linux (LSB), dinamicamente collegata e costruita per il kernel GNU/Linux versione 2.6.32.

.Elenco 6: Informazioni di base utilizzando il file

$ file /bin /touch
/Bin/Touch: Elf 64-BIT LSB Executable, X86-64, versione 1 (SYSV), dinamicamente collegato, Interprete/Lib64/L,
per GNU/Linux 2.6.32, buildid [sha1] = EC08d609e9e8e73d4be6134541a472ad0ea34502, spogliato
$

Il secondo candidato è letto. Visualizza informazioni dettagliate su un file ELF. L'elenco degli switch è relativamente lungo e copre tutti gli aspetti del formato ELF. Utilizzando lo switch -n (breve per -note) Listato 7 mostra solo le sezioni Note, che esistono nel tocco del file: il tag versione ABI e la stringa di build ID.

.Elenco 7: visualizzare le sezioni selezionate di un file ELF

$ readelf -n/usr/bin/touch
Visualizzazione delle note trovate all'offset file 0x00000254 con lunghezza 0x00000020:
Descrizione della dimensione dei dati del proprietario
GNU 0x00000010 NT_GNU_ABI_TAG (Tag della versione ABI)
OS: Linux, Abi: 2.6.32
Visualizzazione delle note trovate all'offset del file 0x00000274 con lunghezza 0x00000024:
Descrizione della dimensione dei dati del proprietario
GNU 0x00000014 NT_GNU_BUILD_ID (Build ID univoco Bitstring)
ID build: EC08D609E9E8E73D4BE6134541A472AD0EA34502

Si noti che sotto Solaris e FreeBSD, l'Elfdump dell'utilità [7] corrisponde a Readelf. A partire dal 2019, non c'è stata una nuova versione o aggiornamento dal 2003.

Il numero tre è il pacchetto denominato Elfutils [6] che è puramente disponibile per Linux. Fornisce strumenti alternativi ai binutili GNU e consente anche di convalidare i file ELF. Si noti che tutti i nomi delle utility fornite nel pacchetto iniziano con l'UE per "Elf Utils".

Ultimo ma non meno importante menzionare Objdump. Questo strumento è simile al lettura ma si concentra su file di oggetti. Fornisce una gamma simile di informazioni sui file ELF e su altri formati di oggetti.

.Elenco 8: Informazioni sul file estratte da Objdump

$ objdump -f /bin /touch
/bin/touch: formato file elf64-x86-64
Architettura: i386: x86-64, flags 0x00000112:
EXEC_P, HAS_SYMS, D_PAGED
Indirizzo di avvio 0x000000004025E3
$

Esiste anche un pacchetto software chiamato "Elfkickers" [9] che contiene strumenti per leggere il contenuto di un file ELF e manipolarlo. Sfortunatamente, il numero di versioni è piuttosto basso, ed è per questo che lo menzioniamo e non mostriamo ulteriori esempi.

Come sviluppatore potresti dare un'occhiata a "Pax-Utils" [10,11]. Questo set di utility fornisce una serie di strumenti che aiutano a convalidare i file ELF. Ad esempio, Dumpelf analizza il file ELF e restituisce un file di intestazione C contenente i dettagli - vedere la Figura 2.

Conclusione

Grazie a una combinazione di design intelligente e documentazione eccellente il formato Elfo funziona molto bene ed è ancora in uso dopo 20 anni. Le utility mostrate sopra consentono una vista di approfondimento in un file elfo e ti consentono di capire cosa sta facendo un programma. Questi sono i primi passi per l'analisi del software - Happy Hacking!

Collegamenti e riferimenti
  • [1] Formato eseguibile e collegabile (ELF), Wikipedia
  • [2] Fuchsia OS
  • [3] Confronto di formati di file eseguibili, Wikipedia
  • [4] Linux Foundation, Specifiche di riferimento
  • [5] Ciro Santilli: Elf Hello World Tutorial
  • [6] Pacchetto Elfutils Debian
  • [7] Elfdump
  • [8] Michael Boelen: il 101 dei file ELF su Linux: comprensione e analisi
  • [9] Elfkickers
  • [10] Utilità indurite/PAX
  • [11] Pax-otils, pacchetto Debian
Riconoscimenti

Lo scrittore desidera ringraziare Axel Beckert per il suo sostegno riguardo alla preparazione di questo articolo.