![如何测试 Linux 二进制文件是否被编译为位置无关代码?](https://linux22.com/image/49880/%E5%A6%82%E4%BD%95%E6%B5%8B%E8%AF%95%20Linux%20%E4%BA%8C%E8%BF%9B%E5%88%B6%E6%96%87%E4%BB%B6%E6%98%AF%E5%90%A6%E8%A2%AB%E7%BC%96%E8%AF%91%E4%B8%BA%E4%BD%8D%E7%BD%AE%E6%97%A0%E5%85%B3%E4%BB%A3%E7%A0%81%EF%BC%9F.png)
我最近了解到(至少在 Fedora 和 Red Hat Enterprise Linux 上),编译为位置独立可执行文件(PIE)的可执行程序会获得更强的地址空间随机化(ASLR)保护。
那么:如何在 Linux 上测试特定可执行文件是否被编译为位置无关可执行文件?
答案1
您可以使用包perl
中包含的脚本hardening-check
,在 Fedora 中可用和德班(作为hardening-includes
)。读这个Debian 维基页面有关检查哪些编译标志的详细信息。它是 Debian 特有的,但该理论也适用于 Red Hat。
例子:
$ hardening-check $(which sshd)
/usr/sbin/sshd:
Position Independent Executable: yes
Stack protected: yes
Fortify Source functions: yes (some protected functions found)
Read-only relocations: yes
Immediate binding: yes
答案2
file
只需在二进制文件上使用:
$ file ./pie-off
./pie-off: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=0dc3858e9f0334060bfebcbe3e854909191d8bdc, not stripped
$ file ./pie-on
./pie-on: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=962235df5bd188e1ec48c151ff61b6435d395f89, not stripped
请注意 LSB 信息后打印的不同类型。
答案3
file
5.36说得很清楚
file
5.36 实际上清楚地打印出可执行文件是否是 PIE。例如,PIE 可执行文件显示为:
main.out: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, not stripped
和一个非 PIE 为:
main.out: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, not stripped
该功能是在 5.33 中引入的,但它只是做了一个简单的chmod +x
检查。在此之前它只是shared object
为 PIE 打印。
在 5.34 中,它本来是要开始检查更专门的DF_1_PIE
ELF 元数据,但由于实现中的错误,它实际上破坏了一些东西,并将 GCC PIE 可执行文件显示为shared objects
.
我已经解释了file
源代码,包括错误,以及它检查的 ELF 格式的确切字节,详细信息如下:https://stackoverflow.com/questions/34519521/why-does-gcc-create-a-shared-object-instead-of-an-executable-binary-according-to/55704865#55704865
文件 5.36 行为的快速总结是:
- 如果
Elf32_Ehdr.e_type == ET_EXEC
- 打印
executable
- 打印
- 否则如果
Elf32_Ehdr.e_type == ET_DYN
- 如果
DT_FLAGS_1
存在动态部分条目- 如果
DF_1_PIE
设置在DT_FLAGS_1
:- 打印
pie executable
- 打印
- 别的
- 打印
shared object
- 打印
- 如果
- 别的
- 文件是否可由用户、组或其他人执行
- 打印
pie executable
- 打印
- 别的
- 打印
shared object
- 打印
- 文件是否可由用户、组或其他人执行
- 如果
GDB 运行可执行文件两次并查看 ASLR
您可以做的一件非常直接的事情是通过 GDB 运行可执行文件两次,看看地址是否因 ASLR 而在运行过程中发生变化。
我已在以下位置详细解释了如何执行此操作:https://stackoverflow.com/questions/2463150/what-is-the-fpie-option-for-position-independent-executables-in-gcc-and-ld/51308031#51308031
虽然这不一定是最实用的解决方案,并且如果您不信任可执行文件也是不可能的,但它很有趣,并且它执行了我们真正关心的最终检查,即 Linux 内核/动态加载器是否更改了可执行文件位置或不是。
答案4
有bash脚本Github 上的 checksec.sh检查可执行文件缓解属性(包括 RELRO、Stack Canary、NX 位、PIE、RPATH、RUNPATH、Fortify Source)。
checksec
使用-f
(文件输入)参数运行:
$ checksec -f /usr/bin/bash
RELRO STACK CANARY NX PIE RPATH RUNPATH FORTIFY Fortified Fortifiable
Full RELRO Canary found NX enabled PIE enabled No RPATH No RUNPATH YES 13 33