Introduction aux ELF Linux: Comprendre et analyser

Il y a des choses dans le monde que nous tenons pour acquises, même si ce sont de véritables chefs-d'œuvre. Une telle chose est les utilitaires Linux tels que ls et ps. Bien qu'ils soient généralement perçus comme simples, c'est loin d'être le cas si l'on regarde à l'intérieur. Il en va de même pour ELF, Executable et Linkable Format. Un format de fichier utilisé universellement, mais peu le comprennent. Ce guide rapide vous aidera à comprendre.



Après avoir lu ce guide, vous apprendrez:

  • Pourquoi le format ELF est-il nécessaire et pour quels types de fichiers est-il utilisé
  • Structure du fichier ELF et détails du format
  • Comment lire et analyser le contenu binaire d'un fichier ELF
  • Quels outils sont utilisés pour analyser les fichiers binaires?

Qu'est-ce qu'un fichier ELF?


ELF signifie Executable and Linkable Format et définit la structure des fichiers binaires, des bibliothèques et des fichiers de base. La spécification de format permet au système d'exploitation d'interpréter correctement les instructions de la machine contenues dans le fichier. Un fichier ELF est généralement le fichier de sortie d'un compilateur ou d'un éditeur de liens et a un format binaire. À l'aide d'outils adaptés, il peut être analysé et étudié.

Pourquoi étudier ELF en détail?


Avant de plonger dans les détails techniques, il ne sera pas inutile d'expliquer pourquoi la compréhension du format ELF est utile. Tout d'abord, il vous permet d'étudier le fonctionnement interne du système d'exploitation. En cas de problème, cette connaissance vous aidera à mieux comprendre ce qui s'est exactement passé et pour quelle raison. En outre, la possibilité d'examiner les fichiers ELF peut être utile pour trouver des failles de sécurité et détecter les fichiers suspects. Et enfin, pour une meilleure compréhension du processus de développement. Même si vous programmez dans un langage de haut niveau comme Go, vous saurez toujours mieux ce qui se passe dans les coulisses.

Alors pourquoi étudier ELF?

  • Pour une compréhension générale du système d'exploitation
  • Pour le développement de logiciels
  • Digital Forensics and Incident Response (DFIR)
  • Recherche de logiciels malveillants (analyse binaire)

De la source au processus


Quel que soit le système d'exploitation que nous utilisons, il est nécessaire de traduire en quelque sorte les fonctions du code source en langage CPU - code machine. Les fonctions peuvent être les plus élémentaires, par exemple, ouvrir un fichier sur le disque ou afficher quelque chose à l'écran. Au lieu d'utiliser directement le langage CPU, nous utilisons un langage de programmation doté de fonctionnalités standard. Le compilateur traduit ensuite ces fonctions en code objet. Ce code objet est ensuite lié dans le programme complet, à l'aide de l'éditeur de liens. Le résultat est un fichier binaire qui peut être exécuté sur une plate-forme spécifique et un type spécifique de CPU.

Avant de commencer


Ce message contient de nombreuses équipes. Il est préférable de les exécuter sur une machine de test. Copiez les fichiers binaires existants avant d'exécuter ces commandes dessus. Nous écrirons également un petit programme C que vous pourrez compiler. En fin de compte, la pratique est la meilleure façon d'apprendre quelque chose.

Anatomie d'un fichier ELF


Une idée fausse commune est que les fichiers ELF sont uniquement pour les fichiers binaires ou exécutables. Nous avons déjà dit qu'ils peuvent être utilisés pour des parties de fichiers exécutables (code objet). Un autre exemple est les fichiers de bibliothèque et les vidages de mémoire (fichiers de base et fichiers a.out). La spécification ELF est également utilisée sous Linux pour le noyau et les modules du noyau.



La structure


En raison de l'extensibilité des fichiers ELF, la structure peut varier pour différents fichiers. Le fichier ELF comprend:

  1. En-tête ELF
  2. les données

Avec la commande readelf, nous pouvons regarder la structure du fichier, et cela ressemblera à ceci:



En-tête ELF


Comme vous pouvez le voir sur la capture d'écran, l'en-tête ELF commence par un «nombre magique». Ce "nombre magique" donne des informations sur le fichier. Les 4 premiers octets déterminent qu'il s'agit d'un fichier ELF (45 = E, 4c = L, 46 = F, ils sont précédés de 7f).

