ELFE

Comprendre le format de fichier ELF

Comprendre le format de fichier ELF

Du code source au code binaire

La programmation commence par avoir une idée intelligente, et écrire le code source dans un langage de programmation de votre choix, par exemple C, et enregistrer le code source dans un fichier. A l'aide d'un compilateur adéquat, par exemple GCC, votre code source est traduit en code objet, d'abord. Finalement, l'éditeur de liens traduit le code objet en un fichier binaire qui lie le code objet avec les bibliothèques référencées. Ce fichier contient les instructions individuelles en tant que code machine qui sont comprises par le CPU et sont exécutées dès que le programme compilé est exécuté.

Le fichier binaire mentionné ci-dessus suit une structure spécifique, et l'un des plus courants est nommé ELF qui abrège Executable and Linkable Format. Il est largement utilisé pour les fichiers exécutables, les fichiers objets réadressables, les bibliothèques partagées et les vidages de mémoire.

Il y a vingt ans - en 1999 - le projet 86open a choisi ELF comme format de fichier binaire standard pour les systèmes Unix et de type Unix sur les processeurs x86. Heureusement, le format ELF avait déjà été documenté à la fois dans l'interface binaire d'application System V et dans la norme d'interface d'outil [4]. Ce fait a énormément simplifié l'accord sur la standardisation entre les différents fournisseurs et développeurs de systèmes d'exploitation basés sur Unix.

La raison de cette décision était la conception d'ELF - flexibilité, extensibilité et support multiplateforme pour différents formats endian et tailles d'adresse. La conception d'ELF n'est pas limitée à un processeur, un jeu d'instructions ou une architecture matérielle spécifique. Pour une comparaison détaillée des formats de fichiers exécutables, regardez ici [3].

Depuis lors, le format ELF est utilisé par plusieurs systèmes d'exploitation différents. Entre autres, cela inclut Linux, Solaris/Illumos, Free-, Net- et OpenBSD, QNX, BeOS/Haiku et Fuchsia OS [2]. De plus, vous le trouverez sur les appareils mobiles fonctionnant sous Android, Maemo ou Meego OS/Sailfish OS ainsi que sur les consoles de jeux comme la PlayStation Portable, Dreamcast et Wii.

La spécification ne clarifie pas l'extension de nom de fichier pour les fichiers ELF. Une variété de combinaisons de lettres, telles que .axf, .poubelle, .elfe, .o, .prx, .bouffée, .ko, .donc, et .mod, ou aucun.

La structure d'un fichier ELF

Sur un terminal Linux, la commande man elf vous donne un résumé pratique de la structure d'un fichier ELF :

Listing 1 : La page de manuel de la structure ELF

$ homme elfe
ELF(5) Manuel du programmeur Linux ELF(5)
NOM
elf - format des fichiers Executable and Linking Format (ELF)
SYNOPSIS
#inclure
LA DESCRIPTION
Le fichier d'en-tête définit le format du binaire exécutable ELF
des dossiers. Parmi ces fichiers se trouvent des fichiers exécutables normaux, déplaçables
fichiers objets, fichiers principaux et bibliothèques partagées.
Un fichier exécutable utilisant le format de fichier ELF se compose d'un en-tête ELF,
suivi d'un tableau d'en-tête de programme ou d'un tableau d'en-tête de section, ou les deux.
L'en-tête ELF est toujours à l'offset zéro du fichier. Le programme
table d'en-tête et le décalage de la table d'en-tête de section dans le fichier sont
défini dans l'en-tête ELF. Les deux tableaux décrivent le reste des
particularités du dossier.

Comme vous pouvez le voir dans la description ci-dessus, un fichier ELF se compose de deux sections - un en-tête ELF et des données de fichier. La section de données de fichier peut consister en une table d'en-tête de programme décrivant zéro ou plusieurs segments, une table d'en-tête de section décrivant zéro ou plusieurs sections, qui est suivie de données référencées par des entrées de la table d'en-tête de programme, et la table d'en-tête de section. Chaque segment contient des informations nécessaires à l'exécution du fichier au moment de l'exécution, tandis que les sections contiennent des données importantes pour la liaison et la relocalisation. La figure 1 illustre schématiquement.

