GNU/Linux >> Tutoriales Linux >  >> Linux

comprobando si un binario compilado con -static

También puedes usar el file comando (y objdump también podría ser útil).


Comprueba si tiene un encabezado de programa de tipo INTERP

En el nivel inferior, un ejecutable es estático si no tiene un encabezado de programa con el tipo:

Elf32_Phd.p_type == PT_INTERP

Esto se menciona en la especificación System V ABI.

Recuerde que los encabezados de programa determinan los segmentos ELF, incluidos los de tipo PT_LOAD que se cargará en la memoria y se ejecutará.

Si ese encabezado está presente, su contenido es exactamente la ruta del cargador dinámico.

readelf comprobar

Podemos observar esto con readelf . Primero compila dinámicamente un C hello world:

gcc -o main.out main.c

y luego:

readelf --program-headers --wide main.out

salidas:

Elf file type is DYN (Shared object file)
Entry point 0x1050
There are 11 program headers, starting at offset 64

Program Headers:
  Type           Offset   VirtAddr           PhysAddr           FileSiz  MemSiz   Flg Align
  PHDR           0x000040 0x0000000000000040 0x0000000000000040 0x000268 0x000268 R   0x8
  INTERP         0x0002a8 0x00000000000002a8 0x00000000000002a8 0x00001c 0x00001c R   0x1
      [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
  LOAD           0x000000 0x0000000000000000 0x0000000000000000 0x000560 0x000560 R   0x1000
  LOAD           0x001000 0x0000000000001000 0x0000000000001000 0x0001bd 0x0001bd R E 0x1000
  LOAD           0x002000 0x0000000000002000 0x0000000000002000 0x000150 0x000150 R   0x1000
  LOAD           0x002db8 0x0000000000003db8 0x0000000000003db8 0x000258 0x000260 RW  0x1000
  DYNAMIC        0x002dc8 0x0000000000003dc8 0x0000000000003dc8 0x0001f0 0x0001f0 RW  0x8
  NOTE           0x0002c4 0x00000000000002c4 0x00000000000002c4 0x000044 0x000044 R   0x4
  GNU_EH_FRAME   0x00200c 0x000000000000200c 0x000000000000200c 0x00003c 0x00003c R   0x4
  GNU_STACK      0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW  0x10
  GNU_RELRO      0x002db8 0x0000000000003db8 0x0000000000003db8 0x000248 0x000248 R   0x1

 Section to Segment mapping:
  Segment Sections...
   00
   01     .interp
   02     .interp .note.ABI-tag .note.gnu.build-id .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt
   03     .init .plt .plt.got .text .fini
   04     .rodata .eh_frame_hdr .eh_frame
   05     .init_array .fini_array .dynamic .got .data .bss
   06     .dynamic
   07     .note.ABI-tag .note.gnu.build-id
   08     .eh_frame_hdr
   09
   10     .init_array .fini_array .dynamic .got

así que tenga en cuenta el INTERP el encabezado está ahí, y es muy importante que readelf incluso dio una vista previa rápida de su contenido corto de 28 (0x1c) bytes:/lib64/ld-linux-x86-64.so.2 , que es la ruta al cargador dinámico (27 bytes de largo + 1 para \0 ).

Tenga en cuenta cómo esto reside al lado de los otros segmentos, incluidos, p. aquellos que realmente se cargan en la memoria, como:.text .

Entonces podemos extraer más directamente esos bytes sin la vista previa con:

readelf -x .interp main.out

que da:

Hex dump of section '.interp':
  0x000002a8 2f6c6962 36342f6c 642d6c69 6e75782d /lib64/ld-linux-
  0x000002b8 7838362d 36342e73 6f2e3200          x86-64.so.2.

como se explica en:¿Cómo puedo examinar el contenido de una sección de datos de un archivo ELF en Linux?

file código fuente

file Los comentarios del código fuente 5.36 en src/readelf.c afirman que también comprueba PT_INTERP :

/*
 * Look through the program headers of an executable image, searching
 * for a PT_INTERP section; if one is found, it's dynamically linked,
 * otherwise it's statically linked.
 */
private int
dophn_exec(struct magic_set *ms, int clazz, int swap, int fd, off_t off,
    int num, size_t size, off_t fsize, int sh_num, int *flags,
    uint16_t *notecount)
{
    Elf32_Phdr ph32;
    Elf64_Phdr ph64;
    const char *linking_style = "statically";

encontrado con git grep statically del mensaje main.out: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, not stripped .

Sin embargo, este comentario parece estar desactualizado en comparación con el código, que en su lugar busca PT_DYNAMIC :

    case PT_DYNAMIC:
        linking_style = "dynamically";
        doread = 1;
        break;

No estoy seguro de por qué se hace esto, y me da pereza profundizar en git log ahora. En particular, esto me confundió un poco cuando traté de hacer un ejecutable PIE enlazado estáticamente con --no-dynamic-linker como se muestra en:¿Cómo crear un ELF ejecutable independiente de posición enlazada estáticamente en Linux? que no tiene PT_INTERP pero tiene PT_DYNAMIC , y que no espero usar el cargador dinámico.

Terminé haciendo un análisis de fuente más profundo para -fPIE at:¿Por qué GCC crea un objeto compartido en lugar de un binario ejecutable según el archivo? es probable que la respuesta también esté ahí.

Código fuente del kernel de Linux

El kernel de Linux 5.0 lee el archivo ELF durante la llamada del sistema exec en fs/binfmt_elf.c como se explica en:¿Cómo obtiene el kernel un archivo binario ejecutable que se ejecuta en Linux?

El kernel recorre los encabezados del programa en load_elf_binary

    for (i = 0; i < loc->elf_ex.e_phnum; i++) {
        if (elf_ppnt->p_type == PT_INTERP) {
            /* This is the program interpreter used for
             * shared libraries - for now assume that this
             * is an a.out format binary
             */

No he leído el código por completo, pero esperaría que solo use el cargador dinámico si INTERP se encuentra, de lo contrario, ¿qué ruta debería usar?

PT_DYNAMIC no se usa en ese archivo.

Bonificación:comprueba si -pie fue usado

Lo expliqué en detalle en:¿Por qué GCC crea un objeto compartido en lugar de un archivo binario ejecutable según el archivo?


ldd /path/to/binary no debe enumerar ninguna biblioteca compartida si el binario se compila estáticamente.


Linux
  1. ¿No se puede compilar el programa simple de subprocesos de C++?

  2. Comprobación del tamaño del directorio con du Command en Linux

  3. Subir archivos como ASCII o binario con FTP

  4. llamar a una función cuando el programa haya terminado con ctrl c

  5. Mi gestor de arranque no se puede compilar con gcc 4.6 y 4.7 ... solo 4.5

Cómo programar con Bash:Sintaxis y herramientas

Bash For Loop con ejemplos prácticos

Administre máquinas virtuales KVM con el programa Virsh

Cómo actualizar un programa instalado con Softaculous

convertir una cadena hexadecimal a binario y enviar con netcat

¿Cómo configuro monit para iniciar un proceso con un usuario específico?