所以如果我有这个代码:
int main() {
char buff[20];
int x = 0;
gets(buff);
if (x==1337) {
print("Congrats");
}
printf("%d\n", x);
return 0;
}
知道这是用C语言编写的(并不重要),如何将这个char[]
完全溢出1337?
而且,我不太了解我得到的输出..例如,如果我运行此代码并输入:
12345678901234567890a
输出结果为:
0
事实上,在数据泄漏到X的值之前,我必须通过我的数组大小的额外 8 字符溢出char[]
。我不知道为什么会这样,如果有人理解这一点,我真的会想要一些帮助。但是,它并不止于此。
如果我输入的是:
1234567890123456789012345678aa
我的输出是:
24929
这引起了我的反响。由于我希望它可以通过a+a
的char值或甚至a*a
溢出,唉它既不是。 (a
的char值为97)。
总而言之,因为我现在可能会感到困惑。我想知道如何将缓冲区(在C中)溢出到int中,使int保持一个非常具体的值(在本例中为1337)。此外,如果您能解释这些数字是如何出现的,我将非常感激!顺便说一句,可能有助于提及代码正在Linux shell上执行。
答案 0 :(得分:4)
由于这可能是家庭作业,而不是给你一个直接的答案,我要做的就是告诉你 C程序做你认为你的程序会做什么,和输入超长输入时的行为方式。
#include <stdio.h>
int main(void)
{
struct {
char buff[20];
volatile unsigned int x;
} S;
S.x = 0;
gets(S.buff);
if (S.x == 1337)
puts("Congrats");
else
printf("Wrong: %08x\n", S.x);
return 0;
}
关键的区别在于我强迫编译器以特定方式布局堆栈帧。我也用十六进制打印x
的值。这使得输出更容易预测,也更容易解释。
$ printf 'xxxxxxxxxxxxxxxxxxxxABCD' | ./a.out
Wrong: 44434241
$ printf 'xxxxxxxxxxxxxxxxxxxxABC' | ./a.out
Wrong: 00434241
$ printf 'xxxxxxxxxxxxxxxxxxxxAB' | ./a.out
Wrong: 00004241
$ printf 'xxxxxxxxxxxxxxxxxxxxA' | ./a.out
Wrong: 00000041
困扰你的一切都是由以下一个或多个引起的:编译器不以你期望的方式布局堆栈帧,int
内的字节顺序不是你的预期,以及从二进制到十进制的转换模糊了RAM中的数据。
练习:在-S
模式下编译我的程序和原始程序,这会转储生成的汇编语言。并排阅读它们。弄清楚差异意味着什么。这应该告诉你什么输入(如果有的话 - 可能不可能!)将让你的程序打印出来#Congrats&#39;。