L'en-tête ELF

L'en-tête ELF fait 32 octets et identifie le format du fichier. Il commence par une séquence de quatre octets uniques qui sont 0x7F suivis de 0x45, 0x4c et 0x46 qui se traduit par les trois lettres E, L et F. Entre autres valeurs, l'en-tête indique également s'il s'agit d'un fichier ELF au format 32 ou 64 bits, utilise peu ou grand endianness, indique la version ELF ainsi que pour quel système d'exploitation le fichier a été compilé afin d'interagir avec interface binaire d'application droite (ABI) et jeu d'instructions du processeur.

Le vidage hexadécimal du fichier binaire touch se présente comme suit :

.Listing 2 : Le hexdump du fichier binaire

$ hd /usr/bin/touch | tête -5
00000000 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 |.elfe… |
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 |[email protected]@… |
00000040 06 00 00 00 05 00 00 00 40 00 00 00 00 00 00 00 |[email protected]|

Debian GNU/Linux propose la commande readelf fournie dans le paquet GNU 'binutils'. Accompagné du commutateur -h (version courte pour "-file-header") il affiche joliment l'en-tête d'un fichier ELF. Le listing 3 illustre cela pour la commande touch.

.Listing 3 : Affichage de l'en-tête d'un fichier ELF

$ readelf -h /usr/bin/touch
En-tête ELF :
Magie : 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00
Classe : ELF64
Données : complément à 2, petit boutien
Version : 1 (actuelle)
OS/ABI : UNIX - Système V
Version ABI : 0
Type : EXEC (fichier exécutable)
Machine : Micro-appareils avancés X86-64
Version : 0x1
Adresse du point d'entrée : 0x4025e3
Début des en-têtes de programme : 64 (octets dans le fichier)
En-têtes de début de section : 58408 (octets dans le fichier)
Drapeaux : 0x0
Taille de cet en-tête : 64 (octets)
Taille des en-têtes de programme : 56 (octets)
Nombre d'en-têtes de programme : 9
Taille des en-têtes de section : 64 (octets)
Nombre d'en-têtes de section : 27
Index de table de chaîne d'en-tête de section : 26

L'en-tête du programme

L'en-tête du programme affiche les segments utilisés au moment de l'exécution et indique au système comment créer une image de processus. L'en-tête du listing 2 montre que le fichier ELF se compose de 9 en-têtes de programme qui ont une taille de 56 octets chacun, et le premier en-tête commence à l'octet 64.

Encore une fois, la commande readelf permet d'extraire les informations du fichier ELF. Le commutateur -l (abréviation de -program-headers ou -segments) révèle plus de détails comme indiqué dans le listing 4.

.Listing 4: Afficher des informations sur les en-têtes de programme

$ readelf -l /usr/bin/touch
Le type de fichier Elf est EXEC (fichier exécutable)
Point d'entrée 0x4025e3
Il y a 9 en-têtes de programme, commençant à l'offset 64
En-têtes de programme :
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Drapeaux Aligner
PHDR 0x00000000000000040 0x00000000000400040 0x000000000000400040
0x00000000000001f8 0x000000000000001f8 R E 8
INTERP 0x000000000000238 0x0000000000400238 0x00000000000400238
0x000000000000001c 0x000000000000001c R 1
[Interpréteur de programme demandeur : /lib64/ld-linux-x86-64.donc.2]
CHARGE 0x0000000000000000 0x0000000000400000 0x00000000000400000
0x000000000000d494 0x000000000000d494 R E 200000
CHARGE 0x000000000000de10 0x000000000060de10 0x0000000000060de10
0x0000000000000524 0x0000000000000748 LE 200000
DYNAMIQUE 0x000000000000de28 0x0000000000060de28 0x0000000000060de28
0x00000000000001d0 0x000000000000001d0 LE 8
REMARQUE 0x000000000000254 0x0000000000400254 0x00000000000400254
0x00000000000000044 0x00000000000000044 R 4
GNU_EH_FRAME 0x000000000000bc40 0x000000000040bc40 0x000000000040bc40
0x000000000000003a4 0x000000000000003a4 R 4
GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000000 0x0000000000000000 LE 10
GNU_RELRO 0x000000000000de10 0x0000000000060de10 0x0000000000060de10
0x00000000000001f0 0x000000000000001f0 R 1
Mappage de section à segment :
Sections de segments…
00
01 .interpréter
02 .interpréter .Remarque.ABI-tag .Remarque.gnou.ID de construction .gnou.hacher .dynamique .dynstr .gnou.version .gnou.version_r .rela.dyn .rela.plt .init .plt .texte .fini .rodata .eh_frame_hdr .eh_frame
03 .init_array .fini_array .jcr .dynamique .a obtenu .a obtenu.plt .Les données .bss
04 .dynamique
05 .Remarque.ABI-tag .Remarque.gnou.ID de construction
06 .eh_frame_hdr
07
08 .init_array .fini_array .jcr .dynamique .a obtenu

