Comprender el formato de archivo ELF

Comprender el formato de archivo ELF

Del código fuente al código binario

La programación comienza con tener una idea inteligente y escribir código fuente en un lenguaje de programación de su elección, por ejemplo C, y guardar el código fuente en un archivo. Con la ayuda de un compilador adecuado, por ejemplo, GCC, su código fuente se traduce en código de objeto, primero. Finalmente, el enlazador traduce el código de objeto en un archivo binario que vincula el código de objeto con las bibliotecas referenciadas. Este archivo contiene las instrucciones únicas como código de máquina que entiende la CPU, y se ejecutan tan pronto como se ejecuta el programa compilado.

El archivo binario mencionado anteriormente sigue una estructura específica, y uno de los más comunes se llama ELF que abrevia el formato ejecutable y vinculable. Se usa ampliamente para archivos ejecutables, archivos de objetos reubicables, bibliotecas compartidas y volcados de núcleo.

Hace veinte años, en 1999, el Proyecto 86Open ha elegido ELF como el formato de archivo binario estándar para sistemas similares a UNIX y UNIX en procesadores X86. Afortunadamente, el formato ELF se había documentado previamente tanto en la interfaz binaria del sistema v como en el estándar de la interfaz de herramienta [4]. Este hecho simplificó enormemente el acuerdo sobre la estandarización entre los diferentes proveedores y desarrolladores de sistemas operativos basados ​​en UNIX.

La razón detrás de esa decisión fue el diseño de ELF: flexibilidad, extensibilidad y soporte multiplataforma para diferentes formatos de Endian y tamaños de dirección. El diseño de ELF no se limita a un procesador, conjunto de instrucciones o arquitectura de hardware específicas. Para una comparación detallada de formatos de archivo ejecutables, eche un vistazo aquí [3].

Desde entonces, el formato ELF está en uso por varios sistemas operativos diferentes. Entre otros, esto incluye Linux, Solaris/Illumos, Free, Net y OpenBSD, QNX, Beos/Haiku y Fuchsia OS [2]. Además, lo encontrará en dispositivos móviles que ejecutan Android, Maemo o Meego OS/Sailfish OS, así como en consolas de juegos como PlayStation Portable, Dreamcast y Wii.

La especificación no aclara la extensión del nombre de archivo para archivos ELF. En uso hay una variedad de combinaciones de letras, como .hacha, .papelera, .duende, .O, .prx, .soplo, .KO, .y entonces .mod, o ninguno.

La estructura de un archivo ELF

En un terminal de Linux, el Man Man de comandos le brinda un resumen útil sobre la estructura de un archivo ELF:

Listado 1: La página de manejo de la estructura de elfos

$ hombre elfo
ELF (5) Manual de programador de Linux Elf (5)
NOMBRE
ELF - Formato de archivos ejecutables y de formato de enlace (ELF)
SINOPSIS
#incluir
DESCRIPCIÓN
El archivo de encabezado define el formato de ELF ejecutable binario
archivos. Entre estos archivos hay archivos ejecutables normales, reubicables
Archivos de objetos, archivos principales y bibliotecas compartidas.
Un archivo ejecutable que usa el formato de archivo ELF consiste en un encabezado ELF,
seguido de una tabla de encabezado del programa o una tabla de encabezado de sección, o ambos.
El encabezado ELF siempre está en desplazamiento cero del archivo. El programa
La tabla de encabezado y la compensación de la tabla de encabezado de sección en el archivo son
definido en el encabezado de elfo. Las dos tablas describen el resto del
particularidades del archivo.

Como puede ver en la descripción anterior, un archivo ELF consta de dos secciones: un encabezado ELF y datos de archivo. La sección de datos del archivo puede consistir en una tabla de encabezado del programa que describe cero o más segmentos, una tabla de encabezado de sección que describe cero o más secciones, que es seguido por los datos mencionados por las entradas desde la tabla de encabezado del programa y la tabla de encabezado de sección. Cada segmento contiene información que es necesaria para la ejecución en tiempo de ejecución del archivo, mientras que las secciones contienen datos importantes para vincular y reubicar. La Figura 1 ilustra este esquemáticamente.

