64位系统下格式字符串漏洞读取完整内存地址问题求助
解决64位系统下格式字符串漏洞高字节丢失的问题
我来帮你搞定这个问题——当初我从32位练到64位格式字符串漏洞的时候也踩过一模一样的坑,核心原因就是32位和64位系统在栈布局、调用约定上的差异没搞清楚。
先搞明白为啥高字节丢了
你现在遇到的问题有两个核心原因:
- 栈参数大小不对:64位x86_64系统里,栈上每个参数都是8字节(64位),但你只构造了6字节的地址,缺失的2字节被栈上默认的
\x00填充,导致完整的64位地址变成了0x00000000ffffeeaa(高4字节被覆盖成0)。 - 格式符不匹配:你用的
%016x在部分64位环境里只会打印低32位数据,直接把高4字节给截断了,所以看不到0x7f那部分。
另外还有个容易忽略的点:x86_64的调用约定是前6个参数用寄存器传递(rdi、rsi、rdx、rcx、r8、r9),只有第7个及以后的参数才会放在栈上。你之前用的8个%016x,前6个其实是寄存器里的值,不是栈上的内容,这也会干扰你对地址位置的判断。
具体怎么解决
1. 构造完整的小端序地址(适配栈对齐)
你的目标地址0x7fffffeeaa是64位用户空间地址,小端序的字节顺序应该是\xaa\xee\xff\xff\xff\x7f\x00\x00。但strcpy遇到\x00就会截断字符串,好在x86_64的用户空间地址高2字节本来就是0x00,所以你只需要写入低6字节就行,剩下的2字节栈会自动补0x00,不用额外处理。
2. 用64位格式符打印完整参数
把%016x换成%016lx(或者%p,专门打印指针),这样就能打印完整的64位栈参数,不会再截断高字节。
3. 调整参数偏移匹配栈布局
因为前6个%lx显示的是寄存器值,从第7个开始才是栈上的真实数据。你需要调整%lx的数量,让目标地址对应的栈参数被正确打印。
修正后的命令可以这么写:
./fmt_vuln $(printf "\xaa\xee\xff\xff\xff\x7f")%016lx.%016lx.%016lx.%016lx.%016lx.%016lx.%016lx.%016lx
4. 要是想读目标内存的话
如果你的最终目的是读取这个地址指向的内存,把对应位置的%016lx换成%s(如果是字符串)或者%llx(如果是数值)就行。比如假设目标地址在第8个参数位置,命令可以改成:
./fmt_vuln $(printf "\xaa\xee\xff\xff\xff\x7f")%016lx.%016lx.%016lx.%016lx.%016lx.%016lx.%016lx.%s
最后再提两个注意点
- 一定要记住x86_64是小端序,地址的最低字节要放在最前面(比如
0x7fffffeeaa的字节顺序是aa ee ff ff ff 7f,不是反过来)。 - 如果以后遇到的地址里包含
\x00字节,strcpy会截断,这时候可以用环境变量或者文件输入的方式传递带\x00的字符串,别死磕命令行参数。
内容的提问来源于stack exchange,提问作者TheEngineer
相关产品推荐
相关产品推荐

