我正在尝试创建一个缓冲区溢出,它将使用值“31337”覆盖变量“b”。编译后的文件名为“bo”。缓冲区的大小为010,为8字节,所以我用“AAAAAAAA”填充它,31337是十六进制的7A69。因此,Linux中的以下命令应该在理论上有效,但它不成功:
printf 'AAAAAAAA\x69\x7A\x00\x00' | ./bo
上述命令应该覆盖“b”变量。如果我将b变量更改为1337并将命令更改为以下内容,则此方法有效:
printf 'xxxxxxxx\x39\x05\x00\x00' | ./bo
1337是十六进制的539。
以下是终端的命令结果
root@kali:~# printf 'AAAAAAAA\x69\x7A\x00\x00' | ./bo
1111638594
我预计31337
root@kali:~# printf 'AAAAAAAA\x39\x05\x00\x00' | ./bo
1337
有人知道我做错了什么吗?它适用于十六进制1337,但不适用于31337.以下是源代码:
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
int play()
{
int a;
int b;
char buffer[010];
a = 0x41414141;
b = 0x42424242;
if (read(STDIN_FILENO, &buffer, 0xC) < 0)
perror("read");
printf("%d\n", b);
}
int main(int argc, char *argv[]){
play();
exit(EXIT_SUCCESS);
}
答案 0 :(得分:1)
您不能假设变量在堆栈上具有特定位置。但是,有一种方法可以强制执行它。你可以这样做:
int play()
{
struct {
int a;
char buffer[010];
int b;
} vars;
vars.a = 0x41414141;
vars.b = 0x42424242;
if (read(STDIN_FILENO, &vars.buffer, 0xC) < 0)
perror("read");
printf("%d\n", vars.b);
}
这将强制执行内存中变量的顺序。当我尝试这个时,它有效,但是当我切换订单时
struct {
int a;
int b;
char buffer[010];
} vars;
它没有。
我不确定你能信任多少或使用它。这只保证&a<&buffer<&b
。它不保证&(a+1)=&buffer
。实际上,如果a
是一个字节类型的变量,则情况并非如此。
以下是订单重要性的示例:
int main()
{
struct {
char x;
int a;
char y;
} v;
struct {
char x;
char y;
int a;
} w;
printf("%d\n", sizeof(v));
printf("%d\n", sizeof(w));
}
输出:
$ ./a.out
12
8
如果重新排序变量,结构的大小可能会发生变化这一事实是不允许编译器重新排序的原因。