El encabezado elfo

El encabezado ELF tiene 32 bytes de largo e identifica el formato del archivo. Comienza con una secuencia de cuatro bytes únicos que son 0x7f seguidos de 0x45, 0x4c y 0x46 que se traduce en las tres letras E, L y F. Entre otros valores, el encabezado también indica si se trata de un archivo ELF para formato de 32 o 64 bits, utiliza poca o gran endianness, muestra la versión ELF y para el cual se compiló el sistema operativo para interpererar con el Interfaz binaria de aplicación correcta (ABI) y Conjunto de instrucciones de CPU.

El hexdump del archivo binario se ve de la siguiente manera:

.Listado 2: el hexdump del archivo binario

$ HD/usr/bin/touch | Cabeza -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 ofrece el comando Readelf que se proporciona en el paquete de GNU 'binutils'. Acompañado por el switch -h (versión corta para "-file-header") Muestra muy bien el encabezado de un archivo ELF. El listado 3 ilustra esto para el toque de comando.

.Listado 3: Mostrar el encabezado de un archivo ELF

$ readelf -h/usr/bin/touch
Encabezado de elfo:
Magic: 7F 45 4C 46 02 01 01 00 00 00 00 00 00 00 00 00
Clase: Elf64
Datos: Complemento de 2, Little Endian
Versión: 1 (actual)
OS/ABI: UNIX - Sistema V
Versión ABI: 0
Tipo: EXEC (archivo ejecutable)
Máquina: dispositivos micro avanzados x86-64
Versión: 0x1
Dirección del punto de entrada: 0x4025e3
Inicio de los encabezados del programa: 64 (bytes en el archivo)
Inicio de los encabezados de la sección: 58408 (bytes en el archivo)
Banderas: 0x0
Tamaño de este encabezado: 64 (bytes)
Tamaño de los encabezados del programa: 56 (bytes)
Número de encabezados del programa: 9
Tamaño de los encabezados de sección: 64 (bytes)
Número de encabezados de sección: 27
Sección del índice de tabla de cadena de encabezado: 26

El encabezado del programa

El encabezado del programa muestra los segmentos utilizados en tiempo de ejecución y le dice al sistema cómo crear una imagen de proceso. El encabezado del Listado 2 muestra que el archivo ELF consta de 9 encabezados del programa que tienen un tamaño de 56 bytes cada uno, y el primer encabezado comienza en Byte 64.

Nuevamente, el comando Readelf ayuda a extraer la información del archivo ELF. El interruptor -l (abreviatura de -program -headers o -segments) revela más detalles como se muestra en el Listado 4.

.Listado 4: Mostrar información sobre los encabezados del programa

