代码
#include <stdio.h>
#include <string.h>
// 定义一个函数,接受一个字符指针作为参数
void Challenge(char *str) {
char temp[9] = {0}; // 定义一个长度为9的字符数组temp,并初始化为0
strncpy(temp, str, 8); // 使用strncpy函数复制字符串,最多复制8个字符
printf("temp=%s\n", temp); // 打印temp数组的内容
// 如果temp和"Please!@"相等
if (strcmp(temp, "Please!@") == 0) {
printf("KEY:****\n"); // 打印密钥
}
}
int main(int argc, char *argv[]) {
char buf2[16]; // 定义一个长度为16的字符数组buf2
int check = 1; // 定义一个整型变量check并初始化为1
char buf[8]; // 定义一个长度为8的字符数组buf
strcpy(buf2, "give me key!!"); // 使用strcpy函数复制字符串
strcpy(buf, argv[1]); // 将命令行参数argv[1]复制到buf数组中
// 如果check等于65
if (check == 65) {
Challenge(buf); // 调用Challenge函数
} else {
printf("check is not 65 (%d)\nProgram terminated!!\n", check); // 打印错误信息
}
return 0; // 结束main函数
}
题目
1.main 函数内的三个本地变量所在的内存区域称为什么,它的两个最基本操作是什么?
2.画出buf,check,buf2 三个变量在内存的布局图。
3.应该给程序提供什么样的命令行参数值(通过argv变量传递)才能使程序执行流程进入判断语句 If(check=65),然后调用challenge( )函数。
4.上述代码所存在的漏洞名字是什么,针对本例代码,请简要说明如何修正上述代码
分析
首先我们看到题目先不要怕,从第一题入手,内存区域,那我们是不是要对计算机代码的存储有所了解?
内存区域的划分
根据进程使用的内存区域的预定功能划分,一般可大致分成以下三个部分:
静态数据区
存放全局变量,分为初始化数据和未初始化的数据
动态数据区
存放程序运行时的动态变量,分栈和堆区
栈区(stack segment):用于存储函数之间的调用关系以及函数内部的变量,以保证被调用函数在返回时回到父函数中继续执行。
堆区(heap segment):程序运行时向系统动态申请的内存空间位于堆区,用完之后需要程序主动释放所请求的内存空间。在C/C++中使用malloc或者new等方式申请的空间就在堆区。
代码区
就是放代码的地方
用代码理解
int x;
int y;
#x和y就是全局变量,存放在静态数据区
int main()
{
int a;
int b;
#a和b就是在函数内部的变量,在内存里面存放在动态数据区里面的栈区
int *value;
// 使用malloc分配内存给一个整型变量
value = (int*)malloc(sizeof(int));
free(value);
#value就是存放在动态数据区里面的堆区
}
然后这一串代码,你可以理解为txt文本,是存储在代码区的
解题
第一题分析:
三个本地变量是在函数里面的,所以属于动态数据区里面的栈,我们这里说动态数据区就好了。两个基本操作就是刚刚代码里面的分配存储空间和释放存储空间呗,c语言里面的malloc和free
第二题分析:
让我们画出buf,check,buf2 三个变量在内存的布局图
刚刚说到了栈,什么是栈呢?栈是一种后进先出的数据结构,然后我们的内存是根据我们的声明顺序一个个存储进去的,我们看一下我们的源代码,先后声明了buff2,check,buf,也就是先存buff2
注:我们存储的时候是先从计算机的高地址开始存储,然后到低地址(这里就牵扯到计算机原理了,感兴趣的自己去查)
答案:
高地址 buff2
| check
V buf
低地址
第三题分析:
好了我们现在才开始真正的审计我们的源代码
总结就是,定义一个比较的函数,定义几个变量,main函数传参数,复制到数组里面
ok现在开始讲我们缓冲区溢出的重要部分了
1.我们先往argv[]中的第9个字符传入十进制65
2.然后代码会把我们的字符串传入buf中
3.因为buf的大小只有8,所以传进去的东西是不是溢出了?
4.溢出的内容到哪里了?我们看我们刚刚的内存图,自然就知道是往高地址的地方走了,也就是65把check的值给覆盖了
5.到此我们成功的通过溢出进入了if里面,调用了challenge函数
答案:
往argv[]中的第9个字符传入十进制65
第四题分析:
上述代码所存在的漏洞名字就是缓冲区溢出拉,修正的话我们刚刚能够传大于8的数据进去,不就是因为strcpy的问题嘛,所以要加一个检测边界的功能
至此,缓冲区溢出的漏洞的基本原理讲完了