Linux 检查二进制文件是否使用“编译”-“静态”;

Linux 检查二进制文件是否使用“编译”-“静态”;,linux,gcc,static,Linux,Gcc,Static,我在linux中有一个二进制文件。如何检查它是否使用“-static”编译 ldd/path/to/binary如果二进制文件是静态编译的,则不应列出任何共享库。您也可以使用file命令(并且objdump也可能有用)。检查它是否有INTERP类型的程序头 在较低级别,如果可执行文件没有with类型,则该可执行文件是静态的: Elf32_Phd.p_type == PT_INTERP 这在报告中提到 请记住,程序头决定了将加载到内存并运行的类型,包括PT_LOAD 如果该标头存在,则其内容正好

我在linux中有一个二进制文件。如何检查它是否使用“-static”编译

ldd/path/to/binary
如果二进制文件是静态编译的,则不应列出任何共享库。

您也可以使用
file
命令(并且
objdump
也可能有用)。

检查它是否有
INTERP
类型的程序头

在较低级别,如果可执行文件没有with类型,则该可执行文件是静态的:

Elf32_Phd.p_type == PT_INTERP
这在报告中提到

请记住,程序头决定了将加载到内存并运行的类型,包括
PT_LOAD

如果该标头存在,则其内容正好是动态加载程序的路径

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
,这是动态加载程序的路径(对于
\0
,27字节长+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.
如下文所述:

文件
源代码

文件
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";
通过消息
main.out中的
git grep静态
找到:ELF 64位LSB可执行文件,x86-64,版本1(SYSV),静态链接,未剥离

但是,与代码相比,此注释似乎已经过时,而代码会检查
PT\u DYNAMIC

    case PT_DYNAMIC:
        linking_style = "dynamically";
        doread = 1;
        break;
我不知道为什么要这样做,我现在懒得深入研究
git日志。特别是,当我试图用
——无动态链接器
创建一个静态链接的饼图可执行文件时,这让我有点困惑,如所示:它没有
PT_INTERP
,但有
PT_dynamic
,并且我不希望使用动态加载程序

最后,我对
-fPIE
进行了更深入的源代码分析:答案很可能也在那里

Linux内核源代码

Linux内核5.0在的exec系统调用期间读取ELF文件,如下所述:

内核在程序头上循环

for(i=0;ielf_ex.e_phnum;i++){
如果(elf\U ppnt->p\U type==PT\U INTP){
/*这是程序解释器,用于
*共享库-现在假设
*是a.out格式的二进制文件
*/
我还没有完全阅读代码,但我希望它只在找到
INTERP
时使用动态加载程序,否则应该使用哪个路径

PT_DYNAMIC
未在该文件中使用

奖金:检查是否使用了
-pie

我已在以下网站详细解释了这一点:

    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
             */