GNU/Linux >> Linux Esercitazione >  >> Linux

un programma può leggere la propria sezione elfo?

Come posso stampare la versione build del programma (che si trova nella sezione .note.gnu.build-id elf) dal programma stesso?

  1. Devi leggere il ElfW(Ehdr) (all'inizio del file) per trovare le intestazioni del programma nel file binario (.e_phoff e .e_phnum ti dirà dove sono le intestazioni del programma e quante di esse leggere).

  2. Quindi leggi le intestazioni del programma, finché non trovi PT_NOTE segmento del tuo programma. Quel segmento ti dirà l'offset all'inizio di tutte le note nel tuo codice binario.

  3. Devi quindi leggere il ElfW(Nhdr) e salta il resto della nota (la dimensione totale della nota è sizeof(Nhdr) + .n_namesz + .n_descsz , correttamente allineato), finché non trovi una nota con .n_type == NT_GNU_BUILD_ID .

  4. Una volta trovato NT_GNU_BUILD_ID nota, salta il suo .n_namesz e leggi il .n_descsz byte per leggere l'effettivo build-id.

Puoi verificare che stai leggendo i dati corretti confrontando ciò che leggi con l'output di readelf -n a.out .

P.S.

Se hai intenzione di affrontare il problema di decodificare build-id come sopra e if il tuo eseguibile non viene rimosso, potrebbe essere meglio per te solo decodificare e stampare simbolo nomi invece (ovvero per replicare ciò che backtrace_symbols fa) - in realtà è più facile da fare che decodificare le note ELF, perché la tabella dei simboli contiene voci di dimensioni fisse.


Fondamentalmente, questo è il codice che ho scritto in base alla risposta data alla mia domanda. Per poter compilare il codice ho dovuto apportare alcune modifiche e spero che funzioni per quanti più tipi di piattaforme possibili. Tuttavia, è stato testato solo su una macchina di compilazione. Uno dei presupposti che ho utilizzato è che il programma è stato compilato sulla macchina che lo esegue, quindi non ha senso controllare la compatibilità endian tra il programma e la macchina.

[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. Come un processo in background conosce il proprio Pid?

  2. Strace/ptrace può causare il crash di un programma?

  3. Intestazioni file ELF

  4. Un eseguibile può scoprire il proprio percorso? (Linux)

  5. Come può una libreria condivisa (.so) chiamare una funzione implementata nel suo programma di caricamento?

Come avviare un processo nel proprio gruppo di processi?

Come posso fare in modo che R legga le mie variabili ambientali?

Cosa può causare la generazione di SIGHUP?

Posso testare la mia rete?

Come leggo un singolo file in una maildir?

IP secondario nel proprio spazio dei nomi netns