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 du code source dans un langage de programmation de votre choix, par exemple C, et l'enregistrement du code source dans un fichier. À l'aide d'un compilateur adéquat, par exemple GCC, votre code source est traduit en code d'objet, d'abord. Finalement, le linker traduit le code d'objet en un fichier binaire qui relie le code d'objet avec les bibliothèques référencées. Ce fichier contient les instructions uniques sous forme de code machine qui sont comprises par le CPU et sont exécutées dès l'exécution du programme compilé.

Le fichier binaire mentionné ci-dessus suit une structure spécifique, et l'un des plus courants s'appelle ELF qui abréviate le format exécutable et lien. Il est largement utilisé pour les fichiers exécutables, les fichiers d'objets relocalisés, les bibliothèques partagées et les vidages de base.

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 UNIX sur les processeurs x86. Heureusement, le format ELF avait été précédemment documenté à la fois dans l'interface binaire d'application System V et la norme d'interface d'outil [4]. Ce fait a énormément simplifié l'accord sur la normalisation 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 de l'elfe - flexibilité, extensibilité et prise en charge multiplateforme pour différents formats endian et tailles d'adresse. La conception d'Elf n'est pas limitée à un processeur, un ensemble d'instructions ou une architecture matérielle spécifique. Pour une comparaison détaillée des formats de fichiers exécutables, jetez un œil ici [3].

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

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

La structure d'un fichier elfe

Sur un terminal Linux, l'elfe de Command Man vous donne un résumé pratique sur la structure d'un fichier ELF:

Listing 1: la page manuelle de la structure ELF

$ man elfe
Elfe (5) Elfe du manuel du programmeur Linux (5)
NOM
ELF - Format des fichiers de format exécutable et de liaison (ELF)
SYNOPSIS
#inclure
DESCRIPTION
Le fichier d'en-tête définit le format de l'Elfe Exécutable binaire
des dossiers. Parmi ces fichiers se trouvent des fichiers exécutables normaux, relocable
Fichiers d'objet, fichiers de base 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'une table d'en-tête de programme ou d'une table d'en-tête de section, ou les deux.
L'en-tête Elfe est toujours à la fin de la fin du fichier. Le programme
La 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 elfe. Les deux tables décrivent le reste du
les particularités du fichier.

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 fichiers. La section des données du fichier peut être composée d'un tableau d'en-tête de programme décrivant zéro ou plus de segments, un tableau d'en-tête de section décrivant zéro ou plus de sections, suivi des données visées par les entrées de la table d'en-tête du programme et la table d'en-tête de section. Chaque segment contient des informations nécessaires à l'exécution de l'exécution du fichier, tandis que les sections contiennent des données importantes pour lier et relocaliser. La figure 1 illustre cette schéma.

L'en-tête elfe

L'en-tête Elfe mesure 32 octets de long 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. Parmi les autres valeurs, l'en-tête indique également s'il s'agit d'un fichier ELF pour le format 32 ou 64 bits, utilise peu ou Big Endianness, affiche la version ELF ainsi que pour quel système d'exploitation a été compilé pour interférer avec le Interface binaire de bonne application (ABI) et ensemble d'instructions CPU.

Le hexdump du fichier binaire touchait comme suit:

.Listing 2: L'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 |… @.8… @… |
00000040 06 00 00 00 05 00 00 00 40 00 00 00 00 00 00 00 |… @… |

Debian GNU / Linux propose la commande Readel qui est fournie dans le package GNU 'Binutils'. Accompagné du commutateur -h (version courte pour «-file-header»), il affiche bien l'en-tête d'un fichier elfe. Listing 3 illustre cela pour la commande de commande.

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

