以后的文章可能都会发在github博客上了,现在暂时还懒得弄域名和服务器。地址:http://jameeeees.github.io/
下面是一段包含缓冲区溢出的代码:
#include <iostream>
using namespace std;
void attacker()
{
cout<<"Attacker is running."<<endl;
exit(0);
}
void leak_func(char *str)
{
char local[4];
int i;
for (i = 0; str[i] !=0; i++)
{
local[i] = str[i];
}
}
int main(int argc, char* argv[])
{
intattack_data[10];
cout<<int(attacker)<<endl;
cout<<int(leak_func)<<endl;
cout<<int(main)<<endl;
attack_data[0] = 0x41424344;
attack_data[1] = 0x41424344;
attack_data[2] = (int)attacker;
leak_func((char *)attack_data);
return 0;
}
该程序的运行结果如下:
可以看到,主函数中并没有调用attacker这个函数,但是在运行时却看到了attacker这个函数在运行,这就是我通过构造缓冲区溢出来实现的。原本子函数leak_func()运行完之后应当返回主函数并执行下一条语句,此时我却通过溢出覆盖了子函数的返回指令,而且通过计算使得原本返回指令的位置被attacker函数的首地址所覆盖。那么程序就直接运行到了我精心构造的位置,假如这个位置是一段恶意代码,那么造成的损失是难以估量的。
下面我将针对上述代码手工构造一个栈来解释缓冲区溢出问题的原理。
首先,我们可以从上图的运行结果中写出三个函数各自的首地址(十六进制):
Attacker:0x4013EE;leak_func:0x401421;main:0x401458。
程序开始时,我们先为数组attack_data[10]申请空间,由于是int型,所以共申请了40个字节的空间。然后我们开始对前三个数组成员赋值,此时的栈大概如下所示:
ESP |
41 |
42 |
43 |
44 |
41 |
42 |
43 |
44 |
00 |
40 |
13 |
EE |
……此处为剩余的七个未赋值数组成员 |
EBP |
注:每个内存单元为一个字节,此处EBP和ESP应占两个内存单元,为了简化所以并未画出。
接下来就要进入leak_func()函数了,在该函数中,我们只开辟了一个char型的,有四个数组成员的函数。因为char型数据只占一个字节,所以整个数组的大小为4字节,而我们之前所输入的3个int型的参数占了12个字节。很明显,我们所申请的数组空间不足以存放我们传入的参数,系统会将我们的int型参数分割成4个char型放入数组中。当子函数开始时,我们的编译器会在内存中再开辟一个栈帧,根据代码,开辟的栈帧如下:
ESP |
Local[0] |
Local[1] |
Local[2] |
Local[3] |
这里代表四个内存单元,存储着整型变量i |
EBP |
返回地址(EIP...) |
从这里我们可以看到,local数组占了4个内存单元,正好存储了attack_data[0],接下来就出现了溢出,整型变量i被attack_data[0]所覆盖.EBP是栈底指针,占16位,EIP存储着返回主函数的地址,也占16位,可是此时EBP和EIP已经被参数attack_data[2]所覆盖,丢失了返回主函数的地址,而且,此时EBP与EIP中存储的是函数attacker的首地址,所以该函数结束后并不返回主函数,而是直接前往了attacker函数。设想一下,假如attacker函数是一段恶意代码,那么你的计算机就很有可能已经被人控制了。
人们为了防止缓冲区溢出攻击已经做出了很多努力。比如让编译器去检查有没有溢出情况,但是让编译器去做这件事意味着牺牲C++最引以为傲的效率,所以我认为这块工作还是要交给程序员去完成。还有就是内存地址随机化的方式。假如内存地址随机化的话,我上面写的那个程序就起不到效果了,因为我没法提前去预知内存中函数地址的情况。据我所知,Linux系统已经完全内存地址随机化了,每次运行程序时,程序所在的内存地址都不相同,而且我在自己的虚拟机下测试了,结果的确如此。而Windows下似乎并没有应用这一技术,我连续运行发现地址都相同,而且重启之后的内存地址也相同,这也是Linux比Windows安全的一大证据吧。当然了,高级的病毒都是利用各种系统文件作为跳板来执行它想要执行的代码的,令人防不胜防。
虽然我们想了各种办法来抵御缓存区溢出攻击,但是黑客们总能想到办法来破解,更何况现在安全并没有被大部分人所重视起来。
希望大家看完能有所收获 欢迎指正!!