为什么在溢出ret地址后,作为函数参数给出的字符串的地址会发生变化?

时间:2011-12-17 12:16:39

标签: c stack callstack buffer-overflow shellcode

我想通过控制堆栈来利用C代码的漏洞用于教育目的。一个简单的基于堆栈的缓冲区溢出,用应该执行shellcode的地址覆盖返回地址。代码是一个简单的函数,它将缓冲区作为参数,并尝试将strcpy()缓冲区转换为固定大小。 main中给出的参数是argv[1]。所以我认为,如果我找到了必须覆盖的确切内存量,那么我可以简单地将由\x90(NOP指令)组成的字符串作为输入,然后是shellcode,最后是该缓冲区的地址。由于这是第一个参数,其地址为$ebp+8,您可以通过运行gdb找到它,在函数的开头设置一个断点,只需键入i args即可获得该地址。作为参数传递的字符串。所以我发现如果我覆盖n个字节,然后给出地址的值,那么这将完全覆盖返回地址。所以我有这样的输入:

perl -e print(\x90 x n-sizeof(shellcode) . shellcode . address)'

它没有用,我试图理解为什么。使用gdb我运行程序。我在strcpy()函数之前放了一个断点。那时我有一个参数,它是一个指向我的输入的字符串指针,它的地址与我的字符串输入结束时的地址相同,我向前走了1条指令。我检查了堆栈。我现在已经保存eip$ebp + 4),其中包含argv[1]末尾给出的地址值,这是预期的行为(这意味着它不会覆盖其他地址在ret地址之上,即第一个参数的值)。奇怪的是,现在$ebp+8的内容不是“地址”而是其他内容?但是保存的eip的内容是指向我利用漏洞的字符串的地址。但似乎ret addr并不执行该地址的内容。

1 个答案:

答案 0 :(得分:1)

堆栈帧的组织方式是ABI的一部分。 Linux在x86-64上使用的ABI的描述是here。你会找到你需要的一切(然后更有可能)。有关堆栈框架组织,请参阅第3.2节。