计算机系统导论 · 第八讲:联合体、地址空间与缓冲区溢出

本页目录

第三章 第八讲:联合体、地址空间与缓冲区溢出

来源:ICS08,2026 年 10 月 8 日,53 页;配合 Attack Lab 实验讲义。

1. 联合体与位模式

联合体各成员从同一地址开始,大小是容纳最大成员并满足整体对齐所需的字节数。课件中的 char、int[2]、double 联合体为 8 字节,对应结构体为 24 字节。

把浮点位模式解释成整数,与数值类型转换是两种运算:浮点数 1.0 的单精度位模式为 0x3f800000,而把 1.0 转成整数得到 1。位模式分析用于解释编码;数值转换按目标类型重新编码。

小端序将最低有效字节放在最低地址。连续字节 f0 f1 f2 f3 f4 f5 f6 f7 在 x86-64 中解释为 64 位整数 0xf7f6f5f4f3f2f1f0。

2. 进程地址空间

  • 代码段:机器指令;只读常量通常置于只读数据区域。
  • 静态数据区:全局变量、静态变量,生命周期贯穿程序运行。
  • 堆:动态分配对象,由分配与释放操作控制生命周期。
  • 栈:活动调用的栈帧,保存局部数据、返回地址和寄存器。
  • 共享库及大块映射区:通过映射组织,位置与具体进程布局有关。

地址空间图描述虚拟地址,不能直接当作物理内存布局。递归每层都保留独立栈帧;大局部数组使每层消耗增大。课件中每层约 128 KiB 的数组很快耗尽栈空间。

3. 越界写怎样改变程序状态

C 中数组访问转成地址计算与内存读写,机器指令不记录源代码中的数组边界。结构体中数组越界可能覆盖相邻浮点字段;栈缓冲区越界可能覆盖保存的寄存器或返回地址。

课件 echo 分配 24 字节栈空间,缓冲区从 %rsp 开始,返回地址在偏移 24 处。即使源代码数组仅 4 字节,返回地址偏移仍由实际栈帧确定。输入 24 个普通字符后,字符串终止符写入偏移 24,已经改动返回地址最低字节。

分析顺序:确定缓冲区首址,计算目标字段相对偏移,按小端序解释覆盖后的字节,再跟踪 ret 的取址与跳转。

4. 代码注入与 ROP 的区别

代码注入把指令字节放入输入缓冲区,并把控制流转到该缓冲区。ROP 将返回地址组织成已有指令片段的地址序列;每个片段通常以 ret 结束,栈同时存放后续片段地址与所需数据。

ret 的效果是从栈顶取新 PC,再令 %rsp 增加 8;popq 还会额外消耗一个栈槽。手工追踪 ROP 时,要逐条记录寄存器和 %rsp,区分地址与该地址中的值。

5. 课件中的保护机制

机制作用
长度受限的输入将实际读入长度限制在缓冲区容量内,并保留终止符空间
地址随机化使栈及映射区域的地址随运行变化
不可执行栈阻止把栈中的数据直接作为指令执行
栈金丝雀在返回前比较栈中的检测值,发现覆盖后终止执行

这些机制分别作用于输入、地址预测、执行权限和覆盖检测。ROP 使用已有可执行代码,因此不可执行栈本身不阻止 ROP;栈金丝雀仍可能检测到覆盖。

fgets(buf, n, stdin) 最多存入 个字符并写终止符;strncpy 在源串过长时可能不写终止符,使用时需要明确长度语义。

查看原始笔记