c - 使用堆栈粉碎跳过指令

标签 c stack buffer-overflow stack-smash

我一直在尝试通过堆栈粉碎更改返回地址来跳过一条指令。以下代码跳过 main 中的 a++ 并打印输出“1 3”。我在 32 位英特尔机器上执行了这段代码。

#include<stdio.h>
void fun(int a,int b) {
    // buffer
    char buf[8];
    char *p;
    p = (char *)buf+24;
    *p=*p+5;
    return;
}

int main() {
    int a=1,b=2;
    fun(a,b);
    a++;
    b++;
    printf("%d %d",a,b);
 }

我无法理解为什么返回地址存储在距 buf 起始地址 24 字节的位移处。我曾尝试在不同的 32 位英特尔机器上执行相同的代码,但我不得不使用 20 字节而不是 24 字节的位移。我把我的理解写在了下图中。我不确定是什么填补了“?”所代表的空白。在图中。 gcc 是否将任何 canary 值放在那里,还是我遗漏了什么?

图链接:http://www.cse.iitb.ac.in/~shashankr/stack.png

Smashing the stack example3.c confusion问了同样的问题,但无法解释一般流离失所的原因。

下图给出了在函数中放置断点得到的堆栈 View 。

stack content
(来源:shashankr at www.cse.iitb.ac.in)

下面是main和fun的汇编代码:

 Dump of assembler (fun):
 0x08048434 <+0>:   push   %ebp
 0x08048435 <+1>:   mov    %esp,%ebp
 0x08048437 <+3>:   sub    $0x18,%esp
 0x0804843a <+6>:   mov    %gs:0x14,%eax
 0x08048440 <+12>:  mov    %eax,-0xc(%ebp)
 0x08048443 <+15>:  xor    %eax,%eax
 0x08048445 <+17>:  lea    -0x14(%ebp),%eax
 0x08048448 <+20>:  add    $0x18,%eax
 0x0804844b <+23>:  mov    %eax,-0x18(%ebp)
 0x0804844e <+26>:  mov    -0x18(%ebp),%eax
 0x08048451 <+29>:  movzbl (%eax),%eax
 0x08048454 <+32>:  add    $0x5,%eax
 0x08048457 <+35>:  mov    %eax,%edx
 0x08048459 <+37>:  mov    -0x18(%ebp),%eax
 0x0804845c <+40>:  mov    %dl,(%eax)
 0x0804845e <+42>:  mov    -0xc(%ebp),%eax
 0x08048461 <+45>:  xor    %gs:0x14,%eax
 0x08048468 <+52>:  je     0x804846f <fun+59>
 0x0804846a <+54>:  call   0x8048350 <__stack_chk_fail@plt>
 0x0804846f <+59>:  leave  
 0x08048470 <+60>:  ret    


 Dump of assembler (main)
 0x08048471 <+0>:   push   %ebp
 0x08048472 <+1>:   mov    %esp,%ebp
 0x08048474 <+3>:   and    $0xfffffff0,%esp
 0x08048477 <+6>:   sub    $0x20,%esp
 0x0804847a <+9>:   movl   $0x1,0x18(%esp)
 0x08048482 <+17>:  movl   $0x2,0x1c(%esp)
 0x0804848a <+25>:  mov    0x1c(%esp),%eax
 0x0804848e <+29>:  mov    %eax,0x4(%esp)
 0x08048492 <+33>:  mov    0x18(%esp),%eax
 0x08048496 <+37>:  mov    %eax,(%esp)
 0x08048499 <+40>:  call   0x8048434 <fun>
 0x0804849e <+45>:  addl   $0x1,0x18(%esp)
 0x080484a3 <+50>:  addl   $0x1,0x1c(%esp)
 0x080484a8 <+55>:  mov    $0x80485a0,%eax
 0x080484ad <+60>:  mov    0x1c(%esp),%edx
 0x080484b1 <+64>:  mov    %edx,0x8(%esp)
 0x080484b5 <+68>:  mov    0x18(%esp),%edx
 0x080484b9 <+72>:  mov    %edx,0x4(%esp)
 0x080484bd <+76>:  mov    %eax,(%esp)
 0x080484c0 <+79>:  call   0x8048340 <printf@plt>
 0x080484c5 <+84>:  leave  
 0x080484c6 <+85>:  ret    

最佳答案

我相信答案是什么。你有不同的 gcc 版本吗?无论如何,允许编译器分配比必要更多的堆栈。也许这是基于变量数量的初始“猜测”,但并没有因优化阶段而减少,优化阶段允许将任何变量移动到寄存器。或者它是一些用于保存 ecx、ebp 或其他寄存器的库,以备子程序需要时使用。

无论如何,有一个固定地址变量可以解决这个问题:a。 返回地址 = &a[-1]。

关于c - 使用堆栈粉碎跳过指令,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13330049/

相关文章:

创建节点问题,知道会发生段错误吗?

stack - 什么是堆栈随机化以及它如何防止缓冲区溢出攻击?

c - 在 ret2ret 漏洞上执行 shellcode

mysql - 使用 c 连接器将字节数组写入 mysql?

c - 有些数字比其他数字需要更长的时间来分解

c - 用 C 编写的工作非递归 floodfill 算法?

stack - 堆栈和队列之间的基本区别是什么?

c++ - "The value of ESP was not properly saved across a function call."问题

c - 在研究缓冲区溢出时我应该使用哪个版本的 GCC 或标志?

c - 缓冲区溢出未到达 eip