L'en-tête ELF est requis. Il est nécessaire pour que les données soient correctement interprétées lors de la liaison et de l'exécution. Pour une meilleure compréhension du fonctionnement interne d'un fichier ELF, il est utile de savoir à quoi servent ces informations.

Classe


Après avoir déclaré un type ELF, un champ de classe suit. Cette valeur signifie l'architecture à laquelle le fichier est destiné. Il peut être 01 (architecture 32 bits) ou 02 (64 bits). Ici, nous voyons 02, qui est traduit par la commande readelf comme un fichier ELF64, c'est-à-dire que ce fichier utilise une architecture 64 bits. Ce n'est pas surprenant, un processeur moderne est installé dans ma voiture.

Les données


Vient ensuite le champ «data», qui a deux options: 01 - LSB (Least Significant Bit), également connu sous le nom de little-endian, ou 02 - MSB (Most Significant Bit, big-endian). Ces valeurs aident à interpréter le reste des objets du fichier. Ceci est important car différents types de processeurs gèrent différemment les structures de données. Dans notre cas, LSB est utilisé, car le processeur a une architecture AMD64.

L'effet LSB devient visible lors de l'utilisation de l'utilitaire hexdump sur un fichier binaire. Voyons l'en-tête ELF pour / bin / ps.

$ hexdump -n 16 /bin/ps 0000000 457f 464c 0102 0001 0000 0000 0000 0000 0000010 

Nous voyons que les paires de valeurs sont différentes, en raison de l'interprétation de l'ordre des données.

La version


Suit ensuite une autre valeur magique "01", qui est le numéro de version. Seule la version 01 est actuellement disponible, donc ce nombre ne signifie rien d'intéressant.

OS / ABI


Chaque système d'exploitation a sa propre façon d'appeler les fonctions, ils ont beaucoup en commun, mais en plus, chaque système a de petites différences. L'ordre de l'appel de fonction est déterminé par l'interface binaire d'application (ABI). Les champs OS / ABI décrivent l'ABI utilisé et sa version. Dans notre cas, la valeur est 00, ce qui signifie que des extensions spécifiques ne sont pas utilisées. Dans la sortie, cela est indiqué comme système V.

Version ABI


Si nécessaire, une version ABI peut être indiquée.

Voiture


Le titre indique également le type de machine attendu (AMD64).

Tapez


Le champ type indique à quoi sert le fichier. Voici quelques types de fichiers courants.

CORE (valeur 4)
DYN (fichier objet partagé), bibliothèque (valeur 3)
EXEC (fichier exécutable), fichier exécutable (valeur 2)
REL (fichier réadressable), fichier avant la liaison (valeur 1)

Voir le titre complet


Bien que certains champs puissent être consultés en lecture seule, il y en a en fait plus. Par exemple, vous pouvez savoir à quel processeur le fichier est destiné. Utilisez hexdump pour voir l'en-tête ELF complet et toutes les valeurs.

 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 |.ELF............| 02 00 3e 00 01 00 00 00 a8 2b 40 00 00 00 00 00 |..>......+@.....| 40 00 00 00 00 00 00 00 30 65 01 00 00 00 00 00 |@.......0e......| 00 00 00 00 40 00 38 00 09 00 40 00 1c 00 1b 00 |....@.8...@.....| 

(sortie hexdump -C -n 64 / bin / ps)

Le champ en surbrillance détermine le type de machine. La valeur 3e est décimale 62, ce qui correspond à AMD64. Pour avoir une idée de tous les types de fichiers, consultez ce fichier d'en-tête.

Bien que vous puissiez faire tout cela dans un vidage hexadécimal, il est logique d'utiliser un outil qui fait le travail pour vous. L'utilitaire dumpelf peut être utile. Il affiche une sortie formatée correspondant à l'en-tête ELF. Il sera bon d'étudier quels champs sont utilisés et quelles sont leurs valeurs typiques.

Maintenant, où nous avons expliqué la signification de ces champs, il est temps de regarder ce qu'est la vraie magie derrière eux et de passer aux rubriques suivantes!

Données de fichier


En plus de l'en-tête, les fichiers ELF se composent de trois parties.

  • En-têtes ou segments de programme
  • Section ou en-têtes de section
  • Les données

