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

为何无溢出行为的函数调用会覆盖其他函数的栈内存?

CSAPP Attack Lab Level3 栈覆盖问题解析

在CSAPP的Attack Lab实验Level3的说明文档中提到:
"调用hexmatch和strncmp函数时,它们会向栈中压入数据,覆盖原本属于getbuf函数缓冲区的部分内存。因此,你需要注意cookie字符串的存放位置。"
我完成了该实验,但实在无法理解为何无溢出行为的函数调用会破坏其他函数的栈内存。注入代码将执行流切换到touch3后,getbuf的40字节栈内存似乎被覆盖了,更准确地说,是在调用hexmatch和strncmp之后发生的覆盖。

以下是相关函数的反汇编代码:

00000000004017a8 <getbuf>:
  4017a8:   48 83 ec 28             sub    $0x28,%rsp
  4017ac:   48 89 e7                mov    %rsp,%rdi
  4017af:   e8 8c 02 00 00          call   401a40 <Gets>
  4017b4:   b8 01 00 00 00          mov    $0x1,%eax
  4017b9:   48 83 c4 28             add    $0x28,%rsp
  4017bd:   c3                      ret    
  4017be:   90                      nop
  4017bf:   90                      nop
000000000040184c <hexmatch>:
  40184c:   41 54                   push   %r12
  40184e:   55                      push   %rbp
  40184f:   53                      push   %rbx
  401850:   48 83 c4 80             add    $0xffffffffffffff80,%rsp
  401854:   41 89 fc                mov    %edi,%r12d
  401857:   48 89 f5                mov    %rsi,%rbp
  40185a:   64 48 8b 04 25 28 00    mov    %fs:0x28,%rax
  401861:   00 00 
  401863:   48 89 44 24 78          mov    %rax,0x78(%rsp)
  401868:   31 c0                   xor    %eax,%eax
  40186a:   e8 41 f5 ff ff          call   400db0 <random@plt>
  40186f:   48 89 c1                mov    %rax,%rcx
  401872:   48 ba 0b d7 a3 70 3d    movabs $0xa3d70a3d70a3d70b,%rdx
  401879:   0a d7 a3 
  40187c:   48 f7 ea                imul   %rdx
  40187f:   48 01 ca                add    %rcx,%rdx
  401882:   48 c1 fa 06             sar    $0x6,%rdx
  401886:   48 89 c8                mov    %rcx,%rax
  401889:   48 c1 f8 3f             sar    $0x3f,%rax
  40188d:   48 29 c2                sub    %rax,%rdx
  401890:   48 8d 04 92             lea    (%rdx,%rdx,4),%rax
  401894:   48 8d 04 80             lea    (%rax,%rax,4),%rax
  401898:   48 c1 e0 02             shl    $0x2,%rax
  40189c:   48 29 c1                sub    %rax,%rcx
  40189f:   48 8d 1c 0c             lea    (%rsp,%rcx,1),%rbx
  4018a3:   45 89 e0                mov    %r12d,%r8d
  4018a6:   b9 e2 30 40 00          mov    $0x4030e2,%ecx
  4018ab:   48 c7 c2 ff ff ff ff    mov    $0xffffffffffffffff,%rdx
  4018b2:   be 01 00 00 00          mov    $0x1,%esi
  4018b7:   48 89 df                mov    %rbx,%rdi
  4018ba:   b8 00 00 00 00          mov    $0x0,%eax
  4018bf:   e8 ac f5 ff ff          call   400e70 <__sprintf_chk@plt>
  4018c4:   ba 09 00 00 00          mov    $0x9,%edx
  4018c9:   48 89 de                mov    %rbx,%rsi
  4018cc:   48 89 ef                mov    %rbp,%rdi
  4018cf:   e8 cc f3 ff ff          call   400ca0 <strncmp@plt>
  4018d4:   85 c0                   test   %eax,%eax
  4018d6:   0f 94 c0                sete   %al
  4018d9:   0f b6 c0                movzbl %al,%eax
  4018dc:   48 8b 74 24 78          mov    0x78(%rsp),%rsi
  4018e1:   64 48 33 34 25 28 00    xor    %fs:0x28,%rsi
  4018e8:   00 00 
  4018ea:   74 05                   je     4018f1 <hexmatch+0xa5>
  4018ec:   e8 ef f3 ff ff          call   400ce0 <__stack_chk_fail@plt>
  4018f1:   48 83 ec 80             sub    $0xffffffffffffff80,%rsp
  4018f5:   5b                      pop    %rbx
  4018f6:   5d                      pop    %rbp
  4018f7:   41 5c                   pop    %r12
  4018f9:   c3                      ret    

