试验目标:
在把握栈帧构造的根底上,学习栈溢出破绽的基本原理。
实现性能:
在函数的栈帧中,局部变量是顺序排列的,栈帧中还保留前栈帧 EBP 及返回地址 RET 等信息。结构 password.txt。
使得 str 在读取该文件后恰可能笼罩 fun 函数的返回地址,从而运行 attack 函数。
试验代码:
#include <stdio.h>
void attack(){printf("Attacked!\n");
exit(0);
}
void fun(){char password[6]="ABCDE";
char str[6];
FILE *fp;
if(!(fp=fopen("password.txt","r"))){exit(0);
}
fscanf(fp,"%s",str);
str[5]='\0';
if(strcmp(str,password)==0)
printf("OK!\n");
else
printf("NO!\n");
}
int main()
{fun();
return 0;
}
试验后果和剖析:
- 设置程序断点
- 让程序运行到断点处进行,这时候查看 main()函数栈的 ebp 指针的值
能够看到 ebp 指针的值是 0x6dff08 - 这时候让咱们跳进 fun()函数中去,同时查看 fun()函数栈中 ebp 指针的值
- 这时候关上内存,查看 fun()的 ebp 指针指向的值
能够看到 fun()函数栈中 ebp 指针指向的值是 main()函数栈中 ebp 指针的值,因为栈的增长方向是从高地址向低地址增长的,ebp 指针紧挨着的高地址地位是函数栈的返回地址。咱们就能够晓得 fun()函数的返回地址是 0x401410,要使得 fun()函数返回时胜利地跳到 attack()函数处去,就得把 fun()函数的返回地址笼罩为 attack()的函数地址,这样能力实现跳转。 - 让咱们查看下 attack()的函数地址
能够看到 attack()函数的地址是 0x401350 - 接着让咱们查看下 str 数组的地址
从 fun()函数的 ebp 地址到 str 数组地址两头相差了 0x6dfef8 – 0x6dfee0 共 24 个字节,存储返回值的地址到 ebp 地址两头又相差了 4 个字节。返回地址的长度是 4 个字节,所以从 str 数组开始到齐全笼罩返回地址须要输出 32 个字节的数据。
前 28 个字节轻易输出,后 4 个字节为 attack 的地址。 - 实现输出后,咱们始终点击 next line 让程序往下执行
能够看到胜利地从 fun()返回后跳到了 attack()函数处,持续执行程序。
胜利了!