GNU/Linux >> Linux の 問題 >  >> Linux

-static でコンパイルされたバイナリかどうかを確認する

file も使用できます コマンド (および objdump も役立つ可能性があります)。


タイプ INTERP のプログラム ヘッダーがあるかどうかを確認します

下位レベルでは、次のタイプのプログラム ヘッダーがない場合、実行可能ファイルは静的です:

Elf32_Phd.p_type == PT_INTERP

これは、System V ABI 仕様に記載されています。

タイプ PT_LOAD の ELF セグメントを含む、プログラム ヘッダーが ELF セグメントを決定することに注意してください。 メモリに読み込まれて実行されます。

そのヘッダーが存在する場合、その内容は正確にダイナミック ローダーのパスです。

readelf チェック

これは readelf で観察できます .最初に C の hello world を動的にコンパイルします:

gcc -o main.out main.c

次に:

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

出力:

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

INTERP に注意してください ヘッダーがあり、readelf が非常に重要です その短い 28 (0x1c) バイトの内容のクイック プレビューも表示されます:/lib64/ld-linux-x86-64.so.2 、これは動的ローダーへのパスです (長さ 27 バイト + \0 の場合は 1) ).

これが他のセグメントとどのように並んでいるかに注意してください。実際にメモリにロードされるもの:.text .

次に、プレビューなしでこれらのバイトをより直接的に抽出できます:

readelf -x .interp main.out

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

説明:Linux で ELF ファイルのデータ セクションの内容を調べるにはどうすればよいですか?

file ソースコード

file src/readelf.c の 5.36 ソース コード コメントは、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";

git grep statically で見つかりました メッセージ main.out: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, not stripped から .

ただし、このコメントは、代わりに PT_DYNAMIC をチェックするコードに比べて古くなっているようです。 :

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

なぜこれが行われるのかわかりません。 git log を掘り下げるのが面倒です 今。特に、静的にリンクされた PIE 実行可能ファイルを --no-dynamic-linker で作成しようとしたとき、これは少し混乱しました。 に示されているように:Linux で静的にリンクされた位置に依存しない実行可能 ELF を作成する方法は? PT_INTERP を持たない PT_DYNAMIC があります であり、ダイナミック ローダーを使用する予定はありません。

-fPIE のより深いソース分析を行うことになりました at:GCC がファイルに従って実行可能なバイナリではなく、共有オブジェクトを作成するのはなぜですか?答えもおそらくそこにあります。

Linux カーネル ソース コード

Linux カーネル 5.0 は、次で説明されているように、fs/binfmt_elf.c での exec システム コール中に ELF ファイルを読み取ります:How does kernel get an executable binary file running under linux?

カーネルは 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
             */

私はコードを完全には読んでいませんが、 INTERP の場合にのみ動的ローダーを使用すると予想します そうでない場合は、どのパスを使用する必要がありますか?

PT_DYNAMIC そのファイルでは使用されていません。

ボーナス:-pie かどうかを確認してください 使用されました

詳細については、こちらで説明しました:なぜ GCC は、ファイルに従って実行可能なバイナリではなく共有オブジェクトを作成するのですか?


ldd /path/to/binary バイナリが静的にコンパイルされている場合、共有ライブラリをリストしないでください。


Linux
  1. さまざまなパラメータ(ループ)でプログラムを実行しますか?

  2. 単純なC++スレッドプログラムをコンパイルできませんか?

  3. FTPを使用してASCIIまたはバイナリとしてファイルをアップロードする

  1. Linux でスレッドを作成する方法 (C サンプル プログラムを使用)

  2. Softaculous でインストールされたプログラムをアップグレードする方法

  3. 私のブートローダーは gcc 4.6 と 4.7 でコンパイルできません ... 4.5 のみ

  1. コンパイル済みのバイナリで「rpath」を変更できますか?

  2. node-webkit のデフォルト プログラムでファイルを開く

  3. 16 進文字列をバイナリに変換し、netcat で送信します