Avant de plonger dans ces en-têtes, il serait utile de savoir que le fichier ELF a deux «types» différents. L'un d'eux est conçu pour l'éditeur de liens et permet l'exécution de code (segments). L'autre concerne les commandes et les données (sections). Selon l'objectif, le type d'en-tête approprié est utilisé. Commençons par l'en-tête du programme, qui se trouve dans les fichiers exécutables ELF.

Titres de programme


Un fichier ELF se compose de zéro ou plusieurs segments et décrit comment créer un processus, une image mémoire pour l'exécution au moment de l'exécution. Lorsque le noyau voit ces segments, il les place dans l'espace d'adressage virtuel à l'aide de l'appel système mmap (2). En d'autres termes, il convertit des instructions pré-préparées en une image en mémoire. Si le fichier ELF est un binaire normal, il nécessite ces en-têtes de programme, sinon il ne fonctionnera tout simplement pas. Ces en-têtes sont utilisés, avec les structures de données correspondantes, pour former le processus. Pour les bibliothèques partagées, le processus est similaire.


En-tête de programme dans un fichier ELF binaire

Nous voyons 9 titres de programme dans cet exemple. Au début, il est difficile de comprendre ce qu'ils signifient. Plongeons-nous dans les détails.

GNU_EH_FRAME


Il s'agit de la file d'attente triée utilisée par le compilateur GCC. Il stocke les gestionnaires d'exceptions. En cas de problème, ils sont utilisés pour gérer correctement la situation.

GNU_STACK


Cet en-tête est utilisé pour enregistrer les informations de pile. Une caractéristique intéressante est que la pile n'a pas besoin d'être exécutable, car cela pourrait entraîner des failles de sécurité.

Si le segment GNU_STACK est manquant, la pile exécutable est utilisée. Les utilitaires scanelf et execstack affichent les détails du périphérique de pile.

 # scanelf -e /bin/ps TYPE STK/REL/PTL FILE ET_EXEC RW- R-- RW- /bin/ps # execstack -q /bin/ps - /bin/ps 

Commandes pour afficher l'en-tête du programme:

  • dumpelf (pax-utils)
  • elfls -S / bin / ps
  • eu-readelf - en-têtes de programme / bin / ps

Sections ELF


En-têtes de section


Les en-têtes de section définissent toutes les sections d'un fichier. Comme déjà mentionné, ces informations sont utilisées pour la liaison et la relocalisation.

Les sections apparaissent dans un fichier ELF après que le compilateur GNU C convertit le code C en assembleur et que l'assembleur GNU crée des objets.

Comme le montre la figure ci-dessus, un segment peut avoir 0 ou plusieurs sections. Il existe quatre sections principales pour les fichiers exécutables: .text, .data, .rodata et .bss. Chacune de ces sections démarre avec des autorisations différentes, qui peuvent être affichées avec readelf -S.

.text


Contient du code exécutable. Il sera conditionné dans un segment avec des droits de lecture et d'exécution. Il est téléchargé une fois et son contenu ne change pas. Cela peut être vu avec l'utilitaire objdump.

 12 .text 0000a3e9 0000000000402120 0000000000402120 00002120 2**4 CONTENTS, ALLOC, LOAD, READONLY, CODE 

.data


Données initialisées avec des autorisations de lecture et d'écriture.

.rodata


Données initialisées avec des autorisations en lecture seule. (= A).

.bss


Données non initialisées avec des autorisations de lecture / écriture. (= WA)

 [24] .data PROGBITS 00000000006172e0 000172e0 0000000000000100 0000000000000000 WA 0 0 8 [25] .bss NOBITS 00000000006173e0 000173e0 0000000000021110 0000000000000000 WA 0 0 32 


Commandes pour afficher les sections et les titres.

  • dumpelf
  • elfls -p / bin / ps
  • eu-readelf –section-headers / bin / ps
  • readelf -S / bin / ps
  • objdump -h / bin / ps

Groupes de sections


Certaines sections peuvent être regroupées comme si elles formaient un seul ensemble. De nouveaux éditeurs de liens prennent en charge cette fonctionnalité. Mais alors que ce n'est pas courant.

 # readelf -g /bin/ps There are no section groups in this file. 

