缓冲区大小和两个地址之间的距离有什么区别?

时间:2013-06-02 20:43:23

标签: c buffer-overflow

 #include <stdio.h>
 #include <stdlib.h>

 int main()
 {
     char *name;
     char *command;
     name=(char *)malloc(10);
     command=(char *)malloc(128);
     printf("address of name is : %d\n",name);
     printf("address of command is:%d\n",command);
     printf("Distance between addresses is :%d\n",command-name);
     printf("Enter your name:");
     gets(name);
     printf("Hello %s\n",name);
     system(command);
 }

分配恒定内存量(缓冲区大小)和两个地址(相邻内存块)之间的距离有什么区别?在此示例中,name和command之间的差异为16 Bytes,name的缓冲区大小为10 Bytes。哪一个会触发缓冲区溢出?

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// typedef size_t u_long;

int main(){
    u_long distance;
    char *buf1= (char *)malloc(16);
    char *buf2= (char *)malloc(16);
    distance= (u_long)buf2 - (u_long)buf1;
    printf("buf1 = %p\nbuf2 = %p\ndistance = 0x%x bytes\n",
           buf1, buf2, distance);
    memset(buf2, 'A', 15); buf2[15]='\0';
    printf("before overflow buf2 = %s\n", buf2);
    memset(buf1, 'B', (8+distance));
    printf("after overflow buf2 = %s\n", buf2);
    return 0;
}

2 个答案:

答案 0 :(得分:0)

由于namecommand是通过对malloc()的单独调用分配的,因此严格来说,他们的地址之间的差异毫无意义。指针算法仅适用于同一阵列或相同分配块中的地址。当然,减去两个指针会给你一些,你只是不能用它做任何事情。没有理由相信malloc()将使用相邻的内存块,或者甚至后来的分配将具有比先前的更高的地址。然而,它可以自由分配它看起来合适。

您分配了10个字节,因此您可以使用10个字节。就是这样。

答案 1 :(得分:0)

当我在Mac OS X 10.8.3上使用GCC 4.7.1运行非常温和编辑的第二个程序版本时,0x%x更改为0x%zX并且{{1}的typedef没有注释,输出是:

u_long

这两项拨款彼此之间的距离并不遥远,这是完全允许的,但(坦率地说)不是我期望看到的。大约14 KiB的写入肯定会引发未定义的行为。

您无法假设可移植代码中的内存分配位置。如果您希望调整到buf1 = 0x7fe8d0c000e0 buf2 = 0x7fe8d0c03a00 distance = 0x3920 bytes before overflow buf2 = AAAAAAAAAAAAAAA Abort trap: 6 的某个特定版本,则可能会这样做,但这会限制您的可移植性。

然而,在像Mac这样的64位系统上,当你进行两个单独的1字节分配时,它们通常相隔16个字节。在您的中间添加此代码:

malloc()

给出了输出:

    char *buffer[4];
    for (int i = 0; i < 4; i++)
    {
        buffer[i] = (char *)malloc(1);
        printf("buffer[%i] = %p\n", i, buffer[i]);
    }

在循环中每次请求16个字节时,我也得到了相同的输出。那很有意思;这意味着没有与这些内存块直接相邻的控制信息(这些分配之间没有控制信息的空间 - 它可能存储在buf1 = 0x7fe821c000e0 buf2 = 0x7fe821c03a00 distance = 0x3920 bytes buffer[0] = 0x7fe821c03a10 buffer[1] = 0x7fe821c03a20 buffer[2] = 0x7fe821c03a30 buffer[3] = 0x7fe821c03a40 before overflow buf2 = AAAAAAAAAAAAAAA Abort trap: 6 buf1之间的某些空间中。在其他64位系统上,我看到最小分配为32字节,其中一些空间用于控制信息。也就是说,来自buf2的1个字节的连续请求的地址将产生相隔32个字节的地址,但是对32个字节的连续请求将产生相隔64个字节的地址。

在32位Linux机器上,我有1个字节和8个字节的请求,我得到了分配:

malloc()

对于16字节的请求,我得到了:

buffer[0] = 0x804a008
buffer[1] = 0x804a018
buffer[2] = 0x804a028
buffer[3] = 0x804a038

如您所见,在第一种情况下,分配相隔16个字节;在第二个,24个字节。额外的8个字节是控制开销。

当您请求N个字节的空格并且buffer[0] = 0x804a008 buffer[1] = 0x804a020 buffer[2] = 0x804a038 buffer[3] = 0x804a050 返回指针P时,您有明确的权限来访问地址范围中的数据:

malloc()

该范围之外的任何访问都会导致未定义的行为。未定义的行为可能包括似乎正常工作。


在第一个程序中,执行 (char *)P + 0 .. (char *)P + N - 1 (inclusive) 而不初始化system(command)指向的数据。这不太可能带来幸福。