osg*_*sgx 77

PIE是支持可执行文件中的地址空间布局随机化(ASLR).

创建PIE模式之前,该程序的可执行文件无法被放置在内存中的随机地址,只有位置无关代码(PIC)动态库会被重新定位到一个随机偏移.它与PIC对动态库的作用非常相似,不同之处在于未创建过程链接表(PLT),而是使用PC相对重定位.

在gcc/linkers中启用PIE支持后,程序体被编译并链接为与位置无关的代码.动态链接器对程序模块执行完全重定位处理,就像动态库一样.通过全局偏移表(GOT)将全局数据的任何使用转换为访问,并添加GOT重定位.

PIE在OpenBSD PIE演示中得到了很好的描述.

此幻灯片显示对功能的更改(PIE与PIC).

x86 pic vs pie

本地全局变量和函数以饼图进行优化

外部全局变量和函数与pic相同

并在此幻灯片中(PIE vs旧式链接)

x86派对无标志(已修复)

局部全局变量和函数类似于fixed

外部全局变量和函数与pic相同

注意,PIE可能与之不兼容 -static

  • 为什么-pie和-static在ARM上兼容,在x86上不兼容?我的问题:http://stackoverflow.com/questions/27082959/gcc-static-and-pie-are-incompatible-for-x86 (5认同)
  • 也在维基百科:http://en.wikipedia.org/wiki/Position-independent_code#Position-independent_executables (3认同)

Cir*_*四事件 27

最小的可运行示例:GDB可执行文件两次

对于那些想要看到一些动作的人:

#include <stdio.h>

int main(void) {
    puts("hello");
}
Run Code Online (Sandbox Code Playgroud)

对于那个-no-pie,我们看到break main运行之间的变化地址:

#!/usr/bin/env bash
echo 2 | sudo tee /proc/sys/kernel/randomize_va_space
for pie in no-pie pie; do
  exe="${pie}.out"
  gcc -O0 -std=c99 "-${pie}" "-f${pie}" -ggdb3 -o "$exe" main.c
  gdb -batch -nh \
    -ex 'set disable-randomization off' \
    -ex 'break main' \
    -ex 'run' \
    -ex 'printf "pc = 0x%llx\n", (long  long unsigned)$pc' \
    -ex 'run' \
    -ex 'printf "pc = 0x%llx\n", (long  long unsigned)$pc' \
    "./$exe" \
  ;
  echo
  echo
done
Run Code Online (Sandbox Code Playgroud)

所以在这个例子中,第一次运行的地址是0x401126和第二次运行的地址run.

但是对于那个,两个运行0x401126的地址-pie保持不变0x1139:

Breakpoint 1 at 0x401126: file main.c, line 4.

Breakpoint 1, main () at main.c:4
4           puts("hello");
pc = 0x401126

Breakpoint 1, main () at main.c:4
4           puts("hello");
pc = 0x401126
Run Code Online (Sandbox Code Playgroud)

0x5630df2d6139确保ASLR打开(Ubuntu 17.10中的默认设置):如何暂时禁用ASLR(地址空间布局随机化)?| 问问Ubuntu.

0x55763ab2e139需要GDB,顾名思义,默认情况下关闭进程的ASLR以在运行时提供固定地址以改善调试体验:gdb地址和"真实"地址之间的差异?| 堆栈溢出

echo 2 | sudo tee /proc/sys/kernel/randomize_va_space 开玩笑

此外,我们还可以观察到:

Breakpoint 1 at 0x1139: file main.c, line 4.

Breakpoint 1, main () at main.c:4
4           puts("hello");
pc = 0x5630df2d6139

Breakpoint 1, main () at main.c:4
4           puts("hello");
pc = 0x55763ab2e139
Run Code Online (Sandbox Code Playgroud)

给出实际的运行时加载地址:

readelf -s ./no-pie.out | grep main
Run Code Online (Sandbox Code Playgroud)

而:

64: 0000000000401122    21 FUNC    GLOBAL DEFAULT   13 main
Run Code Online (Sandbox Code Playgroud)

只给出一个偏移量:

readelf -s ./pie.out | grep main
Run Code Online (Sandbox Code Playgroud)

通过关闭ASLR(使用set disable-randomization off或者readelf),GDB总是给出randomize_va_space地址:set disable-randomization off,因此我们推断main地址由以下组成:

65: 0000000000001135    23 FUNC    GLOBAL DEFAULT   14 main
Run Code Online (Sandbox Code Playgroud)

TODO在Linux内核/ glibc加载器/哪里是硬编码的0x555555554000?如何在Linux中确定PIE可执行文件的文本部分的地址?

在Ubuntu 18.04中测试过.

相关问题:如果使用-fPIC构建目标文件,我怎么能用objdump这样的东西来判断?

  • @CiroSantilli新疆再教育营六四事件法轮功郝海东我的意思是在gdb中添加新断点时显示的地址。无论如何,我为此道歉。我又仔细的测试了一下,这次看到了。谢谢! (2认同)

归档时间:

查看次数:

61397 次

最近记录:

6 年 前