开启Full ASLR的PIE二进制文件栈起始地址计算问题求助
原因分析
- 内核级栈间隙随机化:现代Linux的Full ASLR不仅随机化栈的整体基址,还会在进程启动时向栈顶添加随机大小的间隙(通常是0~几页)。这个间隙是内核主动引入的额外随机层,导致栈内任意地址到栈基址的偏移不再固定。
- 环境变量与参数的动态影响:进程启动时,命令行参数、环境变量的长度和布局会改变栈的使用空间。部分系统还会随机化环境变量的顺序或填充额外字节,进一步导致栈内偏移波动。
解决方法
- 直接泄露栈基址:
- 利用格式字符串漏洞泄露栈帧链(如64位下的
%rbp相关地址),通过回溯栈帧找到栈基址;或者泄露argv[0]的地址,它与栈基址的偏移是固定的(argv数组属于进程启动时的固定栈结构)。 - 泄露栈上的返回地址,结合libc中
__libc_start_main的地址反推_start函数位置,再通过_start的汇编逻辑获取栈基址(_start会保存初始栈顶地址)。
- 利用格式字符串漏洞泄露栈帧链(如64位下的
- 扩大mprotect覆盖范围:已知偏移误差在0x1000~0x2000,可将mprotect的起始地址往低地址偏移0x3000,长度设为0x4000。比如原本计算的栈基址为
addr,则用addr - 0x3000作为起始地址,确保覆盖实际的栈区域。 - 固定环境与参数:用
env -i清空环境变量后手动设置固定的环境变量集合,同时传入长度完全一致的参数,减少栈布局的额外波动(仅辅助,无法解决内核栈间隙问题)。 - 利用栈上固定结构:泄露栈上的
environ变量地址,它与栈基址的偏移是固定的,不受栈间隙影响,可直接通过该偏移计算栈基址。
内容的提问来源于stack exchange,提问作者fest chest
相关产品推荐
相关产品推荐

