如何测试Linux二进制文件是否被编译为位置无关代码?


38

我最近了解到(至少在Fedora和Red Hat Enterprise Linux上),编译为位置独立可执行文件(PIE)的可执行程序将获得更强大的地址空间随机化(ASLR)保护。

因此:如何在Linux上测试特定的可执行文件是否被编译为位置独立可执行文件?


1
不确定大约32位,但是在x86_64上,默认情况下代码是与位置无关的。当然,所有系统软件包都以这种方式在任一拱门上编译。
迈克尔·汉普顿

1
@MichaelHampton,我认为这是不对的。(请注意可执行二进制文件和共享库之间的区别;您的语句可能适用于共享库,但我认为这不适用于可执行文件。)即使在x86_64上,默认情况下二进制文件也不是PIE。我只是编写了一个小型测试程序,在x86_64上,它没有编译为PIE。我认为您必须通过-pie -fpie特殊的编译器标志才能将程序编译为PIE。不过,该链接还有其他有趣的信息-谢谢!
2013年

Answers:


32

您可以使用FedoraDebian(如)中提供perlhardening-check软件包中包含的脚本。阅读此Debian Wiki页面,了解有关检查哪些编译标志的详细信息。它特定于Debian,但该理论也适用于Red Hat。hardening-includes

例:

$ 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

很好的答案,也适用于Ubuntu 16.04 LTS和可能的其他Ubuntu版本。sudo apt-get install hardening-includes然后hardening-check可执行的perl脚本在通常的PATH/usr/bin/hardening-check)上可用;只是个建议:建议./从答案中删除;-)
Dilettant

@ a25bedc5-3d09-41b8-82fb-ea6c353d75ae不在17.10中:-(
Ciro Santilli新疆改造中心法轮功六四事件

在CentOS / RedHat中,此软件包可在epel存储库中使用
vikas027 '18

@ a25bedc5-3d09-41b8-82fb-ea6c353d75ae在Ubuntu 18.04中似乎不再可用
Vadim Kotov

2
包含它的debian软件包现在称为devscripts
塔玛斯·塞莱伊(TamásSzelei)'18

15

我曾经readelf --relocs通过以下方式测试x86-64上的静态或动态库是PIC:

$ readelf --relocs /usr/lib/gcc/x86_64-linux-gnu/4.6/libstdc++.a |\
      awk '$3~/^R_/ && $5!~/^\.debug/{print $3}' |sort -u
R_X86_64_32
R_X86_64_32S
R_X86_64_64
R_X86_64_DTPOFF32
R_X86_64_GOTPCREL
R_X86_64_PC32
R_X86_64_PLT32
R_X86_64_TLSLD
R_X86_64_TPOFF32

我们在这里看到R_X86_64_32R_X86_64_32S。这意味着代码不是位置无关的。当我使用-fPIC重建库时,得到:

$ readelf --relocs libstdc++.a |\
      awk '$3~/^R_/ && $5!~/^\.debug/{print $3}' |sort -u
R_X86_64_64
R_X86_64_DTPOFF32
R_X86_64_GOTPCREL
R_X86_64_PC32
R_X86_64_PLT32
R_X86_64_TLSGD
R_X86_64_TLSLD

此方法可能适用于可执行文件,但我没有那样使用。


8
您是否愿意解释如何解释单线输出?将共享库分为PIC和非PIC的标准是什么?
2013年

如果您使用构建了一个可执行文件-fPIE -no-pie,即使它可能已链接为PIE可执行文件,也始终会在同一地址加载该可执行文件。使用file a.out并查找ELF executable(非PIE)与ELF共享对象(PIE): x86-64 Linux中不再允许使用32位绝对地址吗?
彼得·科德斯

12

只需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信息之后打印的不同类型。


1
如果使用PIE / ASLR进行编译,该如何显示?
巴鲁克

3
pie-off和pie.on的输出之间的唯一区别是executableshared object。我认为共享对象需要可重定位,因此在我看来已经使用PIE进行了编译。
理查德·布拉甘萨

是的,PIE可执行文件是ELF共享对象。对可执行文件实施ASLR的最简单方法是使用动态链接器中的现有支持以及共享对象中的ELF入口点。另请参见x86-64 Linux中不再允许的32位绝对地址?有关控制PIE的gcc选项的更多信息,gcc -fPIE -pie现在这是许多发行版中的默认选项。
彼得·科德斯

较新版本的文件明确提到了Pie:例如ELF 64位LSB Pie可执行文件,x86-64,版本1(SYSV),动态链接,用于GNU / Linux的解释器/lib64/ld-linux-x86-64.so.2。 3.2.0,BuildID [sha1] = 9b502fd78165cb04aec34c3f046c1ba808365a96,剥离
Brian Minton

1
@PeterCordes指出,file5.36现在可以根据的DT_1_PIE标记实际识别PIE-ness DT_FLAGS_1,并明确表示pie executable而不是shared object
Ciro Santilli新疆改造中心法轮功六四事件

8

file 5.36清楚地说

file如果可执行文件为PIE,则5.36实际上清楚地打印了它。例如,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_PIEELF元数据,但是由于实现中的错误,它实际上使事情中断,并将GCC PIE可执行文件显示为shared objects

我已经解释了file源代码(包括错误),并确切地检查了ELF格式的哪些字节,并在以下网址进行了详尽的检查:https : //stackoverflow.com/questions/34519521/why-does-gcc-create-a-shared-object而不是/ 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内核/动态加载程序是否更改了可执行文件的位置或不。


1
“运行之间主要更改的地址”-这不是纯PIE的效果,它是PIE并启用了ASLR。是的,几乎在任何地方都启用了它,但是对于禁用了ASLR地址的机器,两次都相同。可以全局启用ASLR,但可以通过setarch -R man7.org/linux/man-pages/man8/setarch.8.html-R, --addr-no-randomize 禁用虚拟地址空间的随机化。打开ADDR_NO_RANDOMIZE。”来禁用ASLR 。“ man7.org/linux/man-pages/man2/personality.2.htmlADDR_NO_RANDOMIZE(从Linux 2.6.12开始)设置此标志后,禁用地址空间布局随机化。
osgx

2

Github上有bash脚本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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.