因此,我试图对这段代码执行缓冲区溢出,目的是将变量 target
更改为“Y”。问题是,我似乎无法让缓冲区溢出到足以产生运行时错误的程度。谁能帮我理解为什么?
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
enum {SIZE = 50};
char target = 'Z';
char name[SIZE];
FILE *f;
void read(char *s) {
char buffer[SIZE];
int i = 0;
int c;
for (;;)
{
c = getchar();
if ((c == EOF) || (c == '\n'))
break;
buffer[i] = c;
i++;
}
buffer[i] = '\0';
for (i = 0; i < SIZE; i++)
s[i] = buffer[i];
}
int main(void)
{
read(name);
if (strcmp(name, "ABCD") == 0)
target = 'Y';
printf("%s\n", name);
printf("%c\n", target);
exit(0);
}
最佳答案
如果您尝试使用更改后的返回地址执行此操作,则需要用您想要的特定地址覆盖它。在这种情况下,为了获得所需的结果,您可以使用代码 target = 'Y';
根据堆栈的组织方式,您可以直接破坏 read()
的返回地址,这将使您返回到 main
的第一行之后> 它被调用的地方。如果做不到这一点,您就有机会破坏 i
,这将使您可以任意写入内存。写入这些字节时需要小心,因为它会影响索引。
我假设这是在 ARM 上完成的,因为我更熟悉他们的堆栈布局和调用约定。所以,你的堆栈看起来像这样:
STACKPTR-60: buffer[0]
| | |
STACKPTR-11: buffer[49]
STACKPTR-10: padding
STACKPTR -9: padding
STACKPTR -8: i (bits 7..0)
| | |
STACKPTR -5: i (bits 31..24)
STACKPTR -4: c (bits 7..0)
| | |
STACKPTR -1: c (bits 31..24)
STACKPTR +0: link register (return address) (bits 7..0)
| | |
STACKPTR +3: link register (return address) (bits 31..24)
因此,对于这种堆栈布局,当您溢出 buffer
时,您将首先填充两个填充字节。之后,填充i
的最低有效字节。在这种情况下,您可以跳过巨大的溢出,只需修改您的索引以指向堆栈链接寄存器。你希望 i=60
开始写入返回地址,但是在你写入之后,它会递增,所以你真的想要 i=59
,这将是增加到 i=60
。此时,您可以从最低位到最高位写入所需的返回地址,然后是 EOF
或 \n
。
真正重要的是要注意,这完全是特定于体系结构和特定于编译器的。编译器设置将决定 int
的大小,是否填充堆栈以对齐变量,以及变量在堆栈中出现的顺序。该架构将决定您的堆栈框架的外观。
关于c - 缓冲区溢出困境,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23494685/