当前位置: 首页 > news >正文

易混淆的点:栈的增长方向 和 缓冲区内的数据写入方向是相反的

核心概念澄清

  1. 栈的增长方向:指当新的栈帧(函数调用)或新的局部变量被分配时,栈指针(SP)移动的方向。

    • 从高地址向低地址增长(这是绝大多数现代系统,如x86/x86-64架构的标准行为)。

    • 这决定了不同变量在栈上的相对位置

  2. 缓冲区内的数据写入方向:指当向一个数组或缓冲区(如 char buffer[10])写入数据时,字节被放置的顺序。

    • 从低地址向高地址填充(这是内存操作的基本逻辑,与架构无关)。

    • 这决定了溢出时会影响到哪个相邻的变量


结合例子进行图解

假设我们有如下代码,栈的起始位置在 0x1050

void function() {int authenticated = 0; // 第9行,先声明char buffer[4];        // 第10行,后声明strcpy(buffer, "OVERFLOW!"); // 不安全拷贝,数据过长
}
第一步:栈帧分配与变量布局(栈的增长方向)

当 function 被调用时,系统会为其在栈上分配空间。

  1. authenticated 先被分配。栈指针向低地址移动,假设 authenticated 被放在地址 0x104C - 0x1048

  2. 接着 buffer 被分配。栈指针继续向低地址移动,buffer 被放在地址 0x1044 - 0x1047

此时的内存布局(从高到低)如下:

内存地址存储内容说明
0x1050...调用者的栈帧
0x104Cauthenticated (字节0)高地址,先入栈的变量
0x104Bauthenticated (字节1)
0x104Aauthenticated (字节2)
0x1049authenticated (字节3)
0x1048
0x1047buffer[3]后入栈的变量
0x1046buffer[2]
0x1045buffer[1]
0x1044buffer[0]低地址,缓冲区的起始位置

关键点一:由于栈向低地址增长,先声明的 authenticated 确实在高地址,后声明的 buffer 在低地址

第二步:向缓冲区写入数据(缓冲区内的写入方向)

现在执行 strcpy(buffer, "OVERFLOW!")。字符串 "OVERFLOW!" (包括结尾的 \0) 会被复制到 buffer 开始的地址。

  1. 字符 'O' 被写入 buffer[0] (地址 0x1044)。

  2. 字符 'V' 被写入 buffer[1] (地址 0x1045)。

  3. 字符 'E' 被写入 buffer[2] (地址 0x1046)。

  4. 字符 'R' 被写入 buffer[3] (地址 0x1047)。

  5. 此时,4字节的 buffer 已满。但字符串还没完,于是开始溢出...

  6. 字符 'F' 被写入下一个相邻的字节,即地址 0x1048

  7. 字符 'L' 被写入 0x1049

  8. 字符 'O' 被写入 0x104A

  9. 字符 'W' 被写入 0x104B

  10. 字符 '!' 被写入 0x104C

  11. 字符 '\0' 被写入 0x104D

关键点二:数据写入是从 buffer 的起始低地址 (0x1044) 开始,逐步向高地址填充。当填满 buffer 后,继续写入就会覆盖更高地址的内存。

第三步:溢出后果

从上面的写入过程可以看出:

  • 地址 0x1048 到 0x104D 原本不属于 buffer

  • 地址 0x1049 到 0x104C 正好是 authenticated 变量所在的位置!

  • 字符 'W' 和 '!' 覆盖了 authenticated 的部分数据,将其从 0 修改为了一个非零值。


总结与类比

可以把栈想象成一本从后往前写的笔记本(栈向低地址增长):

  • 你先写第一章(authenticated),写在笔记本的靠后位置(高地址)。

  • 然后你写第二章(buffer),写在笔记本的靠前位置(低地址)。

但当你具体写第二章的内容时,你依然是从左到右(向高地址)书写的。如果你写得太长,超出了第二章预留的页面,你就会写到第一章的内容上,把第一章的字给擦掉覆盖了。

结论

  • 栈的增长方向(分配变量):高地址 -> 低地址。这决定了 authenticated 在 buffer 的“上方”(高地址)。

  • 数据的写入方向(填充变量):低地址 -> 高地址。这决定了当 buffer 溢出时,数据会向“上方”(高地址)蔓延,从而覆盖 authenticated

http://www.dtcms.com/a/549719.html

相关文章:

  • 全流程掌握生态环评核心技术——涵盖生物量模拟、生物多样性计算、脆弱度评价及公路铁路、机场、水利项目实战
  • 【Embedded System】嵌入式C语言基础知识
  • PsTools 学习笔记(7.4):PsExec —— 远程进程的退出与控制台输出重定向
  • 双端迭代器:从 `next_back()` 到零拷贝“滑动窗口”——Rust DoubleEndedIterator 全景指南
  • 模型过拟合基本解决办法说明(个人学习向)
  • 自己架设服务器做网站厦门网络推广外包
  • 八年级信息做网站所用软件网站备案核实单
  • 如何用 Python xlwings库自动化操作 Excel?
  • 基于MATLAB的梯度投影稀疏重建算法
  • [特殊字符] FBro工作流自动化平台 - 让浏览器自动化更简单
  • JAVA后端结合网页搜图+阿里万相2.5实现自动化修图与返回
  • 和平区网站制作手机企业网站怎么做
  • 如何在好医生网站做二类学分dede中英文网站切换
  • Kubernetes 实战入门内容
  • 变量声明与可变性
  • 前端生产部署完全指南:从零到精通
  • 做外贸的人常用的网站wordpress视频站模板下载
  • Oracle数据库安装(Windows)
  • 跳转指令介绍
  • 关于网站制作的论文个人网页效果图
  • 评估agent能力benchmark收集汇总
  • 番禺五屏网站建设西安网站建设xs029
  • 深入剖析 Rust `HashMap`:安全哈希 (SipHash) 与高性能冲突处理 (Swiss Table)
  • 一款漏洞库批量下载更新工具,便于在离线情况下漏洞的访问检索
  • 做任务的网站源码活动线报资源网
  • 【Oceanbase】OceanBase批量写入性能优化实战:转储、日志归档、多并发
  • 企业网站制作要求免费的企业网站
  • 9-SpringCloud-服务网关 Gateway-高级特性之 Filter-1
  • 服务器数据恢复—重装导致reiserfs中损坏数据如何复活?
  • RabbitMQ实现原理深度解析:从AMQP协议到高可用集群