$ readelf -l/usr/bin/touch
El tipo de archivo ELF es EXEC (archivo ejecutable)
Punto de entrada 0x4025e3
Hay 9 encabezados del programa, comenzando en el desplazamiento 64
Encabezados del programa:
Escriba compensación virtaddr Physaddr
Alineación de banderas de MEMSIZ de filesiz
PHDR 0x000000000000000040 0x0000000000400040 0x0000000000400040
0x0000000000000001F8 0x00000000000001F8 R E 8
Interp 0x000000000000000238 0x0000000000400238 0x0000000000400238
0x00000000000000001C 0x000000000000001C R 1
[Solicitar intérprete del programa: /lib64 /ld-linux-x86-64.entonces.2]
Carga 0x000000000000000000 0x0000000000400000 0x0000000000400000
0x00000000000000D494 0x00000000000000D494 R E 200000
Carga 0x00000000000000DE10 0x000000000060DE10 0x000000000060DE10
0x0000000000000524 0x0000000000000748 RW 200000
Dinámica 0x00000000000000DE28 0x000000000060DE28 0x000000000060DE28
0x00000000000001D0 0X00000000000001D0 RW 8
Nota 0x0000000000000254 0x0000000000400254 0x0000000000400254
0x000000000000000044 0x0000000000000044 R 4
Gnu_eh_frame 0x00000000000000BC40 0x000000000040BC40 0x000000000040BC40
0x0000000000000003A4 0x0000000000000003A4 R 4
Gnu_stack 0x0000000000000000 0x0000000000000000 0x000000000000000000
0x000000000000000000 0x000000000000000000 RW 10
Gnu_relro 0x00000000000000de10 0x000000000060de10 0x00000000000060DE10
0x00000000000001F0 0x00000000000001F0 R 1
Mapeo de sección a segmento:
Secciones de segmento ..
00
01 .interp
02 .interp .nota.Trapis .nota.ñu.idiota .ñu.picadillo .dinsym .dinstruco .ñu.versión .ñu.versión_r .rela.dinina .rela.PLT .en eso .PLT .texto .fini .Rodata .eh_frame_hdr .eh_frame
03 .init_array .fini_array .JCR .dinámica .consiguió .consiguió.PLT .datos .BSS
04 .dinámica
05 .nota.Trapis .nota.ñu.idiota
06 .eh_frame_hdr
07
08 .init_array .fini_array .JCR .dinámica .consiguió

El encabezado de la sección

La tercera parte de la estructura de elfo es el encabezado de sección. Está destinado a enumerar las secciones únicas del binario. El interruptor -s (abreviatura de -sesion -headers o -sections) enumera los diferentes encabezados. En cuanto al comando touch, hay 27 encabezados de sección, y el listado 5 muestra los primeros cuatro más el último, solo. Cada línea cubre el tamaño de la sección, el tipo de sección, así como su dirección y compensación de memoria.

.Listado 5: Detalles de la sección revelados por Readelf

$ readelf -s/usr/bin/touch
Hay 27 encabezados de sección, comenzando en el desplazamiento 0xe428:
Encabezados de sección:
[NR] Tipo de nombre Compensación de dirección
Size entsize Flags Enlace Información de información
[0] nulo 000000000000000000 00000000
000000000000000000 000000000000000000 0 0 0
[1] .Interp Progbits 000000000000400238 00000238
00000000000000001C 000000000000000000 A 0 0 1
[2] .nota.Nota de Tag ABI 0000000000400254 00000254
000000000000000020 000000000000000000 A 0 0 4
[3] .nota.ñu.Build-I Note 000000000000400274 00000274


[26] .shstrtab strtab 000000000000000000 0000E334
0000000000000000EF 000000000000000000 0 0 1
Clave de las banderas:
W (Write), A (Alloc), X (Ejecutar), M (Fusion), S (Strings), L (grande)
I (Info), L (orden de enlace), G (grupo), T (TLS), E (excluido), X (desconocido)
O (requerido procesamiento adicional del sistema operativo) o (SO específico), P (procesador específico)

Herramientas para analizar un archivo ELF

Como puede haber señalado en los ejemplos anteriores, GNU/Linux se desarrolla con una serie de herramientas útiles que lo ayudan a analizar un archivo ELF. El primer candidato que veremos es la utilidad de los archivos.

El archivo muestra información básica sobre los archivos ELF, incluida la arquitectura del conjunto de instrucciones para la cual está previsto el código en un archivo de objeto reubicable, ejecutable o compartido. En el Listado 6 le indica que/bin/touch es un archivo ejecutable de 64 bits que sigue a la base estándar de Linux (LSB), vinculada dinámicamente y creada para la versión 2 de Kernel GNU/Linux.6.32.

.Listado 6: Información básica utilizando el archivo

$ archivo /bin /touch
/bin/touch: ELF Ejecutable LSB de 64 bits, x86-64, versión 1 (SYSV), vinculado dinámicamente, intérprete/lib64/l,
para GNU/Linux 2.6.32, BuildID [SHA1] = EC08D609E9E8E73D4BE6134541A472Ad0EA34502, despojado
ps

