简介
ASLR,全称为 Address Space Layout Randomization,地址空间布局随机化。ASLR 技术在 2005 年的 kernel 2.6.12 中被引入到 Linux 系统,它将进程的某些内存空间地址进行随机化来增大入侵者预测目的地址的难度,从而降低进程被成功入侵的风险。当前 Linux、Windows 等主流操作系统都已经采用该项技术。
具体实现
分级
Linux 平台上 ASLR 分为 0,1,2 三级,用户可以通过一个内核参数 randomize_va_space 进行等级控制。它们对应的效果如下:
- 0:没有随机化。即关闭 ASLR。
- 1:保留的随机化。共享库、栈、mmap() 以及 VDSO 将被随机化。
- 2:完全的随机化。在 1 的基础上,通过 brk() 分配的内存空间也将被随机化。
看到这里列出的几项内存空间,很自然有两个地方十分值得注意,第一,代码段以及数据段(data段和bss段)是否被随机化了?第二,堆是否被随机化了?
ASLR 并不负责代码段和数据段的随机化
编写程序进行测试:
#include <stdio.h>
void func();
int uninitialGlobalVar;
int globalVar = 1;
int main(void)
{
int localVar = 1;
printf("Address of func() is %p, in text setment\n", func);
printf("Address of uninitialGlobalVar is %p, in bss segment\n", &uninitialGlobalVar);
printf("Address of globalVar is %p, in data segment\n", &globalVar);
printf("Address of localVar is %p, in stack\n", &localVar);
return 0;
}
void func()
{
;
}
开启完全的ASLR机制,即设置 ASLR 为 2,详细的开启关闭命令后文有介绍。使用如下命令:
sudo bash -c "echo 2 > /proc/sys/kernel/randomize_va_space"
运行程序,结果如下:
plus@plus:~/Desktop$ ./addr
Address of func() is 0x400595, in text setment
Address of uninitialGlobalVar is 0x601048, in bss segment
Address of globalVar is 0x601040, in data segment
Address of localVar is 0x7ffc353d218c, in stack
plus@plus:~/Desktop$
plus@plus:~/Desktop$ ./addr
Address of func() is 0x400595, in text setment
Address of uninitialGlobalVar is 0x601048, in bss segment
Address of globalVar is 0x601040, in data segment
Address of localVar is 0x7ffc08733eac, in stack
可见栈的地址被随机化了,但是代码段以及数据段的地址均没有发生变化。由此可知,ASLR 并不负责代码段和数据段的随机化工作。
事实上,Linux 平台通过 PIE 机制来负责代码段和数据段的随机化工作,而不是 ASLR。要开启 PIE,在使用 gcc 进行编译链接时添加 -fpie -pie 选项即可:
plus@plus:~/Desktop$ gcc addr.c -fpie -pie -o addr
开启 PIE 后,设置 ASLR 为 2,重新运行程序,结果如下:
plus@plus:~/Desktop$ ./addr
Address of func() is 0x564753ff37ee, in text setment
Address of uninitialGlobalVar is 0x5647541f4050, in bss segment
Address of globalVar is 0x5647541f4048, in data segment
Address of localVar is 0x7ffd61090a2c,