课堂作业
(谨慎参考,我也不知道对不对,不对我再来改)
实现一程序,分别在Windows、linux操作系统下验证:
- 栈、堆、数据区是否可读可写不可执行
- 代码段是否可读可执行不可写
Windows
栈可执行
没有输出return,说明溢出把printf("foo return");
覆盖了。
没有溢出,返回地址给了buf,还是执行了printf("foo return")
; 。。。。??(不理解)
堆不可执行
返回值异常,没有执行heap;
数据段可执行
执行了指令0xFEEB,但是不知道是什么指令;
代码段不可写
修改一下代码段的内容,试试能不能成功
修改失败, printf("f = %d \n",f);
没有运行,证明没法写代码段。
1.用计算器进行换算,3221225477=0xC0000005
2.进行搜索,NTSTATUS 0xC0000005,得到:STATUS_ACCESS_VIOLATION也就是我们熟知的糟糕的翻译。
该内存不能为’read’
该内存不能为’written’
对应的错误。
知乎:https://www.zhihu.com/question/397800014/answer/1250693169
综合成一个程序
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
unsigned int a=0xFEEB;
void foo()//stack
{
unsigned int i;
char buf[10];
strcpy(buf,"ABCCDEFG");
printf("buf is %s\n",buf);
*(&i+2) =(unsigned int)buf;
}
void h()//heap
{
unsigned int i;
char *p;
p = (char *)malloc(sizeof(char)*10);
strcpy(p,"string");
printf("p = %s\n",p);
*(&i+2) = (unsigned int)p;
free(p);
}
void f()//data
{
unsigned int i;
printf("i = %d\n",&i);
*(&i+2) = (unsigned int)&a;
}
void c()//code
{
int i=3;
printf("i = %d\n",i);
}
int main()
{
printf(" Which one do you want to try?\n");
printf("1.Can the stack segment execute?(If it prints return, it can be executed)\n");
printf("2.Can the heap segment execute?(If it prints return, it can be executed)\n");
printf("3.Can the data segment execute?(If it prints return, it can be executed)\n");
printf("4.Can the code segment write?(If it prints f = .., it can be writen)\n");
int num;
scanf("%d",&num);
switch(num)
{
case 1:
foo();
printf(" return");
break;
case 2:
h();
printf(" return");
break;
case 3:
f();
printf(" return");
break;
case 4:
*(int *)f =9;
printf("f = %d\n",*(int*)f);
break;
}
}
linux
栈不可执行
传的数组太大的时候,程序崩溃了。。。。。
传小一点的
数据比较少,也没有输出 return,所以我感觉它准备去执行栈了,但是有异常,终止了,所以不能执行栈。
堆不可执行
也没有输出 return,有异常,终止了,所以不能执行堆。
数据段不可执行
报错。
代码段不可写
windows下可以执行堆栈、数据段,但是有ASLR(Address space layout randomization),是一种针对缓冲区溢出的安全保护技术,通过对堆、栈、共享库映射等线性区布局的随机化,通过增加攻击者预测目的地址的难度,防止攻击者直接定位攻击代码位置,达到阻止溢出攻击的目的。
不保证对哈,仅供参考,我也没学好。。。。