Bien que cela ne semble pas très intéressant, la connaissance des outils d'analyse de fichiers ELF offre de grands avantages. Pour cette raison, un aperçu de ces outils et de leur fonction est donné à la fin de l'article.

Binaires statiques et dynamiques


Lorsqu'il s'agit de fichiers binaires ELF, il sera utile de savoir comment ces deux types de fichiers sont liés. Ils peuvent être statiques et dynamiques, et cela s'applique aux bibliothèques qu'ils utilisent. Si le binaire est «dynamique», cela signifie qu'il utilise des bibliothèques externes qui contiennent certaines fonctions communes, telles que l'ouverture d'un fichier ou la création d'une socket réseau. Les binaires statiques, en revanche, incluent toutes les bibliothèques nécessaires.

Si vous souhaitez vérifier si le fichier est statique ou dynamique, utilisez la commande file. Elle montrera quelque chose comme ceci:

 $ file /bin/ps /bin/ps: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), <b>dynamically linked (uses shared libs)</b>, for GNU/Linux 2.6.24, BuildID[sha1]=2053194ca4ee8754c695f5a7a7cff2fb8fdd297e, stripped 

Pour déterminer quelles bibliothèques externes sont utilisées, utilisez simplement ldd sur le même binaire:

 $ ldd /bin/ps linux-vdso.so.1 => (0x00007ffe5ef0d000) libprocps.so.3 => /lib/x86_64-linux-gnu/libprocps.so.3 (0x00007f8959711000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f895934c000) /lib64/ld-linux-x86-64.so.2 (0x00007f8959935000) 

Conseil: Pour voir d'autres dépendances, il est préférable d'utiliser l'utilitaire lddtree.

Outils d'analyse binaire


Si vous souhaitez analyser des fichiers ELF, il sera certainement utile de regarder d'abord les outils existants. Il existe des boîtes à outils pour le développement inverse des binaires et du code exécutable. Si vous débutez dans l'analyse des fichiers ELF, commencez par l'analyse statique. L'analyse statique implique que nous examinions les fichiers sans les démarrer. Lorsque vous commencez à mieux comprendre leur travail, passez à l'analyse dynamique. Exécutez les exemples et examinez leur comportement réel.

Outils populaires


Radare2


La boîte à outils Radare2 a été créée par Sergi Alvarez. Le chiffre 2 implique que le code a été complètement réécrit par rapport à la première version. Maintenant, il est utilisé par de nombreux chercheurs pour étudier le fonctionnement du code.

Logiciels


La plupart des systèmes Linux ont des binutils installés. D'autres packages peuvent vous aider à voir plus d'informations. La boîte à outils appropriée simplifiera votre travail, surtout si vous analysez des fichiers ELF. J'ai compilé ici une liste de packages et d'utilitaires pour l'analyse des fichiers ELF.