00000000004018fa <touch3>:
  4018fa:   53                      push   %rbx
  4018fb:   48 89 fb                mov    %rdi,%rbx
  4018fe:   c7 05 d4 2b 20 00 03    movl   $0x3,0x202bd4(%rip)        # 6044dc <vlevel>
  401905:   00 00 00 
  401908:   48 89 fe                mov    %rdi,%rsi
  40190b:   8b 3d d3 2b 20 00       mov    0x202bd3(%rip),%edi        # 6044e4 <cookie>
  401911:   e8 36 ff ff ff          call   40184c <hexmatch>
  401916:   85 c0                   test   %eax,%eax
  401918:   74 23                   je     40193d <touch3+0x43>
  40191a:   48 89 da                mov    %rbx,%rdx
  40191d:   be 38 31 40 00          mov    $0x403138,%esi
  401922:   bf 01 00 00 00          mov    $0x1,%edi
  401927:   b8 00 00 00 00          mov    $0x0,%eax
  40192c:   e8 bf f4 ff ff          call   400df0 <__printf_chk@plt>
  401931:   bf 03 00 00 00          mov    $0x3,%edi
  401936:   e8 52 03 00 00          call   401c8d <validate>
  40193b:   eb 21                   jmp    40195e <touch3+0x64>
  40193d:   48 89 da                mov    %rbx,%rdx
  401940:   be 60 31 40 00          mov    $0x403160,%esi
  401945:   bf 01 00 00 00          mov    $0x1,%edi
  40194a:   b8 00 00 00 00          mov    $0x0,%eax
  40194f:   e8 9c f4 ff ff          call   400df0 <__printf_chk@plt>
  401954:   bf 03 00 00 00          mov    $0x3,%edi
  401959:   e8 f1 03 00 00          call   401d4f <fail>
  40195e:   bf 00 00 00 00          mov    $0x0,%edi
  401963:   e8 d8 f4 ff ff          call   400e40 <exit@plt>

问题原因解析

核心原因是x86-64架构的栈向下增长特性,以及后续函数的栈帧扩展覆盖了getbuf的栈缓冲区:

  1. getbuf的栈布局:
    getbuf通过sub $0x28,%rsp分配了40字节的缓冲区,缓冲区的地址范围是[rsp_prev - 40, rsp_prev)(其中rsp_prev是进入getbuf时的rsp值)。当我们通过溢出修改getbuf的返回地址为touch3后,getbuf执行ret时会跳转到touch3,此时rsp回到rsp_prev,并在ret后加8(弹出返回地址到rip)。

  2. hexmatch的栈空间分配:
    touch3调用hexmatch时,call指令会先将下一条指令的地址压栈(rsp减8)。进入hexmatch后:

    • 先push r12、rbp、rbx三个寄存器,rsp再减24字节;
    • 执行add $0xffffffffffffff80,%rsp,等价于sub $0x80,%rsp,直接向低地址方向分配128字节的局部空间。
      此时rsp的位置为rsp_prev - 8 - 24 - 128 = rsp_prev - 160,hexmatch的局部空间范围是[rsp_prev - 160, rsp_prev - 32)。
  3. 栈空间重叠与覆盖:
    getbuf的缓冲区范围是[rsp_prev - 40, rsp_prev),其中[rsp_prev - 40, rsp_prev - 32)这8字节的区域,正好和hexmatch局部空间的高地址部分重叠。当hexmatch调用__sprintf_chk向局部空间写入字符串时,就会覆盖这部分属于getbuf缓冲区的内存,也就是你观察到的getbuf栈内存被覆盖的现象。

简单来说,不是函数调用有溢出,而是后续函数的栈帧扩展直接覆盖了之前函数留在栈上的缓冲区区域——栈的向下增长特性让这种重叠成为可能。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 19:55:17