Cir*_*四事件 10
检查它是否具有类型的程序头 INTERP
在较低级别,如果可执行文件没有以下类型的程序头,则它是静态的:
Elf32_Phd.p_type == PT_INTERP
Run Code Online (Sandbox Code Playgroud)
System V ABI 规范中提到了这一点。
请记住,程序头确定ELF 段,包括PT_LOAD将加载到内存中并运行的类型。
如果该标头存在,则其内容正是动态加载器的路径。
readelf 查看
我们可以观察到这一点readelf。首先动态编译一个C hello world:
gcc -o main.out main.c
Run Code Online (Sandbox Code Playgroud)
进而:
readelf --program-headers --wide main.out
Run Code Online (Sandbox Code Playgroud)
输出:
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
Run Code Online (Sandbox Code Playgroud)
所以请注意INTERP标头在那里,它非常重要,readelf甚至可以快速预览其短的 28 (0x1c) 字节内容:/lib64/ld-linux-x86-64.so.2,这是动态加载程序的路径(27 字节长 + 1 for \0)。
注意如何驻留并排与其他部分,例如包括那些实际加载到内存中,如:.text。
然后我们可以更直接地提取这些字节而无需预览:
readelf -x .interp main.out
Run Code Online (Sandbox Code Playgroud)
这使:
Hex dump of section '.interp':
0x000002a8 2f6c6962 36342f6c 642d6c69 6e75782d /lib64/ld-linux-
0x000002b8 7838362d 36342e73 6f2e3200 x86-64.so.2.
Run Code Online (Sandbox Code Playgroud)
如在:如何在 Linux 上检查 ELF 文件的数据部分的内容?
file 源代码
filesrc/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";
Run Code Online (Sandbox Code Playgroud)
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;
Run Code Online (Sandbox Code Playgroud)
我不确定为什么要这样做,我现在懒得深入研究git log。特别是,当我尝试制作静态链接的 PIE 可执行文件时,这让我有点困惑,--no-dynamic-linker如下所示:如何在 Linux 中创建静态链接的位置无关的可执行文件 ELF?哪个没有PT_INTERP但确实有PT_DYNAMIC,我不希望使用动态加载器。
我最终对-fPIEat进行了更深入的源代码分析:为什么 GCC 根据文件创建共享对象而不是可执行二进制文件?答案很可能也在那里。
Linux内核源代码
Linux 内核 5.0 在fs/binfmt_elf.c处的 exec 系统调用期间读取 ELF 文件,如以下所述:内核如何获取在 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
*/
Run Code Online (Sandbox Code Playgroud)
我还没有完全阅读代码,但我希望它只使用动态加载器如果INTERP找到,否则它应该使用哪个路径?
PT_DYNAMIC 未在该文件中使用。
奖励:检查是否-pie被使用
我已经详细解释过:为什么 GCC 根据文件创建共享对象而不是可执行二进制文件?
| 归档时间: |
|
| 查看次数: |
7457 次 |
| 最近记录: |