C 堆栈缓冲区溢出

C 堆栈缓冲区溢出,c,stack-overflow,buffer-overflow,C,Stack Overflow,Buffer Overflow,我试图复制堆栈缓冲区溢出。这是我的密码 #include <stdio.h> int main(int argc, char *argv[]) { char x[1]; gets(x); printf("%s\n", x); } 我是在32位机器上编译的,这意味着每个内存地址都有4字节长。由于每个字符都是使用sizeof验证的1字节,所以当我输入AAAA作为输入时,我预计堆栈缓冲区会溢出,超出x所能容纳的1字节。然而,在输入13 As之前,什么都不会发生,在这一点上,

我试图复制堆栈缓冲区溢出。这是我的密码

#include <stdio.h>

int main(int argc, char *argv[]) {
  char x[1];
  gets(x);
  printf("%s\n", x);
}
我是在32位机器上编译的,这意味着每个内存地址都有4字节长。由于每个字符都是使用sizeof验证的1字节,所以当我输入AAAA作为输入时,我预计堆栈缓冲区会溢出,超出x所能容纳的1字节。然而,在输入13 As之前,什么都不会发生,在这一点上,我得到了一个非法的指令错误。14导致分段错误

问题

为什么我在5 As时没有出现分段错误? 非法指令和分段错误之间有什么区别? 除了gdb,还有什么好的工具可以可视化堆栈? 我已经看过了,但我很难理解答案

这是我的程序集转储:

(gdb) disassemble main
Dump of assembler code for function main:
   0x0804844d <+0>: push   %ebp
   0x0804844e <+1>: mov    %esp,%ebp
   0x08048450 <+3>: and    $0xfffffff0,%esp
   0x08048453 <+6>: sub    $0x20,%esp
   0x08048456 <+9>: lea    0x1f(%esp),%eax
   0x0804845a <+13>:    mov    %eax,(%esp)
   0x0804845d <+16>:    call   0x8048310 <gets@plt>
=> 0x08048462 <+21>:    lea    0x1f(%esp),%eax
   0x08048466 <+25>:    mov    %eax,(%esp)
   0x08048469 <+28>:    call   0x8048320 <puts@plt>
   0x0804846e <+33>:    leave  
   0x0804846f <+34>:    ret    
End of assembler dump.
堆栈在第3行执行主函数后立即对齐16字节。所以您不能只计算保存的返回地址的确切地址,您可以尝试从5字节到21字节。 非法指令是指与任何已定义指令不匹配的字节。每个指令都用机器代码表示,例如:push ebp为0x55等,但例如,0xff 0xff与x86机器中的任何指令都不匹配。但当任何内存访问无效时,就会出现分段错误。
使用调试器。提供所提供功能的拆解。未定义的行为是未定义的,所以在C代码方面没有太多讨论。我只是添加了反汇编。我正在使用gdb,但不知道如何可视化堆栈并查看堆栈指针与变量x的比较位置。您刚刚发布了这篇文章,是为了说明使用堆栈溢出标记的重要性,不是吗:-PSo,and+子模块做什么?试着用不同的价值观,尤其是视觉化。我建议使用书写工具或艺术媒介,由保护壳内的一个狭窄的固体颜料芯构成,在一种薄材料上画一些标记,这种薄材料是由来自木材、破布或草的纤维素纸浆湿纤维挤压而成,如果你不知道如何读/理解/写程序集,我认为你不能用这个堆栈做任何有用的事情。我认为你是从错误的方向开始的。你应该试着去理解机器语言是如何工作的,编译器是如何生成代码的,以及当一些不好的事情发生时操作系统是如何工作的。谢谢!请你再详细解释一下1好吗。如何确定堆栈是如何设置的?那么,16字节右对齐是否意味着每个堆栈单元都有16字节长?所以,即使我声明了一个1字节的char变量,操作系统也会使用16个字节来存储它?此外,为什么返回地址保存的位置不确定?首先,当调用指令执行时,您可以根据x64 ABI猜测堆栈地址,此时堆栈必须是16字节对齐的,但由于编译器优化或其他原因,它并不总是正确的。堆栈对齐意味着rsp应该是数字的倍数,在本例中为16。声明的变量与堆栈对齐无关。之所以这样做,可能是因为您在main中调用了函数,然后通过ABI,rsp必须是16 at call指令的倍数。此外,保存的返回地址没有理由是确定性的。编译器使代码满足ABI,而保存的返回地址的不确定性行为只是副作用。