GNU/Linux >> Tutoriales Linux >  >> Linux

¿Puede un programa leer su propia sección elf?

¿Cómo puedo imprimir la versión de compilación del programa (que se encuentra en la sección .note.gnu.build-id elf) desde el propio programa?

  1. Tienes que leer el ElfW(Ehdr) (al principio del archivo) para encontrar encabezados de programa en su binario (.e_phoff y .e_phnum le dirá dónde están los encabezados del programa y cuántos de ellos leer).

  2. Luego lee los encabezados del programa, hasta que encuentre PT_NOTE segmento de su programa. Ese segmento le indicará el desplazamiento al comienzo de todas las notas en su binario.

  3. A continuación, debe leer el ElfW(Nhdr) y omita el resto de la nota (el tamaño total de la nota es sizeof(Nhdr) + .n_namesz + .n_descsz , correctamente alineado), hasta que encuentre una nota con .n_type == NT_GNU_BUILD_ID .

  4. Una vez que encuentres NT_GNU_BUILD_ID nota, pase por alto su .n_namesz y lea el .n_descsz bytes para leer el ID de compilación real.

Puede verificar que está leyendo los datos correctos comparando lo que lee con el resultado de readelf -n a.out .

PD

Si se va a tomar la molestia de decodificar el ID de compilación como se indicó anteriormente, y si su ejecutable no está eliminado, puede ser mejor para usted simplemente decodificar e imprimir símbolo nombres en su lugar (es decir, para replicar lo que backtrace_symbols hace):en realidad es más fácil de hacer que decodificar notas ELF, porque la tabla de símbolos contiene entradas de tamaño fijo.


Básicamente, este es el código que he escrito basado en la respuesta dada a mi pregunta. Para compilar el código tuve que hacer algunos cambios y espero que funcione para tantos tipos de plataformas como sea posible. Sin embargo, se probó solo en una máquina de construcción. Una de las suposiciones que usé fue que el programa se creó en la máquina que lo ejecuta, por lo que no tiene sentido verificar la compatibilidad de endianness entre el programa y la máquina.

[email protected]:~/$ uname -s -r -m -o
Linux 3.2.0-45-generic x86_64 GNU/Linux
[email protected]:~/$ g++ test.cpp -o test
[email protected]:~/$ readelf -n test | grep Build
    Build ID: dc5c4682e0282e2bd8bc2d3b61cfe35826aa34fc
[email protected]:~/$ ./test
    Build ID: dc5c4682e0282e2bd8bc2d3b61cfe35826aa34fc
#include <elf.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>

#if __x86_64__
#  define ElfW(type) Elf64_##type
#else
#  define ElfW(type) Elf32_##type
#endif

/*
detecting build id of a program from its note section
http://stackoverflow.com/questions/17637745/can-a-program-read-its-own-elf-section
http://www.scs.stanford.edu/histar/src/pkg/uclibc/utils/readelf.c
http://www.sco.com/developers/gabi/2000-07-17/ch5.pheader.html#note_section
*/

int main (int argc, char* argv[])
{
  char *thefilename = argv[0];
  FILE *thefile;
  struct stat statbuf;
  ElfW(Ehdr) *ehdr = 0;
  ElfW(Phdr) *phdr = 0;
  ElfW(Nhdr) *nhdr = 0;
  if (!(thefile = fopen(thefilename, "r"))) {
    perror(thefilename);
    exit(EXIT_FAILURE);
  }
  if (fstat(fileno(thefile), &statbuf) < 0) {
    perror(thefilename);
    exit(EXIT_FAILURE);
  }
  ehdr = (ElfW(Ehdr) *)mmap(0, statbuf.st_size, 
    PROT_READ|PROT_WRITE, MAP_PRIVATE, fileno(thefile), 0);
  phdr = (ElfW(Phdr) *)(ehdr->e_phoff + (size_t)ehdr);
  while (phdr->p_type != PT_NOTE)
  {
    ++phdr;
  }
  nhdr = (ElfW(Nhdr) *)(phdr->p_offset + (size_t)ehdr); 
  while (nhdr->n_type != NT_GNU_BUILD_ID)
  {
    nhdr = (ElfW(Nhdr) *)((size_t)nhdr + sizeof(ElfW(Nhdr)) + nhdr->n_namesz + nhdr->n_descsz);
  }
  unsigned char * build_id = (unsigned char *)malloc(nhdr->n_descsz);
  memcpy(build_id, (void *)((size_t)nhdr + sizeof(ElfW(Nhdr)) + nhdr->n_namesz), nhdr->n_descsz);
  printf("    Build ID: ");
  for (int i = 0 ; i < nhdr->n_descsz ; ++i)
  {
    printf("%02x",build_id[i]);
  }
  free(build_id);
  printf("\n");
  return 0;
}

Linux
  1. ¿Puede Bash escribir en su propio flujo de entrada?

  2. ¿Encontrar archivos que un usuario no puede leer?

  3. ¿Puede un script ser ejecutable pero no legible?

  4. ¿Cómo es que cada programa o servicio tiene una cuenta propia en /etc/passwd?

  5. Encabezados de archivos ELF

¿Puede leer (2) devolver cero cuando no está en EOF?

Herramienta para modificar la sección dinámica de un binario ELF

¿Cómo iniciar un proceso en su propio grupo de procesos?

¿Cómo puedo hacer que R lea mis variables ambientales?

¿Cómo puede una biblioteca compartida (.so) llamar a una función que está implementada en su programa de carga?

¿Qué puede causar una señal 11?