L'en-tête de section

La troisième partie de la structure ELF est l'en-tête de section. Il est destiné à répertorier les sections individuelles du binaire. Le commutateur -S (abréviation de -section-headers ou -sections) liste les différents en-têtes. Quant à la commande tactile, il y a 27 en-têtes de section, et la liste 5 montre les quatre premiers d'entre eux plus le dernier, seulement. Chaque ligne couvre la taille de la section, le type de section ainsi que son adresse et son décalage mémoire.

.Listing 5: Détails de la section révélés par readelf

$ readelf -S /usr/bin/touch
Il y a 27 en-têtes de section, commençant à l'offset 0xe428 :
En-têtes de section :
[Nr] Nom Type Adresse Décalage
Taille EntSize Drapeaux Lien Info Aligner
[ 0] NULL 0000000000000000 00000000
0000000000000000 0000000000000000 0 0 0
[ 1] .PROGBITS interp 0000000000400238 00000238
000000000000001c 0000000000000000 A 0 0 1
[ 2] .Remarque.Étiquette ABI REMARQUE 0000000000400254 00000254
00000000000000020 000000000000000 A 0 0 4
[ 3] .Remarque.gnou.build-i REMARQUE 0000000000400274 00000274


[26] .shstrtab STRTAB 0000000000000000 0000e334
000000000000000ef 000000000000000 0 0 1
Clé des drapeaux :
W (écrire), A (allouer), X (exécuter), M (fusionner), S (chaînes), l (grand)
I (info), L (ordre des liens), G (groupe), T (TLS), E (exclure), x (inconnu)
O (traitement supplémentaire du système d'exploitation requis) o (spécifique au système d'exploitation), p (spécifique au processeur)

Outils pour analyser un fichier ELF

Comme vous l'avez peut-être noté dans les exemples ci-dessus, GNU/Linux est étoffé avec un certain nombre d'outils utiles qui vous aident à analyser un fichier ELF. Le premier candidat que nous examinerons est l'utilitaire de fichier.

fichier affiche des informations de base sur les fichiers ELF, y compris l'architecture du jeu d'instructions pour laquelle le code d'un fichier objet transférable, exécutable ou partagé est destiné. Dans la liste 6, il vous indique que /bin/touch est un fichier exécutable 64 bits suivant la Linux Standard Base (LSB), lié dynamiquement et construit pour le noyau GNU/Linux version 2.6.32.

.Listing 6 : Informations de base à l'aide d'un fichier

$ fichier /bin/touch
/bin/touch : exécutable LSB 64 bits ELF, x86-64, version 1 (SYSV), lié dynamiquement, interpréteur /lib64/l,
pour GNU/Linux 2.6.32, BuildID[sha1]=ec08d609e9e8e73d4be6134541a472ad0ea34502, supprimé
$

Le deuxième candidat est readelf. Il affiche des informations détaillées sur un fichier ELF. La liste des commutateurs est relativement longue et couvre tous les aspects du format ELF. En utilisant le commutateur -n (abréviation de -notes), la liste 7 montre uniquement les sections de notes qui existent dans le fichier touch - la balise de version ABI et la chaîne de bits d'ID de construction.

.Listing 7 : Afficher les sections sélectionnées d'un fichier ELF

