Wie kann ich die Build-Version des Programms (im Abschnitt .note.gnu.build-id elf) aus dem Programm selbst ausdrucken?
-
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). -
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. -
Sie müssen dann den
ElfW(Nhdr)
lesen und überspringe den Rest der Notiz (Gesamtgröße der Notiz istsizeof(Nhdr) + .n_namesz + .n_descsz
, richtig ausgerichtet), bis Sie eine Notiz mit.n_type == NT_GNU_BUILD_ID
finden . -
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;
}