[超详细]栈溢出漏洞原理实例讲解
本篇文章通过《0day安全:软件漏洞分析技术》书中第二章中所用到的一个程序的栈溢出漏洞的复现,以及使用OD一步步调试来学习栈溢出完整的原理。程序虽然简单,但在一些基础薄弱的人眼中还是无法理解,所以导致很多新手到了这里就被“劝退”。 所以在这篇博客中我会差不多一句一句的解释汇编代码的意思,一步一步的看栈的变化,即使遇到一些“常识”我也会进行介绍,来帮助理解栈溢出漏洞
使用软件:
- vc++6.0 (用来编译程序)
- OllyDbg
- 十六进制编辑软件
代码简介
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define PASSWORD "1234567" //写入静态密码
int verify_password(char *password)//确认密码是否输入正确
{
int authenticated;
char buffer[8];
authenticated=strcmp(password,PASSWORD);
strcpy(buffer,password); //存在栈溢出的函数
return authenticated;
}
void main()
{
int valid_flag=0;
char password[1024];
scanf("%s",password); //输入密码
valid_flag=verify_password(password);
if(valid_flag) //返回0代表正确,返回1代表错误
{
printf("incorrect password!\n");
}
else
{
printf("success\n");
}
getchar();//暂停一下
}
运行结果如下:
好,接下来开始演示栈溢出的原理。
分析程序整体执行流程
首先使用Debug编译器(最好不要使用release编译器),Debug和Release编译后的程序的区别就是,在调用一些系统函数的时候,Debug会保留调用点,而转去系统函数所在地继续执行;而Release会直接将系统函数粘贴过来,不用实现调用便可完成。使用Debug能更直观看出函数执行到了什么位置。使用OD打开编译好的.exe文件。
典型的VC编译的程序的样子,但程序的入口点并不是main函数的入口点,接下来我们要找到main函数,有两种方法:
-
单步跟踪(F8),在遇到call调用的时候使用F7跳转到跟踪函数内部,直到进入(我们可以判断出是)main函数的地方,如:
-
根据“常识”,在GetCommandLineA后不远处就是main入口,在main之前会有(三个)连续的压栈操作,如:
找到main函数之后,F7跟进main函数里,继续分析:
如图所示,根据左侧ASCII码的提示,和代码中调用系统函数的名字,我们很轻易的找到了scanf函数的位置,按从右至左的顺序将参数(password就是[local.2