C语言实现缓冲区溢出实例
2015-06-05 15:58
585 查看
参考书目:0day安全:软件漏洞分析技术
相关工具使用:OD,IDA Pro,VC++6.0,UltraEdit
最近需要做课堂演习,就选了缓冲区溢出的实践。主要参考0day安全这本书,一面一句话很经典:
To be the apostrophe which changed Impossible into I’m possible!
直接步入正题:
代码就是简单验证输入密码是否正确,首先用IDA打开编译生成的应用程序。看到这样一个图(好像每次打开生成的东西都不太一样~)
如果看不到地址可以在Options->General在Line prefixes前打钩以及将Number of opcode bytes设置为6就可以了。这样就可以找到代码中相应的跳转部分,然后用OD打开对应的EXE文件,看到下图:
找到004010D5这条命令就是对应的判断地方了,对应的汇编命令为:
于是将JE改成JNE,再运行程序,这时发现原来正确的密码不正确,原来错误密码都可以通过!用OD还可以对程序保存,一个简单的破解就完成了。(OD保存软件不会的话可以网上搜一下,我当时没搞懂还是请教的大神)
啊,原来是这样啊,输入qqqqqqqq,或者输入其他8位也行(11111111不行,自己探索吧)在strcmp的时候auth确实是1,但是在进行strcpy之后,buffer里面的数据太长了,占了auth的位置,将auth从1改成了0。
看来下次写程序要注意点了!
事实上,EBP是PE文件执行时候在函数调用时函数调用前栈底指针,在函数调用时会重新生成一个比较小的栈,此新栈为调用的函数所用,因此需要将之前栈的栈底入栈。在调用新的子程序的时候,也需要将子函数的返回地址入栈,不然子函数执行完了,计算机就不知道下一步执行什么了~
搞懂了这点知识,我们就可以利用这个来修改程序的执行流程了,具体实验可以自己做。
此次的实验中由于控制台输入的限制性,将输入流改为文本。实验的目的是利用缓冲区溢出漏洞植入代码,代码内容为弹出一个新的窗口。
上面是MessageBox的四个参数,如果弹出标题和内容都是hellobug的串,四个参数分别为:
NULL, “hellobug”, “hellobug”, NULL
根据MessageBox得到应该执行的汇编代码
最后的Address是MessageBoxA地址,对应的机器码如下:
因为缓冲区有44个字节,而四个字节一组,因此有11组,加上原来的auth,EBP和返回地址,一共14组,每组4个字节。新建一个这样的文件。
我在执行的过程中最后部分0018FD44就是Buff的起始地址。
接下来的问题就是buff的起始地址以及MessageBox的入口地址怎么找到呢?
首先是buff的起始地址,这个比较简单,将该文件写为14组1234,然后在OD里面跑一遍之后可以看到内存里面的数据,这个数据区的起始地址就是就是buff的起始地址。
然后是MessageBox的入口地址,在0Day安全这本书中有计算过程,我按照这个过程没有实现,因此我自己找了一个方法,有兴趣的同学可以按照书上的计算一下~
我的试验工程就是新建一个工程,只允许Messagebox然后通过OD查看其入口地址
写这样一个简单的程序用OD打开以下就好啦
找到MessageBox回车之后就进入了,从这个图可以看出入口地址是768EFD1E
然后整个文件就***完成了,运行一下看看吧
以上就是一个简单的缓冲区溢出的实例了,不过在植入代码这个过程中电机确定之后~~就挂了,因为一些参数没有设置好,慢慢再深入研究吧。
相关工具使用:OD,IDA Pro,VC++6.0,UltraEdit
最近需要做课堂演习,就选了缓冲区溢出的实践。主要参考0day安全这本书,一面一句话很经典:
To be the apostrophe which changed Impossible into I’m possible!
直接步入正题:
1. 反汇编修改程序
在实现缓冲区溢出之前,简单熟悉一下反汇编重用的两个软件,OD和IDA,用OD修改程序代码实例。[code]#include <stdio.h> #define PASSWORD "1234567" int verify(char *password) { int auth; auth = strcmp(password, PASSWORD); return auth; } int main(void){ int flag = 0; char pass[1024]; while(1){ printf("enter the password:\t"); scanf("%s", pass); flag = verify(pass); if(flag) printf("password incorrect!\n"); else{ printf("congratulation!\n"); break; } } }
代码就是简单验证输入密码是否正确,首先用IDA打开编译生成的应用程序。看到这样一个图(好像每次打开生成的东西都不太一样~)
如果看不到地址可以在Options->General在Line prefixes前打钩以及将Number of opcode bytes设置为6就可以了。这样就可以找到代码中相应的跳转部分,然后用OD打开对应的EXE文件,看到下图:
找到004010D5这条命令就是对应的判断地方了,对应的汇编命令为:
[code]JE X1.004010E6
于是将JE改成JNE,再运行程序,这时发现原来正确的密码不正确,原来错误密码都可以通过!用OD还可以对程序保存,一个简单的破解就完成了。(OD保存软件不会的话可以网上搜一下,我当时没搞懂还是请教的大神)
2. 缓冲区溢出漏洞修改邻接变量
还是刚刚的类似程序,假如程序员一不小心或者因为要在其他地方使用字符串,加了个strcpy函数,验证函数如下所示:[code]int verify(char *password) { int auth; char buffer[8]; auth = strcmp(password, PASSWORD); strcpy(buffer, password); return auth; }
[code]看似还是正常的一个程序却会发生不可思议的事情,不信运行程序输入qqqqqqqq试试,发现没,通过验证了!这是为什么呢?来看看栈里面数据的存放:
啊,原来是这样啊,输入qqqqqqqq,或者输入其他8位也行(11111111不行,自己探索吧)在strcmp的时候auth确实是1,但是在进行strcpy之后,buffer里面的数据太长了,占了auth的位置,将auth从1改成了0。
看来下次写程序要注意点了!
3. 修改程序执行流程
是看了上面的原理图,是不是懂了点什么!EBP和返回地址是啥?不禁心生恶意,我要是再长点,是不是把返回地址给换了???还有那个EBP啥东西???事实上,EBP是PE文件执行时候在函数调用时函数调用前栈底指针,在函数调用时会重新生成一个比较小的栈,此新栈为调用的函数所用,因此需要将之前栈的栈底入栈。在调用新的子程序的时候,也需要将子函数的返回地址入栈,不然子函数执行完了,计算机就不知道下一步执行什么了~
搞懂了这点知识,我们就可以利用这个来修改程序的执行流程了,具体实验可以自己做。
4 代码植入
之前例子的缓冲区较小,正常的函数中如果使用的话,缓冲区可能是比较大的,下面用新的例子来测试缓冲区溢出中的代码植入,完整的代码见上传的文件。[code]int verify(char *password) { int auth; char buffer[44]; auth = strcmp(password, PASSWORD); strcpy(buffer, password); return auth; }
此次的实验中由于控制台输入的限制性,将输入流改为文本。实验的目的是利用缓冲区溢出漏洞植入代码,代码内容为弹出一个新的窗口。
[code]int MessageBox( HWND hWnd, // handle of owner window LPCTSTR lpText, // address of text in message box LPCTSTR lpCaption, // address of title of message box UINT uType // style of message box );
上面是MessageBox的四个参数,如果弹出标题和内容都是hellobug的串,四个参数分别为:
NULL, “hellobug”, “hellobug”, NULL
根据MessageBox得到应该执行的汇编代码
[code]Xor ebx, ebx Push ebx Push 68656C6Ch Push 6F627567h Mov eax, esp Push ebx Push eax Push eax Push ebx MOV EAX, ADDRESS CALL EAX
最后的Address是MessageBoxA地址,对应的机器码如下:
[code]33 DB 53 68 6C 6C 65 68 //hell 68 67 75 62 6F //obug 8B C4 53 50 50 53 B8 ADDRESS FF D0
因为缓冲区有44个字节,而四个字节一组,因此有11组,加上原来的auth,EBP和返回地址,一共14组,每组4个字节。新建一个这样的文件。
我在执行的过程中最后部分0018FD44就是Buff的起始地址。
接下来的问题就是buff的起始地址以及MessageBox的入口地址怎么找到呢?
首先是buff的起始地址,这个比较简单,将该文件写为14组1234,然后在OD里面跑一遍之后可以看到内存里面的数据,这个数据区的起始地址就是就是buff的起始地址。
然后是MessageBox的入口地址,在0Day安全这本书中有计算过程,我按照这个过程没有实现,因此我自己找了一个方法,有兴趣的同学可以按照书上的计算一下~
我的试验工程就是新建一个工程,只允许Messagebox然后通过OD查看其入口地址
[code]#include <stdio.h> #include <windows.h> int main(void) { LoadLibrary("user32.dll"); MessageBoxA(NULL, "abc", "def", NULL); return 0; }
写这样一个简单的程序用OD打开以下就好啦
找到MessageBox回车之后就进入了,从这个图可以看出入口地址是768EFD1E
然后整个文件就***完成了,运行一下看看吧
以上就是一个简单的缓冲区溢出的实例了,不过在植入代码这个过程中电机确定之后~~就挂了,因为一些参数没有设置好,慢慢再深入研究吧。
相关文章推荐
- 如何利用VC++构建一个游戏框架
- 杭电2024:C语言合法标识符
- DevC++中使用boost简析
- 小计C/C++问题(1)
- MFC在其他线程中刷新主对话框中EDIT等控件数据
- C++友元函数(有缘分,咋都行!)
- C++多线程编程
- C++ libcurl 使用
- C++容器类和Qt容器类的对比
- 设计模式C++实现(9)——享元模式
- C++运算符重载
- C++类与内存
- 【Reverse Integer】cpp
- VC++ 的this关键字
- Effective C++ 46条 需要类型转换时请为模板定义非成员函数
- 防止资源泄漏
- vector中针对自定义类型的排序
- 一个例子演示了C++异常的推荐用法
- C++ STL 容器自定义内存分配器
- C++ 复制构造函数