Bagaimana cara mencetak versi build program (terletak di bagian .note.gnu.build-id elf) dari program itu sendiri?
-
Anda perlu membaca
ElfW(Ehdr)
(di awal file) untuk menemukan header program di biner Anda (.e_phoff
dan.e_phnum
akan memberi tahu Anda di mana letak tajuk program, dan berapa banyak yang harus dibaca). -
Anda kemudian membaca header program, sampai Anda menemukan
PT_NOTE
segmen program Anda. Segmen itu akan memberi tahu Anda offset ke awal semua nada dalam biner Anda. -
Anda kemudian perlu membaca
ElfW(Nhdr)
dan lewati sisa catatan (ukuran total catatan adalahsizeof(Nhdr) + .n_namesz + .n_descsz
, disejajarkan dengan benar), hingga Anda menemukan catatan dengan.n_type == NT_GNU_BUILD_ID
. -
Setelah Anda menemukan
NT_GNU_BUILD_ID
perhatikan, lewati.n_namesz
nya , dan baca.n_descsz
byte untuk membaca build-id yang sebenarnya.
Anda dapat memverifikasi bahwa Anda membaca data yang benar dengan membandingkan apa yang Anda baca dengan keluaran readelf -n a.out
.
P.S.
Jika Anda akan mengalami kesulitan untuk mendekode build-id seperti di atas, dan jika executable Anda tidak dilucuti, mungkin lebih baik bagi Anda untuk mendekode dan mencetak simbol nama sebagai gantinya (yaitu untuk mereplikasi apa backtrace_symbols
tidak) -- ini sebenarnya lebih mudah dilakukan daripada mendekode catatan ELF, karena tabel simbol berisi entri berukuran tetap.
Pada dasarnya, ini adalah kode yang saya tulis berdasarkan jawaban yang diberikan untuk pertanyaan saya. Untuk mengkompilasi kode saya harus membuat beberapa perubahan dan saya harap ini akan berfungsi untuk sebanyak mungkin jenis platform. Namun, itu diuji hanya pada satu mesin build. Salah satu asumsi yang saya gunakan adalah bahwa program dibuat di atas mesin yang menjalankannya sehingga tidak ada gunanya memeriksa kompatibilitas endianness antara program dan mesin.
[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;
}