Linux奇技淫巧之-使用setarch 禁止地址空间随机化

时间:2024-02-24 13:42:17

先来看这样一个代码:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main() {

        int *p = (int*)malloc(sizeof(int));
        *p = 0;
        while(1){
                printf("[%d]addr: %p, value: %d\n", getpid(), p, *p);
                *p = *p + 1;
                sleep(1);
        }
        return 0;
}

代码很简单,在堆上分配一个int大小的内存空间,先将这个内存空间清零,然后在一个死循环中打印进程id,该内存空间的地址,以及该内存空间保存的数据,然后将其中的数字加1,睡眠1秒钟,如此循环往复。

我们将其编译成可执行文件,并命名为addr_randomize

gcc -o addr_randomize addr_randomize.c

如果我们在命令行同时运行这个程序的两个实例,看看会发生什么:

[-bash-4.2  $]./addr_randomize & ./addr_randomize &
[1] 2139
[2] 2140
[-bash-4.2 $]
[2139]addr: 0x912010, value: 0
[2140]addr: 0xda2010, value: 0
[2139]addr: 0x912010, value: 1
[2140]addr: 0xda2010, value: 1
[2139]addr: 0x912010, value: 2
[2140]addr: 0xda2010, value: 2
[2140]addr: 0xda2010, value: 3
[2139]addr: 0x912010, value: 3
[2140]addr: 0xda2010, value: 4

可以看到启动了两个进程,一个pid为2139,另一个为2140.这里我们关注这个指针p所指向的地址,2139进程,p指向0x912010,2140进程,p指向0xda2010。

同一个可执行文件,每次执行时分配给p的内存地址是随机的,这是Linux内核的一种叫做Linux内核地址空间布局随机化(ASLR)的特性。目的是增大黑客预测某一个函数或者某一个数据结构的难度。

Linux kernel's Address Space Layout Randomization (ASLR). ASLR is a security feature that randomizes the memory addresses used by system processes, making it harder for attackers to predict the locations of specific functions or data structures.

那如果想禁用这个特性,应该怎么做呢?

使用setarch命令

setarch $(uname -m) --addr-no-randomize your_program_name

其中uname -m 返回你的机器的架构,在我的机器上,它返回x86_64,addr-no-randomize选项可以禁用某一个可执行文件的ASLR。

[-bash-4.2 $]setarch $(uname -m) --addr-no-randomize ./addr_randomize & setarch $(uname -m) --addr-no-randomize ./addr_randomize &
[1] 3146
[2] 3147
[-bash-4.2 $]
[3146]addr: 0x602010, value: 0
[3147]addr: 0x602010, value: 0
[3146]addr: 0x602010, value: 1
[3147]addr: 0x602010, value: 1
[3146]addr: 0x602010, value: 2
[3147]addr: 0x602010, value: 2
[3146]addr: 0x602010, value: 3
[3147]addr: 0x602010, value: 3

可以看到,在禁用了ASLR之后,进程3146和进程3147中p指向的地址都是0x602010。

虽然这两个进程中p都指向0x602010, 并不意味着两个进程中的p真的指向同一个物理内存地址。因为0x602010是逻辑地址,还要经过地址单元的翻译,才会映射到最终的物理地址。

上述命令只对某一个进程起作用。如果要对所有进程都禁用ASLR,可以修改这个参数:kernel.randomize_va_space

sudo sysctl -w kernel.randomize_va_space=0

当系统重启后,这个参数会恢复默认值1

如果要保持重启后依然有效,需要将其写入配置文件/etc/sysctl.conf

kernel.randomize_va_space = 0

编辑完 /etc/sysctl.conf 后,执行下面的命令使更改生效:

sudo sysctl -p

需要注意的事,正如前面所说,修改这个参数会降低系统的安全系数,最好不要去改,除非有特殊的需要并且你很清楚这么做的后果。