GNU/Linux >> Belajar Linux >  >> Linux

memeriksa apakah biner dikompilasi dengan -statis

Anda juga dapat menggunakan file perintah (dan objdump juga bisa berguna).


Periksa apakah memiliki header program dengan jenis INTERP

Di tingkat yang lebih rendah, sebuah executable bersifat statis jika tidak memiliki header program dengan tipe:

Elf32_Phd.p_type == PT_INTERP

Hal ini disebutkan dalam spesifikasi System V ABI.

Ingat bahwa header program menentukan segmen ELF, termasuk tipe PT_LOAD yang akan dimuat ke memori dan dijalankan.

Jika tajuk itu ada, isinya persis seperti jalur pemuat dinamis.

readelf periksa

Kita dapat mengamati ini dengan readelf . Pertama, kompilasi C hello world secara dinamis:

gcc -o main.out main.c

lalu:

readelf --program-headers --wide main.out

keluaran:

Elf file type is DYN (Shared object file)
Entry point 0x1050
There are 11 program headers, starting at offset 64

Program Headers:
  Type           Offset   VirtAddr           PhysAddr           FileSiz  MemSiz   Flg Align
  PHDR           0x000040 0x0000000000000040 0x0000000000000040 0x000268 0x000268 R   0x8
  INTERP         0x0002a8 0x00000000000002a8 0x00000000000002a8 0x00001c 0x00001c R   0x1
      [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
  LOAD           0x000000 0x0000000000000000 0x0000000000000000 0x000560 0x000560 R   0x1000
  LOAD           0x001000 0x0000000000001000 0x0000000000001000 0x0001bd 0x0001bd R E 0x1000
  LOAD           0x002000 0x0000000000002000 0x0000000000002000 0x000150 0x000150 R   0x1000
  LOAD           0x002db8 0x0000000000003db8 0x0000000000003db8 0x000258 0x000260 RW  0x1000
  DYNAMIC        0x002dc8 0x0000000000003dc8 0x0000000000003dc8 0x0001f0 0x0001f0 RW  0x8
  NOTE           0x0002c4 0x00000000000002c4 0x00000000000002c4 0x000044 0x000044 R   0x4
  GNU_EH_FRAME   0x00200c 0x000000000000200c 0x000000000000200c 0x00003c 0x00003c R   0x4
  GNU_STACK      0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW  0x10
  GNU_RELRO      0x002db8 0x0000000000003db8 0x0000000000003db8 0x000248 0x000248 R   0x1

 Section to Segment mapping:
  Segment Sections...
   00
   01     .interp
   02     .interp .note.ABI-tag .note.gnu.build-id .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt
   03     .init .plt .plt.got .text .fini
   04     .rodata .eh_frame_hdr .eh_frame
   05     .init_array .fini_array .dynamic .got .data .bss
   06     .dynamic
   07     .note.ABI-tag .note.gnu.build-id
   08     .eh_frame_hdr
   09
   10     .init_array .fini_array .dynamic .got

jadi perhatikan INTERP header ada di sana, dan sangat penting bahwa readelf bahkan memberikan pratinjau cepat dari konten pendek 28 (0x1c) byte:/lib64/ld-linux-x86-64.so.2 , yang merupakan jalur ke pemuat dinamis (panjang 27 byte + 1 untuk \0 ).

Perhatikan bagaimana ini berada berdampingan dengan segmen lainnya, termasuk mis. yang benar-benar dimuat ke dalam memori seperti:.text .

Kami kemudian dapat lebih langsung mengekstrak byte tersebut tanpa pratinjau dengan:

readelf -x .interp main.out

yang memberikan:

Hex dump of section '.interp':
  0x000002a8 2f6c6962 36342f6c 642d6c69 6e75782d /lib64/ld-linux-
  0x000002b8 7838362d 36342e73 6f2e3200          x86-64.so.2.

seperti yang dijelaskan di:Bagaimana cara memeriksa konten bagian data file ELF di Linux?

file kode sumber

file 5.36 komentar kode sumber di src/readelf.c mengklaim bahwa ia juga memeriksa PT_INTERP :

/*
 * Look through the program headers of an executable image, searching
 * for a PT_INTERP section; if one is found, it's dynamically linked,
 * otherwise it's statically linked.
 */
private int
dophn_exec(struct magic_set *ms, int clazz, int swap, int fd, off_t off,
    int num, size_t size, off_t fsize, int sh_num, int *flags,
    uint16_t *notecount)
{
    Elf32_Phdr ph32;
    Elf64_Phdr ph64;
    const char *linking_style = "statically";

ditemukan dengan git grep statically dari pesan main.out: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, not stripped .

Namun, komentar ini tampaknya sudah usang dibandingkan dengan kodenya, yang justru memeriksa PT_DYNAMIC :

    case PT_DYNAMIC:
        linking_style = "dynamically";
        doread = 1;
        break;

Saya tidak yakin mengapa ini dilakukan, dan saya malas menggali git log sekarang. Secara khusus, ini sedikit membingungkan saya ketika saya mencoba membuat PIE yang terhubung secara statis dapat dieksekusi dengan --no-dynamic-linker seperti yang ditunjukkan di:Bagaimana cara membuat ELF yang dapat dieksekusi independen dengan posisi yang terhubung secara statis di Linux? yang tidak memiliki PT_INTERP tetapi memiliki PT_DYNAMIC , dan yang saya tidak harapkan untuk menggunakan pemuat dinamis.

Saya akhirnya melakukan analisis sumber yang lebih dalam untuk -fPIE di:Mengapa GCC membuat objek bersama alih-alih biner yang dapat dieksekusi menurut file? jawabannya mungkin ada juga.

Kode sumber kernel Linux

Kernel Linux 5.0 membaca file ELF selama panggilan sistem exec di fs/binfmt_elf.c seperti yang dijelaskan di:Bagaimana cara kernel menjalankan file biner yang dapat dieksekusi di linux?

Kernel mengulang header program di load_elf_binary

    for (i = 0; i < loc->elf_ex.e_phnum; i++) {
        if (elf_ppnt->p_type == PT_INTERP) {
            /* This is the program interpreter used for
             * shared libraries - for now assume that this
             * is an a.out format binary
             */

Saya belum membaca kode sepenuhnya, tetapi saya berharap kode itu hanya menggunakan pemuat dinamis jika INTERP ditemukan, jika tidak jalur mana yang harus digunakan?

PT_DYNAMIC tidak digunakan dalam file itu.

Bonus:periksa apakah -pie digunakan

Saya telah menjelaskannya secara mendetail di:Mengapa GCC membuat objek bersama alih-alih biner yang dapat dieksekusi menurut file?


ldd /path/to/binary tidak boleh mencantumkan perpustakaan bersama apa pun jika biner dikompilasi secara statis.


Linux
  1. Menambal Biner Dengan Dd?

  2. Menjalankan Program Dengan Berbagai Parameter (loop)?

  3. Memeriksa Ukuran Direktori dengan du Command di Linux

  1. Unggah file sebagai ASCII atau biner dengan FTP

  2. Cara Membuat Thread di Linux (Dengan Program Contoh C)

  3. memanggil fungsi ketika program selesai dengan ctrl c

  1. Bootloader saya tidak dapat dikompilasi dengan gcc 4.6 dan 4.7 ... hanya 4.5

  2. program lynx gagal dengan 'Tidak dapat mengakses file awal'?

  3. Linux:tutup program dengan baris perintah (bukan matikan)