在x86-64架构Linux系统中能否向虚拟地址0x0写入数据?
在x86-64 Linux系统中向虚拟地址0x0写入数据的实现方式
Linux内核默认会将虚拟地址0x0所在的内存页标记为无效,直接访问会触发SIGSEGV段错误,但通过以下几种方式可以实现向0x0地址写入数据(均需要root权限):
1. 调整内核内存防护参数
内核的vm.mmap_min_addr参数限制了用户进程可映射的最低虚拟地址,默认值一般为65536(0x10000),以此防范NULL指针解引用类攻击。要允许映射0地址,执行:
sysctl -w vm.mmap_min_addr=0
修改后,用户进程即可通过mmap系统调用手动映射0地址起始的内存页,进而对0x0地址进行读写。
2. 编写可访问0x0地址的用户态程序
以C语言为例,通过mmap映射0地址页后即可写入数据:
#include <sys/mman.h> #include <stdio.h> #include <stdlib.h> int main() { // 映射0地址起始的4KB内存页,赋予读写权限 void *null_page = mmap((void*)0, 4096, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (null_page == MAP_FAILED) { perror("mmap failed"); exit(EXIT_FAILURE); } // 向0x0地址写入数据 *(unsigned int*)0x0 = 0xDEADBEEF; // 验证写入结果 printf("Wrote 0x%X to 0x0, read back: 0x%X\n", 0xDEADBEEF, *(unsigned int*)0x0); munmap(null_page, 4096); return 0; }
编译运行步骤:
gcc -o write_null write_null.c ./write_null
3. 关于编译链接标志的说明
不存在单纯通过gcc/ld的编译链接标志直接让0x0地址可写的方法,因为虚拟地址的访问权限由内核页表和MMU硬件控制,编译链接阶段无法绕过内核的内存管理策略。所有能访问0x0地址的方法,都需要先调整内核相关设置或通过内核层面操作修改页表权限。
注意事项
- 关闭
vm.mmap_min_addr防护会大幅降低系统安全性,容易被利用NULL指针漏洞的恶意程序攻击,仅建议在测试环境中使用。 - 直接修改内核页表的方式(如编写内核模块)风险极高,可能导致系统崩溃或不稳定,除非有特殊需求否则不推荐。
内容的提问来源于stack exchange,提问作者Architek
相关产品推荐
相关产品推荐