$ Readel -h / usr / bin / Touch
En-tête elfe:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Classe: ELF64
Données: complément de 2, Little Endian
Version: 1 (actuel)
OS / ABI: UNIX - Système V
Version ABI: 0
Type: Exec (fichier exécutable)
Machine: Micro Dispositifs 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)
Début des en-têtes de section: 58408 (octets dans le fichier)
Flags: 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 montre 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 de 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 de lecture aide à extraire les informations du fichier ELF. Le commutateur -l (abréviation pour -program-theaders ou -segments) révèle plus de détails comme indiqué dans la liste 4.

.Listing 4: afficher des informations sur les en-têtes du programme

$ Readel -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, à partir de décalage 64
En-têtes de programme:
Tapez le décalage Virtaddr Physaddr
FileSiz MemSiz Flags Align
PHDR 0x0000000000000040 0x0000000000400040 0x00000000400040
0x00000000000001F8 0x00000000000001F8 R E 8
Interp 0x0000000000000238 0x0000000000400238 0x0000000000400238
0x000000000000001C 0x000000000000001C R 1
[Interpréteur du programme de demande: / lib64 / ld-linux-x86-64.donc.2]
Chargez 0x0000000000000000 0x0000000000400000 0x0000000000400000
0x000000000000D494 0x000000000000D494 R E 200000
Chargez 0x00000000000000DE10 0x000000000060DE10 0x000000000060DE10
0x0000000000000524 0x0000000000000748 RW 200000
Dynamique 0x000000000000DE28 0x000000000060de28 0x00000000000060de28
0x00000000000001D0 0x00000000000001D0 RW 8
Remarque 0x0000000000000254 0x0000000000400254 0x0000000000400254
0x0000000000000044 0x000000000000000044 R 4
GNU_EH_FRAME 0x000000000000BC40 0x000000000040BC40 0x000000000040BC40
0x00000000000003A4 0x0000000000000003A4 R 4
GNU_STACK 0x0000000000000000 0x0000000000000000 0x00000000000000
0x0000000000000000 0x000000000000000000 RW 10
GNU_RELRO 0x00000000000000DE10 0x000000000060DE10 0x00000000000060DE10
0x00000000000001F0 0x00000000000001F0 R 1
Mappage de segment à segment:
Sections de segment…
00
01 .interpréter
02 .interpréter .note.Abi-tag .note.gnou.build-id .gnou.hacher .dynsym .dynstrue .gnou.version .gnou.version_r .lié.dyn .lié.PLT .init .PLT .texte .fini .Rodata .eh_frame_hdr .eh_frame
03 .init_array .fin_array .JCR .dynamique .a obtenu .a obtenu.PLT .données .BSS
04 .dynamique
05 .note.Abi-tag .note.gnou.build-id
06 .eh_frame_hdr
07
08 .init_array .fin_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é à énumérer les sections uniques du binaire. Le commutateur -s (abréviation pour les t-t-t-t-t-thers ou -sections) répertorie les différents en-têtes. Quant à la commande tactile, il y a 27 en-têtes de section, et le listing 5 affiche les quatre premiers plus le dernier, seulement. Chaque ligne couvre la taille de la section, le type de section ainsi que son adresse et son décalage de mémoire.

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

$ Readel -s / usr / bin / Touch
Il y a 27 en-têtes de section, à partir de décalage 0xe428:
En-têtes de section:
[Nr] Offset d'adresse de type de nom
Taille des informations sur les drapeaux de taille
[0] null 0000000000000000 00000000
0000000000000000 000000000000000000 0 0 0
[ 1] .Interp Progbits 0000000000400238 00000238
000000000000001C 000000000000000000 A 0 0 1
[2] .note.Note Abi-Tag 0000000000400254 00000254
000000000000000020 000000000000000000 A 0 0 4
[3] .note.gnou.Build-i Note 0000000000400274 00000274


