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

x64 Windows环境下栈溢出修改返回地址示例不生效问题问询

问题核心:栈结构、偏移计算存在多处根本性错误

你的代码移植失败本质是把32位x86平台的栈溢出逻辑直接套用到x64 Windows环境,两者的调用约定、栈布局、编译防护机制完全不同,具体错误点如下:

  • 架构位数认知错误:你所有的长度计算都是按32位x86来的,x64环境下地址、返回地址、栈上保存的帧指针长度都是8字节,不是你写的4字节,这直接导致偏移计算从根上就错了。
  • 调用约定认知错误:x64平台的前4个整数/指针参数都是通过寄存器传递的,不会像32位cdecl约定那样压到栈上。你反汇编出来的代码里f(1,2)的两个参数是分别放到ecx、edx寄存器的,属于Windows x64调用约定,这两个参数根本不会出现在f的栈帧里,你之前栈布局里写的栈上存储参数1、2完全不成立。
  • 局部变量布局认知错误:编译器不会严格按照你声明变量的顺序排列栈上局部变量:
    • 首先会做栈对齐(x64要求栈保持16字节对齐),5字节的buffer1、10字节的buffer2实际分配的栈空间都会向上对齐到8或16字节,不会刚好占5、10字节;
    • 编译器可能重排局部变量顺序,还会在局部变量和返回地址之间插入栈金丝雀(Windows默认开启/GS编译选项的安全检查)、预留对齐填充空间,你假设buffer1往上12字节就是返回地址完全是主观猜测。
  • 指针类型使用错误:你用int*类型存储栈地址,x64下int类型长度是4字节,指针长度是8字节,赋值时会直接截断地址高4位,访问的根本不是你想要的内存位置。
  • 返回地址位置认知错误:x64下进入函数f时,栈上从高到低的结构(无优化、无防护的理想情况)是:
    高地址
    调用方main预留的32字节shadow space(Windows x64强制要求)
    call指令压入的8字节返回地址 <-- 目标修改位置,位于f的RBP寄存器+8偏移处
    f入口push rbp压入的8字节旧RBP值 <-- f执行时RBP寄存器指向这个位置
    栈金丝雀、对齐填充、局部变量(buffer1、buffer2、ret)
    低地址
    
    也就是说哪怕没有任何防护、变量顺序和你想的一样,buffer1到返回地址的偏移也至少是buffer1实际分配长度 + 8字节旧RBP + 金丝雀/填充长度,远大于12字节。
  • 你对跳过指令的长度计算本身是对的:从call指令返回后的地址0x4015b3(对应x=21的赋值指令)到下一条指令0x4015ba的差是7字节,只要能正确把返回地址加7确实能跳过赋值,但你根本没有定位到正确的返回地址位置。

Windows环境下额外的阻碍

就算你算对了偏移,默认编译选项下程序也不会按你的预期运行:

  • Windows默认开启/GS栈保护,溢出时会先覆盖栈金丝雀,函数返回前校验失败直接终止进程,根本不会走到返回地址跳转的步骤;
  • 部分编译选项下编译器会直接把短函数f内联到main里,根本不会生成call f的指令,不存在你要修改的返回地址;
  • 调试模式下编译器会在栈上插入额外的调试信息、填充值,进一步打乱局部变量布局。

正确的调试方法

你现在只反汇编了main函数,根本不知道f函数实际的栈布局,正确的做法是:

  1. 编译时关闭所有防护:关闭/GS、关闭ASLR(链接选项加/DYNAMICBASE:NO)、关闭优化(加/Od)、关闭内联;
  2. 反汇编f函数本身,跟踪buffer1的实际栈地址,再通过调试器直接查看栈内存,计算buffer1到返回地址的实际偏移,不要靠32位的经验猜测。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.31 10:33:17