强制缓冲区溢出以了解
Forcing buffer overflow for Understanding
我试图理解缓冲区溢出的概念,但我在计算要将多少数据塞入堆栈以使其正确溢出时遇到了问题。假设我得到了一些代码(这不是我的代码,是的,它来自 class,但这不是评分作业):
目标是让 bar 被执行。
#include <stdio.h>
#include <string.h>
void foo(char *s) {
char buf[4];
strcpy(buf, s);
printf("You entered: [%s]", buf);
fflush(stdout);
}
void bar() {
printf("\n\nWhat? I was not supposed to be called!\n\n");
fflush(stdout);
}
int main(int argc, char *argv[]) {
if (argc != 2) {
printf("Usage: %s some_string", argv[0]);
return 2;
}
foo(argv[1]);
return 0;
}
当我反汇编bar时,我得到了bar的起始地址:
(gdb) disas bar
Dump of assembler code for function bar:
0x000000000040062d <+0>: push %rbp
我被告知需要将 28 个字节的数据塞入缓冲区,最后 4 个字节需要 \x2d\x06\x04\x00
。你从哪里得到 24 个字节来知道要填充多少随机数据。
一般来说,我最感兴趣的是如何概括和解决任何问题。
如何计算填充堆栈帧然后覆盖函数的 return 地址所需的字节数?
注意:这是用C语言编写的,用GCC 4.4.7编译的
如何计算填充堆栈帧所需的字节数,然后覆盖函数的 return 地址?
您可以通过了解您尝试利用的体系结构中堆栈帧的布局,以及编译器如何将变量放入堆栈帧来实现。 28 个字节恰好是第一个变量的位置与您正在使用的特定体系结构的堆栈帧中的 return 地址之间的差异。
从一段C代码,你可以得到不同的结果。
void foo(char *s) {
char buf[4];
strcpy(buf, s);
printf("You entered: [%s]", buf);
fflush(stdout);
}
编译器可能会输出
ADD SP, 4 // space for buf
PUSH SP-12 // address of string 's'
PUSH SP-8 // address of SP (4 + space for s)
call strcpy
push literal_You_entered
push SP-8
call printf
...
或者它可能想要一个堆栈框架。
PUSH Frame
MOVE SP, Frame
ADD SP, 4 // space for buf
....
或者可能需要保存寄存器
PUSH Frame
MOVE SP, Frame
PUSH Reg1
PUSH Reg2
ADD SP, 4 // space for buf
这可以基于编译器的优化设置。在每种情况下,这都会移动值。
尝试像 '\x01\x02\x03\x04\.....\xfe\xff'
这样的神奇缓冲区。
您得到的分段错误应该会告诉您重要字节的位置。 0x08090a0b 处的访问冲突将描述哪些字节是 return.
覆盖帧指针 (FP) 意味着您可以修改调用函数中的行为,这也可能对您有所帮助。
我试图理解缓冲区溢出的概念,但我在计算要将多少数据塞入堆栈以使其正确溢出时遇到了问题。假设我得到了一些代码(这不是我的代码,是的,它来自 class,但这不是评分作业): 目标是让 bar 被执行。
#include <stdio.h>
#include <string.h>
void foo(char *s) {
char buf[4];
strcpy(buf, s);
printf("You entered: [%s]", buf);
fflush(stdout);
}
void bar() {
printf("\n\nWhat? I was not supposed to be called!\n\n");
fflush(stdout);
}
int main(int argc, char *argv[]) {
if (argc != 2) {
printf("Usage: %s some_string", argv[0]);
return 2;
}
foo(argv[1]);
return 0;
}
当我反汇编bar时,我得到了bar的起始地址:
(gdb) disas bar
Dump of assembler code for function bar:
0x000000000040062d <+0>: push %rbp
我被告知需要将 28 个字节的数据塞入缓冲区,最后 4 个字节需要 \x2d\x06\x04\x00
。你从哪里得到 24 个字节来知道要填充多少随机数据。
一般来说,我最感兴趣的是如何概括和解决任何问题。
如何计算填充堆栈帧然后覆盖函数的 return 地址所需的字节数?
注意:这是用C语言编写的,用GCC 4.4.7编译的
如何计算填充堆栈帧所需的字节数,然后覆盖函数的 return 地址?
您可以通过了解您尝试利用的体系结构中堆栈帧的布局,以及编译器如何将变量放入堆栈帧来实现。 28 个字节恰好是第一个变量的位置与您正在使用的特定体系结构的堆栈帧中的 return 地址之间的差异。
从一段C代码,你可以得到不同的结果。
void foo(char *s) {
char buf[4];
strcpy(buf, s);
printf("You entered: [%s]", buf);
fflush(stdout);
}
编译器可能会输出
ADD SP, 4 // space for buf
PUSH SP-12 // address of string 's'
PUSH SP-8 // address of SP (4 + space for s)
call strcpy
push literal_You_entered
push SP-8
call printf
...
或者它可能想要一个堆栈框架。
PUSH Frame
MOVE SP, Frame
ADD SP, 4 // space for buf
....
或者可能需要保存寄存器
PUSH Frame
MOVE SP, Frame
PUSH Reg1
PUSH Reg2
ADD SP, 4 // space for buf
这可以基于编译器的优化设置。在每种情况下,这都会移动值。
尝试像 '\x01\x02\x03\x04\.....\xfe\xff'
这样的神奇缓冲区。
您得到的分段错误应该会告诉您重要字节的位置。 0x08090a0b 处的访问冲突将描述哪些字节是 return.
覆盖帧指针 (FP) 意味着您可以修改调用函数中的行为,这也可能对您有所帮助。