El segundo candidato es el lectura. Muestra información detallada sobre un archivo ELF. La lista de interruptores es comparablemente larga y cubre todos los aspectos del formato Elfo. Usando el Listado 7 -N (abreviatura de -notes), muestra las secciones de nota, solo que existen en el archivo touch: la etiqueta de versión ABI y la bitstring de ID de compilación.

.Listado 7: Muestra secciones seleccionadas de un archivo ELF

$ readelf -n/usr/bin/touch
Mostrar notas encontradas en el compensación del archivo 0x00000254 con longitud 0x00000020:
Descripción del tamaño de datos del propietario
GNU 0x00000010 NT_GNU_ABI_TAG (etiqueta de versión ABI)
OS: Linux, ABI: 2.6.32
Mostrar notas encontradas en el compensación del archivo 0x00000274 con longitud 0x00000024:
Descripción del tamaño de datos del propietario
GNU 0x0000000014 NT_GNU_BUILD_ID (bitstring de ID de compilación único)
ID de compilación: EC08D609E9E8E73D4BE6134541A472Ad0EA34502

Tenga en cuenta que bajo Solaris y FreeBSD, la utilidad Elfdump [7] se corresponde con Readelf. A partir de 2019, no ha habido una nueva versión o actualización desde 2003.

El número tres es el paquete llamado Elfutils [6] que está puramente disponible para Linux. Proporciona herramientas alternativas para los binutilos GNU, y también permite validar archivos ELF. Tenga en cuenta que todos los nombres de las utilidades proporcionadas en el paquete comienzan con la UE para 'Elf Utils'.

Por último, pero no menos importante, mencionaremos Objdump. Esta herramienta es similar a la lectura pero se enfoca en archivos de objetos. Proporciona una gama similar de información sobre los archivos ELF y otros formatos de objetos.

.Listado 8: Información del archivo extraída por OBJDUMP

$ objdump -f /bin /touch
/bin/touch: formato de archivo ELF64-X86-64
Arquitectura: i386: x86-64, banderas 0x00000112:
Exec_p, has_syms, d_paged
Dirección de inicio 0x0000000000004025E3
ps

También hay un paquete de software llamado 'Elfkickers' [9] que contiene herramientas para leer el contenido de un archivo ELF, así como manipularlo. Desafortunadamente, el número de lanzamientos es bastante bajo, y es por eso que lo mencionamos y no mostramos más ejemplos.

Como desarrollador, puede echar un vistazo a 'Pax-Utils' [10,11], en su lugar. Este conjunto de utilidades proporciona una serie de herramientas que ayudan a validar los archivos ELF. Como ejemplo, Dumpelf analiza el archivo ELF y devuelve un archivo de encabezado C que contiene los detalles; consulte la Figura 2.

Conclusión

Gracias a una combinación de diseño inteligente y excelente documentación, el formato de elfo funciona muy bien, y todavía está en uso después de 20 años. Las utilidades que se muestran arriba le permiten una vista de información sobre un archivo ELF y le permiten averiguar qué está haciendo un programa. Estos son los primeros pasos para analizar el software: Happy Hacking!

Enlaces y referencias
  • [1] Formato ejecutable y vinculable (ELF), Wikipedia
  • [2] FUCHSIA OS
  • [3] Comparación de formatos de archivo ejecutables, Wikipedia
  • [4] Fundación Linux, especificaciones referenciadas
  • [5] Ciro Santilli: Elf Hello World Tutorial
  • [6] Paquete de elfutils Debian
  • [7] Elfdump
  • [8] Michael Boelen: El 101 de los archivos ELF en Linux: comprensión y análisis
  • [9] Elfkickers
  • [10] Utilidades endurecidos/pax
  • [11] Pax-Utils, paquete Debian
Agradecimientos

El escritor desea agradecer a Axel Beckert por su apoyo con respecto a la preparación de este artículo.