GNU/Linux >> LINUX-Kenntnisse >  >> Linux

kann ein programm seinen eigenen elfabschnitt lesen?

Wie kann ich die Build-Version des Programms (im Abschnitt .note.gnu.build-id elf) aus dem Programm selbst ausdrucken?

  1. Sie müssen den ElfW(Ehdr) lesen (am Anfang der Datei), um Programmheader in Ihrer Binärdatei zu finden (.e_phoff und .e_phnum wird Ihnen sagen, wo Programmkopfzeilen sind und wie viele davon zu lesen sind).

  2. Dann lesen Sie Programmkopfzeilen, bis Sie PT_NOTE finden Abschnitt Ihres Programms. Dieses Segment teilt Ihnen mit, dass alle Noten in Ihrer Binärdatei an den Anfang versetzt sind.

  3. Sie müssen dann den ElfW(Nhdr) lesen und überspringe den Rest der Notiz (Gesamtgröße der Notiz ist sizeof(Nhdr) + .n_namesz + .n_descsz , richtig ausgerichtet), bis Sie eine Notiz mit .n_type == NT_GNU_BUILD_ID finden .

  4. Sobald Sie NT_GNU_BUILD_ID gefunden haben Beachten Sie, überspringen Sie den .n_namesz , und lesen Sie die .n_descsz Bytes, um die tatsächliche Build-ID zu lesen.

Sie können überprüfen, ob Sie die richtigen Daten lesen, indem Sie das Gelesene mit der Ausgabe von readelf -n a.out vergleichen .

P.S.

Wenn Sie sich die Mühe machen, build-id wie oben zu entschlüsseln, und if Ihre ausführbare Datei wird nicht entfernt, es ist möglicherweise besser für Sie, Symbol einfach zu decodieren und zu drucken Namen statt (d. h. um zu replizieren, was backtrace_symbols tut) -- es ist eigentlich einfacher als das Decodieren von ELF-Noten, weil die Symboltabelle Einträge mit fester Größe enthält.


Grundsätzlich ist dies der Code, den ich basierend auf der Antwort auf meine Frage geschrieben habe. Um den Code zu kompilieren, musste ich einige Änderungen vornehmen und ich hoffe, dass er für so viele Arten von Plattformen wie möglich funktioniert. Es wurde jedoch nur auf einer Build-Maschine getestet. Eine der Annahmen, die ich verwendet habe, war, dass das Programm auf der Maschine erstellt wurde, auf der es läuft, also hat es keinen Sinn, die Endianness-Kompatibilität zwischen dem Programm und der Maschine zu überprüfen.

[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. Kann Bash in seinen eigenen Eingabestrom schreiben?

  2. Dateien finden, die ein Benutzer nicht lesen kann?

  3. Kann ein Skript ausführbar, aber nicht lesbar sein?

  4. Wie erkennt ein Hintergrundprozess seine eigene Pid?

  5. Kann Strace/ptrace ein Programm zum Absturz bringen?

Wie kommt es, dass jedes Programm oder jeder Dienst ein eigenes Konto in /etc/passwd hat?

Wie starte ich einen Prozess in einer eigenen Prozessgruppe?

Wie kann ich R dazu bringen, meine Umgebungsvariablen zu lesen?

Wie kann eine gemeinsam genutzte Bibliothek (.so) eine Funktion aufrufen, die in ihrem Ladeprogramm implementiert ist?

Was kann ein Signal 11 verursachen?

Sekundäre IP in einem eigenen netns-Namespace