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

栈帧为何可存储指令?栈中指令执行机制及攻击场景疑问

栈帧中存储的指令执行机制疑问

问题简述

给出的汇编指令如下:

0:    48 c7 c7 ee 4f 37 45 mov    $0x45374fee, %rdi
  7:    68 60 18 40 00       pushq  $0x401860
  c:    c3                   retq

疑问:上述存储在栈帧中的3条指令如何被执行?栈帧不是仅存储数据吗?它也能存储指令?数据会被读取到寄存器,但这些指令是怎么被执行的?

问题详述

自学CMU 15-213《计算机系统》课程时,在Attack Lab第二阶段遇到栈帧被攻击代码覆盖的场景:调用getbuf()的返回地址被覆盖为%rsp指向的栈顶地址,而该栈顶地址处已注入上述攻击代码。

之前通过《CSAPP》了解到栈帧仅存储寄存器溢出的数据(包括返回地址、额外参数等),不明白为什么栈帧还能存储指令(攻击代码)并被执行。具体困惑点:

  • %rsp指向的栈帧内容是通过什么机制被执行的?
  • %rsp存储的是调用函数的返回地址(是地址而非指令),这个地址是如何被当作指令执行的?

解答

1. 内存无“数据/指令”物理划分,栈可执行是前提

CPU执行指令的核心逻辑是根据程序计数器(%rip)指向的内存地址,读取该地址开始的字节序列作为指令解码执行。内存本身只是字节序列的容器,所谓“代码区”“数据区”“栈区”是操作系统和编译器的逻辑划分,默认会给栈区设置不可执行权限,但Attack Lab的实验环境特意关闭了栈执行保护,让栈段被标记为可执行——所以栈里的字节序列只要符合x86-64指令格式,就能被CPU当作指令执行。

2. 攻击代码的执行流程

这个攻击的核心是篡改getbuf()的返回地址:

  • 正常流程:getbuf()执行retq指令时,会从栈中弹出原本的返回地址,将其加载到%rip,CPU就会跳去执行该地址的指令。
  • 攻击流程:我们把栈中存储的原返回地址替换为攻击代码的起始地址(即%rsp指向的栈顶位置)。当getbuf()执行retq时,这个栈地址会被加载到%rip,CPU接下来就会从栈的这个位置开始读取字节,解码成你给出的三条指令并依次执行:
    • mov $0x45374fee, %rdi:将目标值加载到%rdi,作为后续函数调用的第一个参数
    • pushq $0x401860:把目标函数的地址压入栈中
    • retq:弹出栈顶的目标函数地址并加载到%rip,跳去执行该函数

3. 纠正对%rsp的误解

%rsp是栈指针,它指向栈帧的栈顶(当前栈中可用的最高地址位置),它本身并不存储返回地址——返回地址是保存在栈帧的固定偏移位置里的。攻击中修改的是栈里存储的返回地址值,让它指向栈中注入代码的位置,而非修改%rsp本身。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 06:01:04