elfutils
/ usr / bin / eu-addr2line
/ usr / bin / eu-ar - une alternative à ar, pour créer et traiter des fichiers d'archives
/ usr / bin / eu-elfcmp
/ usr / bin / eu-elflint - vérifier la conformité aux spécifications gABI et psABI
/ usr / bin / eu-findtextrel - recherche de délocalisations de texte
/ usr / bin / eu-ld - combine les fichiers objet et archive
/ usr / bin / eu-make-debug-archive
/ usr / bin / eu-nm - affiche les symboles de l'objet et des fichiers exécutables
/ usr / bin / eu-objdump - affiche les informations du fichier objet
/ usr / bin / eu-ranlib - crée un index des fichiers d'archive
/ usr / bin / eu-readelf - affiche le fichier ELF sous une forme lisible
/ usr / bin / eu-size - affiche la taille de chaque section (texte, données, bss, etc.)
/ usr / bin / eu-stack - affiche la pile du processus en cours ou le vidage du noyau
/ usr / bin / eu-strings - affiche les chaînes de texte (comme l'utilitaire strings)
/ usr / bin / eu-strip - supprime la table des caractères du fichier ELF
/ usr / bin / eu-unstrip - ajoute des symboles et des informations de débogage au binaire
Remarque: le paquet elfutils sera un bon début, il contient la plupart des outils d'analyse

elfkickers
/ usr / bin / ebfc - compilateur de langage Brainfuck
/ usr / bin / elfls - affiche les en-têtes de programme et les en-têtes de section avec des drapeaux
/ usr / bin / elftoc - convertit un binaire en programme C
/ usr / bin / infect - un utilitaire injectant un compte-gouttes crée un fichier setuid dans / tmp
/ usr / bin / objres - crée un objet à partir de données régulières ou binaires
/ usr / bin / rebind - modifie la liaison et la visibilité des caractères dans les fichiers ELF
/ usr / bin / sstrip - supprime les composants inutiles d'un fichier ELF
Remarque: l'auteur du package ELFKickers se concentre sur la manipulation des fichiers ELF, ce qui vous permet d'obtenir plus d'informations lorsque vous travaillez avec les «mauvais» binaires ELF

pax-utils
/ usr / bin / dumpelf - vidage de la structure ELF interne
/ usr / bin / lddtree - comme ldd, avec la définition du niveau des dépendances affiché
/ usr / bin / pspax - affiche des informations ELF / PaX sur les processus en cours d'exécution
/ usr / bin / scanelf - un large éventail d'informations, y compris les détails PaX
/ usr / bin / scanmacho - affiche les détails des binaires Mach-O (Mac OS X)
/ usr / bin / symtree - affiche les caractères d'arbre
Remarque: certains utilitaires de ce package peuvent analyser récursivement les répertoires et sont idéaux pour analyser l'intégralité du contenu d'un répertoire. L'accent est mis sur les outils de recherche PaX. En plus de prendre en charge ELF, vous pouvez extraire des informations des fichiers binaires Mach-O.

Exemple de sortie
 scanelf -a /bin/ps TYPE PAX PERM ENDIAN STK/REL/PTL TEXTREL RPATH BIND FILE ET_EXEC PeMRxS 0755 LE RW- R-- RW- - - LAZY /bin/ps 


prelink
/ usr / bin / execstack - vous pouvez afficher ou modifier des informations pour savoir si la pile est exécutable
/ usr / bin / prelink - déplace les appels dans les fichiers ELF pour accélérer le processus

Foire aux questions


Qu'est-ce qu'un ABI?


ABI est l'interface binaire d'application et définit une interface de bas niveau entre le système d'exploitation et le code exécutable.

Qu'est-ce que ELF?


ELF est un format exécutable et liable. Il s'agit d'une spécification de format qui définit comment les instructions sont écrites dans du code exécutable.

Comment puis-je voir le type de fichier?


Utilisez la commande file pour la première étape de l'analyse. Cette commande est capable d'afficher les détails extraits des numéros et des titres "magiques".

Conclusion


Les fichiers ELF sont destinés à l'exécution et à la liaison. Selon le but, ils contiennent les segments et sections nécessaires. Le noyau du système d'exploitation analyse les segments et les mappe en mémoire (à l'aide de mmap). Les sections sont affichées par un éditeur de liens qui crée un fichier exécutable ou un objet partagé.

Les fichiers ELF sont très flexibles et prennent en charge différents types de CPU, d'architectures de machine et de systèmes d'exploitation. Il est également extensible, chaque fichier est conçu différemment, en fonction des pièces requises. En utilisant les bons outils, vous pouvez comprendre le but du fichier et examiner le contenu des fichiers binaires. Vous pouvez afficher les fonctions et les lignes contenues dans le fichier. Un bon début pour ceux qui recherchent des logiciels malveillants, ou pour comprendre pourquoi le processus se comporte (ou non) d'une certaine manière.

Ressources pour une étude plus approfondie


Si vous voulez en savoir plus sur ELF et la rétro-ingénierie, vous pouvez voir le travail que nous faisons dans Linux Security Expert. Dans le cadre du programme, nous avons un module de rétro-ingénierie avec des travaux pratiques en laboratoire.

Pour ceux d'entre vous qui aiment lire, un bon et profond document: ELF Format et un article rédigé par Brian Raiter, également connu sous le nom d'ELFkickers. Pour ceux qui aiment comprendre la source, consultez l'en- tête ELF documenté d'Apple.

Astuce:
Si vous souhaitez améliorer l'analyse des fichiers, commencez à utiliser les outils d'analyse populaires actuellement disponibles.

Source: https://habr.com/ru/post/fr480642/


All Articles