当我在ubuntu 17.10中执行一些静态链接的二进制文件时, 其他二进制文件是可以的,但具体的一些二进制文件是问题。
gdb-peda$ x/15i 0x4000f0
0x4000f0: push 0x400105
0x4000f5: push 0x0
0x4000f7: xor rax,rax
0x4000fa: mov edx,0x10000
0x4000ff: mov rsi,rsp
0x400102: xor rdi,rdi
0x400105: syscall
0x400107: mov eax,0x1
0x40010c: mov edx,0x1000
0x400111: pop rsi
0x400112: mov edi,0x1
0x400117: syscall
0x400119: mov eax,0x3c
0x40011e: ret
所有代码都像上面那样。 如果我运行这个二进制文件,我得到以下错误声明:
root@ubuntu:/home/hitcon/Desktop# ./biglittle
Segmentation fault
我用strace跟踪它,因为这个二进制文件是静态链接的, 我明白了。
root@ubuntu:/home/hitcon/Desktop# strace -fFi ./biglittle
[00007f9eaed12fa7] execve("./biglittle", ["./biglittle"], [/* 53 vars */]) = -1 ENOMEM (Cannot allocate memory)
[00007f9eaed12fa7] --- SIGSEGV {si_signo=SIGSEGV, si_code=SI_KERNEL, si_addr=NULL} ---
[????????????????] +++ killed by SIGSEGV +++
Segmentation fault (core dumped)
有人可以给我建议解决它吗?
答案 0 :(得分:0)
我在一个特殊二进制文件上有完全相同的strace
。我们的名字不是二进制foo.elf
。
在docker 中运行时,在内核空间中运行foo.elf
segfaults *,这是在流控制到达ELF入口点之前的方式。与您显示的完全相同:execve
返回ENOMEM,然后strace
进程本身会收到带有si_code=SI_KERNEL
的奇怪SIGSEGV。
*更准确地说,不是foo.elf
进程的段错误(一个甚至从未开始运行) - 它是post-fork()父进程获取SIGSEGV。功能
但是,foo.elf
在主机系统上运行良好!
令人费解。
所以这就是我在我的案例中找到的。我的foo.elf
可执行文件是静态链接的:
⚓ file foo.elf foo.elf: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), statically linked, stripped
- 这意味着它不使用共享库(.so
)。反过来,这意味着ELF文件不会通过ld.so
程序头(也称为段)请求动态链接器INTERP
作为其解释器:
⚓ readelf --segments foo.elf
Elf file type is DYN (Shared object file)
Entry point 0x14b5b0
There are 3 program headers, starting at offset 64
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
LOAD 0x0000000000000000 0x0000000000100000 0x0000000000100000
0x000000000004bddb 0x000000000004bddb R E 10000
LOAD 0x000000000000bc18 0x00000000000fbc18 0x00000000000fbc18
0x0000000000000000 0x0000000000000000 RW 1000
GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000000 0x0000000000000000 RWE 0
- 请参阅,没有INTERP
部分。与基线动态可执行文件比较:
⚓ readelf --segments /bin/ls Elf file type is EXEC (Executable file) Entry point 0x404b48 There are 9 program headers, starting at offset 64 Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flags Align PHDR 0x0000000000000040 0x0000000000400040 0x0000000000400040 0x00000000000001f8 0x00000000000001f8 R E 8 INTERP 0x0000000000000238 0x0000000000400238 0x0000000000400238 0x000000000000001c 0x000000000000001c R 1 [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2] LOAD 0x0000000000000000 0x0000000000400000 0x0000000000400000 0x00000000000193fc 0x00000000000193fc R E 200000 LOAD 0x000000000001a328 0x000000000061a328 0x000000000061a328 0x00000000000012d8 0x0000000000001ff8 RW 200000 DYNAMIC 0x000000000001ada8 0x000000000061ada8 0x000000000061ada8 0x0000000000000200 0x0000000000000200 RW 8 NOTE 0x0000000000000254 0x0000000000400254 0x0000000000400254 0x0000000000000044 0x0000000000000044 R 4 GNU_EH_FRAME 0x0000000000016650 0x0000000000416650 0x0000000000416650 0x0000000000000744 0x0000000000000744 R 4 GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000 0x0000000000000000 0x0000000000000000 RW 10 GNU_RELRO 0x000000000001a328 0x000000000061a328 0x000000000061a328 0x0000000000000cd8 0x0000000000000cd8 R 1 Section to Segment mapping: Segment Sections... 00 01 .interp [...]
这是正确的。
......等等!这是什么?
⚓ file foo.elf foo.elf: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), statically linked, stripped
这个??
⚓ readelf --file-header foo.elf ELF Header: Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 Class: ELF64 Data: 2's complement, little endian Version: 1 (current) OS/ABI: UNIX - System V ABI Version: 0 Type: DYN (Shared object file) Machine: Advanced Micro Devices X86-64 Version: 0x1 Entry point address: 0x14b5b0 Start of program headers: 64 (bytes into file) Start of section headers: 0 (bytes into file) Flags: 0x0 Size of this header: 64 (bytes) Size of program headers: 56 (bytes) Number of program headers: 3 Size of section headers: 64 (bytes) Number of section headers: 0 Section header string table index: 0
...... Aah-huh!我们的可执行文件声称是一个共享库!
即。其ELF文件标头的e_type
字段设置为ET_DYN
(3),而不是ET_EXEC
(2)。
这有点奇怪,但通常是可以接受的:ELF格式允许双重任务二进制文件,您可以dlopen()
作为库,exec()
作为程序。动态链接器(ld.so
),我认为就是这样。
回到我的foo.elf
:它是使用-fPIE
CFLAG和-pie
链接标记生成的,稍后使用几个ELF转换工具进行后处理。 PIE代表与位置无关的可执行文件;对我而言,删除-fPIE -pie
以获取e_type == ET_EXEC
二进制文件就足够了:
foo.elf.nopie: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, stripped
这个很棒。在码头工人或其他方面没有段错误。哇哇,谜题解决了!希望这有助于那里的人:)