GNU/Linux >> Tutoriels Linux >  >> Linux

un programme peut-il lire sa propre section elf ?

Comment puis-je imprimer la version de construction du programme (située dans la section .note.gnu.build-id elf) à partir du programme lui-même ?

  1. Vous devez lire le ElfW(Ehdr) (au début du fichier) pour trouver les en-têtes de programme dans votre binaire (.e_phoff et .e_phnum vous indiquera où se trouvent les en-têtes de programme et combien d'entre eux doivent être lus).

  2. Vous lisez ensuite les en-têtes de programme, jusqu'à ce que vous trouviez PT_NOTE partie de votre programme. Ce segment vous indiquera le décalage par rapport au début de toutes les notes de votre binaire.

  3. Vous devez ensuite lire le ElfW(Nhdr) et ignorez le reste de la note (la taille totale de la note est de sizeof(Nhdr) + .n_namesz + .n_descsz , correctement aligné), jusqu'à ce que vous trouviez une note avec .n_type == NT_GNU_BUILD_ID .

  4. Une fois que vous avez trouvé NT_GNU_BUILD_ID note, sautez son .n_namesz , et lisez le .n_descsz octets pour lire le build-id réel.

Vous pouvez vérifier que vous lisez les bonnes données en comparant ce que vous lisez avec la sortie de readelf -n a.out .

PS

Si vous allez avoir du mal à décoder build-id comme ci-dessus, et if votre exécutable n'est pas dépouillé, il peut être préférable pour vous de simplement décoder et imprimer le symbole noms à la place (c'est-à-dire pour répliquer ce que backtrace_symbols fait) - c'est en fait plus facile à faire que de décoder les notes ELF, car la table des symboles contient des entrées de taille fixe.


Fondamentalement, c'est le code que j'ai écrit en fonction de la réponse donnée à ma question. Afin de compiler le code, j'ai dû apporter quelques modifications et j'espère que cela fonctionnera pour autant de types de plates-formes que possible. Cependant, il n'a été testé que sur une seule machine de construction. L'une des hypothèses que j'ai utilisées était que le programme était construit sur la machine qui l'exécute, donc inutile de vérifier la compatibilité de l'endianness entre le programme et la machine.

[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. Un script peut-il être exécutable mais pas lisible ?

  2. Comment se fait-il que chaque programme ou service ait son propre compte dans /etc/passwd ?

  3. Strace/ptrace peut-il provoquer le plantage d'un programme ?

  4. Ajout d'une section au fichier ELF

  5. read(2) peut-il renvoyer zéro lorsqu'il n'est pas à EOF ?

Comment un processus d'arrière-plan connaît-il son propre pid ?

En-têtes de fichiers ELF

Un exécutable peut-il découvrir son propre chemin ? (Linux)

Comment faire en sorte que R lise mes variables d'environnement ?

Qu'est-ce qui peut provoquer la génération de SIGHUP ?

Qu'est-ce qui peut provoquer un signal 11 ?