$ readelf -n /usr/bin/touch
Affichage des notes trouvées au décalage de fichier 0x00000254 avec une longueur 0x00000020 :
Propriétaire Taille des données Description
GNU 0x0000010 NT_GNU_ABI_TAG (balise de version ABI)
Système d'exploitation : Linux, ABI : 2.6.32
Affichage des notes trouvées au décalage de fichier 0x00000274 avec une longueur 0x00000024 :
Propriétaire Taille des données Description
GNU 0x00000014 NT_GNU_BUILD_ID (chaîne de bits d'ID de construction unique)
ID de construction : ec08d609e9e8e73d4be6134541a472ad0ea34502

Notez que sous Solaris et FreeBSD, l'utilitaire elfdump [7] correspond à readelf. En 2019, il n'y a pas eu de nouvelle version ou de mise à jour depuis 2003.

Le numéro trois est le paquet nommé elfutils [6] qui est purement disponible pour Linux. Il fournit des outils alternatifs à GNU Binutils, et permet également de valider les fichiers ELF. Notez que tous les noms des utilitaires fournis dans le package commencent par eu pour 'elf utils'.

Enfin, nous mentionnerons objdump. Cet outil est similaire à readelf mais se concentre sur les fichiers objets. Il fournit une gamme similaire d'informations sur les fichiers ELF et d'autres formats d'objets.

.Listing 8 : Informations de fichier extraites par objdump

$ objdump -f /bin/touch
/bin/touch : format de fichier elf64-x86-64
architecture : i386 : x86-64, indicateurs 0x00000112 :
EXEC_P, HAS_SYMS, D_PAGED
adresse de début 0x00000000004025e3
$

Il existe également un progiciel appelé 'elfkickers' [9] qui contient des outils pour lire le contenu d'un fichier ELF ainsi que pour le manipuler. Malheureusement, le nombre de versions est plutôt faible, et c'est pourquoi nous le mentionnons simplement, et ne montrons pas d'autres exemples.

En tant que développeur, vous pouvez consulter 'pax-utils' [10,11], à la place. Cet ensemble d'utilitaires fournit un certain nombre d'outils qui aident à valider les fichiers ELF. Par exemple, dumpelf analyse le fichier ELF et renvoie un fichier d'en-tête C contenant les détails - voir Figure 2.

Conclusion

Grâce à une combinaison d'une conception intelligente et d'une excellente documentation, le format ELF fonctionne très bien et est toujours utilisé après 20 ans. Les utilitaires présentés ci-dessus vous permettent d'avoir un aperçu d'un fichier ELF et de comprendre ce que fait un programme. Ce sont les premières étapes de l'analyse des logiciels - un piratage heureux!

Liens et références
  • [1] Format exécutable et associable (ELF), Wikipédia
  • [2] Fuchsia OS
  • [3] Comparaison des formats de fichiers exécutables, Wikipedia
  • [4] Linux Foundation, Spécifications référencées
  • [5] Ciro Santilli : tutoriel ELF Hello World
  • [6] paquet Debian elfutils
  • [7] elfdump
  • [8] Michael Boelen : Les 101 fichiers ELF sous Linux : Compréhension et analyse
  • [9] elfekickers
  • [10] Utilitaires renforcés/PaX
  • [11] pax-utils, paquet Debian
Remerciements

L'auteur tient à remercier Axel Beckert pour son soutien dans la préparation de cet article.

Jeux HD remasterisés pour Linux qui n'ont jamais eu de version Linux plus tôt
De nombreux développeurs et éditeurs de jeux proposent une remasterisation HD d'anciens jeux pour prolonger la durée de vie de la franchise, veuillez ...
Comment utiliser AutoKey pour automatiser les jeux Linux
AutoKey est un utilitaire d'automatisation de bureau pour Linux et X11, programmé en Python 3, GTK et Qt. En utilisant ses fonctionnalités de script e...
Comment afficher le compteur FPS dans les jeux Linux
Les jeux Linux ont reçu une impulsion majeure lorsque Valve a annoncé la prise en charge de Linux pour le client Steam et leurs jeux en 2012. Depuis l...