这是开头

事情起于19级某份代码(代码的主人说求放过,所以这里就不贴出来了)出现了一个字符串的问题,这个问题本身也比较有意思,所以就有了这篇水贴

这是正文

先给个样例:

/* try with: gcc -m32 -Og -g ./test.c */
#include <stdlib.h>
#include <stdio.h>

char* str1 = "Hello1";
char str2[] = "Hello2";
int main(){
    char* str3 = "Hello3";
    char str4[] = "Hello4";

    char* str5 = (char*)malloc(sizeof(char)*8);
    for(int i=0;i<7;i++) str5[i] = str4[i];
    str5[5] = '5';

    printf("%s\n",str1);
    printf("%s\n",str2);
    printf("%s\n",str3);
    printf("%s\n",str4);
    printf("%s\n",str5);
    return 0;
}

上面代码只是用五种不同的方式创建了五个不同的字符串,打印出来的结果看上去没有什么差异,但其实这几个字符串是放在不同的地方的,而且有不同的特性(多图预警,特别留意地址)。

首先str1和str3(指向的东西)算是同一类型的,都是拿个指针指向一个字符串常量,这里常量的意思是这个字符串是不可被改变的,原因是它们被放在了.rodata(read only data)段,这个位置的东西都是只读不可写的。要注意的是只是str1和str3指向的字符串是放在.rodata,str1和str3这两个指针本身还是放在不同地方的。

str2算是第二种类型——全局变量,和上面的不同,它是可写的,因为它被放在了.data段(另:带初值的全局变量都会被放在这个段,没初值的全局变量会被放在一个叫.bss的段,而且初值被设为0)。

上图可以看到,.data段里除了str2这个字符串外,还存这str1这个指针,因为str1也是全局变量,下图的".WUV"就是str1指向的地址(little-endian)。

另给一下str3的图,可以看到"Hello1"和"Hello3"是相邻的(只是这份代码是相邻的,其他我不敢保证)。

str4和str2类似,放的地方不同,从地址就可以看出来距离隔了很远,str4被放在了一个叫栈(stack)的地方,栈的话其实可以吹很多东西,简单来说就是局部变量(local variable)会被放在这里。

最后的str5从代码上都可以看出它是异类了,特点是str5指向的地方是用malloc分配的,只要分配的大小不是非非非常大,malloc分配的空间都在堆(heap)上,从图来看会觉得str5的地址跟str1的差不多,但其实只是heap被放在了.rodata隔壁而已。

总结

ctf新生赛快开始了,欢迎报名~ !
(虽然我上个月就是这么说的。。。)

    Tover 建议把看地址所需的命令或指南给出,毕竟是给新生看。他们可能不懂dbg。我看很多大二的现在也不懂。

      Tover 建议水一篇关于程序的heap、stack等内存分布的帖子。我曾经多次在大三的课堂上提问,大部分同学没有相关概念。不知道现在有否改变?

        Bintou 虽然🉑,但感觉自己怎么水都不会有ctf-wiki讲的详细😂,而且这两块涉及的东西太多了,也不太好讲,特别对现在19的(18 csapp讲到的话应该可以水一下)

        © 2018-2025 0xFFFF