[26] .shstrtab strtab 0000000000000000 0000e334
000000000000000000F 000000000000000000 0 0 1
Clé des drapeaux:
W (write), a (alloc), x (exécuter), m (fusion), s (cordes), l (grand)
I (info), l (ordre de lien), g (groupe), t (tls), e (exclure), x (inconnu)
O (traitement du système d'exploitation supplémentaire requis) o (SPÉCIFICALE), P (spécifique au processeur)

Outils pour analyser un fichier ELF

Comme vous l'avez peut-être noté à partir des 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 allons jeter un œil est l'utilitaire de fichier.

Le fichier affiche des informations de base sur les fichiers ELF, y compris l'architecture d'instructions pour laquelle le code dans un fichier d'objet relocable, exécutable ou partagé est prévu. Dans Listing 6, il vous indique que / bin / touch est un fichier exécutable 64 bits suivant la base standard Linux (LSB), liée dynamiquement et construite pour la version 2 du noyau GNU / Linux.6.32.

.Listing 6: informations de base à l'aide du fichier

$ file / bin / touch
/ bin / Touch: EXECTABLE LSB ELF 64 bits, x86-64, version 1 (SYSV), lié dynamiquement, interprète / lib64 / l,
pour GNU / Linux 2.6.32, buildId [sha1] = ec08d609e9e8e73d4be6134541a472ad0ea34502, dépouillé
$

Le deuxième candidat est lu. Il affiche des informations détaillées sur un fichier ELF. La liste des commutateurs est comparable et couvre tous les aspects du format ELF. L'utilisation du commutateur -N (abréviation pour -notes) Listing 7 montre les sections de notes, seulement qui existent dans le fichier touch - la balise de version ABI et le build id bitstring.

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

$ Readel -n / usr / bin / Touch
Affichage des notes trouvées au décalage de fichier 0x00000254 avec la longueur 0x00000020:
Description de la taille des données du propriétaire
GNU 0x00000010 NT_GNU_ABI_TAG (TAG DE VERSION ABI)
OS: Linux, ABI: 2.6.32
Affichage des notes trouvées au décalage de fichier 0x00000274 avec la longueur 0x00000024:
Description de la taille des données du propriétaire
GNU 0x00000014 NT_GU_BUILD_ID (ID de construction unique BitString)
ID de construction: EC08D609E9E8E73D4BE6134541A472AD0EA34502

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

Le numéro trois est le package nommé Elfutils [6] qui est purement disponible pour Linux. Il fournit des outils alternatifs aux binutilles GNU et permet également de valider les fichiers ELF. Notez que tous les noms des utilitaires fournis dans le package commencent par l'UE pour les «utils elfe».

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

.Listing 8: Informations sur le fichier extraites par Objdump

$ objdump -f / bin / touch
/ bin / Touch: Format de fichier ELF64-X86-64
Architecture: i386: x86-64, drapeaux 0x00000112:
Exec_p, has_syms, d_paged
Adresse de démarrage 0x00000000004025E3
$

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

En tant que développeur, vous pouvez jeter un œil à «Pax-utils» [10,11], plutôt. Cet ensemble de services publics fournit un certain nombre d'outils qui aident à valider les fichiers ELF. À titre d'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 de conception intelligente et d'une excellente documentation, le format ELF fonctionne très bien, et est toujours utilisé après 20 ans. Les utilitaires illustrés ci-dessus vous permettent une vue d'informations sur un fichier ELF et vous permettent de déterminer ce qu'un programme fait. Ce sont les premières étapes pour analyser les logiciels - Happy Hacking!

Liens et références
  • [1] Format exécutable et lien (ELF), Wikipedia
  • [2] Fuchsia OS
  • [3] Comparaison des formats de fichiers exécutables, Wikipedia
  • [4] Fondation Linux, spécifications référencées
  • [5] Ciro Santilli: Elf Hello World Tutorial
  • [6] Package de Debian Elfutils
  • [7] ElfDump
  • [8] Michael Boelen: le 101 des fichiers ELF sur Linux: compréhension et analyse
  • [9] Elfkickers
  • [10] Utilitaires endurcis / PAX
  • [11] Pax-Utils, package Debian
Remerciements

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