开头
上一篇博客讲到了栈溢出,关于做栈溢出实验,可使用的工具是反汇编工具。
之前讲到了IDA的实现:
感兴趣的也可以看看。
~
现在说到老师上课可能更喜欢用的反汇编软件OllyDbg,来实现一下简单的栈溢出实验。
~
软件介绍:OllyDbg
摘自百度:
<<<OD,是一个反汇编工具,又叫OllyDebug,一个新的动态追踪工具,将IDA与SoftICE结合起来的思想,Ring 3 级的调试器,己代替SoftICE成为当今最为流行的调试解密工具了。同时还支持插件扩展功能,是目前最强大的调试工具。基本上,调试自己的程序因为有源码,一般用vc,破解别人的程序用OllyDebug。>>>
~
~~下面简称OD
~
IDA与OD
~
说简单点,OD是一款火爆的反汇编工具,免费也是其特点,优点可能对电脑环境要求并不高,缺点是其运行很复杂,函数名之类的信息不清晰,等于要自己找。
IDA相比于OD,更加方便,这点可以从我上一篇博客看出,同时IDA操作简单,但要付费。即使其破解版在机房的电脑上一般不好运行,所以导致学校老师教学一般用OD。这里开讲,怎么用更复杂的OD(ollydbg).
~
1.打开软件
可以清楚看到界面:
看到很多框体,再细看一下:
2.准备好要运行的程序
即准备好实现栈溢出的代码,和上一篇博客代码一样,可以对比:
~
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void attack()
{
printf("This is attack.\n"); //attack函数
}
void func() //func函数
{
char password[6] = "ABCDE";
char str[6];
FILE *fp;
if(!(fp=fopen("D:\\password.txt","r"))) //打开D盘的password.txt文件
exit(0);
fscanf(fp,"%s",str); //将str的内容写入fp
str[5]='\0';
if(strcmp(str,password)==0) //判断str是否与password相同
printf("OK.\n");
else
printf("NO.\n");
}
int main()
{
func(); //运行func函数
return 0;
}
~
同样上面的fscanf函数是导致栈溢出的问题所在,也就是说当fscanf读取了大于str容量的字符串,导致了其数据在栈上的溢出,从而影响函数的正常运行。
类似的,像gets,strcpy等函数,当读取比设定的容量大时,都会发生栈溢出。
~
注意:
~
为防止栈溢出漏洞出现,最近的vs系列,vs2018,2019等都会提醒不要使用不安全的函数,而使用安全的会进行边界检查的函数。所以栈溢出实验无法在vs系列上实现。
~
vc 6.0 和 codeblocks上依旧可以进行栈溢出实验。可以在这两个编译器上实现该实验。
3.代码运行
在记事本中输入AAAAAA…运行程序,由于其与password不同,所以输出“NO”
4.OD开始反汇编
将该程序的可执行文件拖入OD:
出现了很多复杂的数据。其实现在只需要关注左上角的区域即可:(放大来看)
1,首先看左边红色区域:大家应该很熟悉,这是16进制码
2,中间蓝色的区域:这是汇编代码,学过汇编的人看得出来。
3. 右边紫色框选的区域:可以看作为伪代码,(个人认为)可以看到出现了一些程序中有的字符串和一些类似的细节。
~
相当于中间是汇编代码,即该exe文件转换为的汇编代码,左边是该行对应的16进制代码,右边是伪代码。
~
这里和IDA的分析结果一样,都通过反汇编,让你得以查看可执行文件的汇编代码和伪代码,当然也能查看栈。
~
IDA是分散的框体。而OD把其放在了一起。
~
这里就要说到IDA的函数名很方便查找,而OD得函数名只能自己从上表中分析,甚至没有明确的函数名。
~
但是
~
OD可以进行动态调试,而IDA只能静态,这是截然不同的,但又相互联系。
重要:OllyDbg的相关快捷键
这个是很重要的OD的操作快捷键,其实更多的功能,自己可以试出来,这里只说必须的:
~
(1)F2(左键双击):设置断点
~
双击或F2的位置变红了,当程序再运行时,会自动运行到断点处,则不会再往下运行。用于动态分析查看。 再按F2取消断点。 或者点击右键选择–>breakpoint–>toggle.
~
(2) F7,选中的区域向下,但碰到子程序时会进入其中,可以查看子程序信息。
~
(3) F8,单纯地向下一个信息移动。
~
(4)Ctrl+F12, 即为"restart"重新开始运行程序, 但会在断点处停住:
(5)F9 继续运行函数,直至断点:
4.开始分析如何“栈溢出”
这个框体里的内容很多,向下滚轮,在最右边的伪代码中寻找与代码有关的内容,人看的懂的内容。在往下滚时,看到了"this is attack","password"字样,说明找到了func()和attack()函数(见下图)
那么下图框选的"PUSH EBP"应该是attack(),func()函数的开头,记下函数入口地址:
~
attack()地址: 00401350
func()函数地址:00401365
~
再稍微往下一划,看到"fopen,fscanf"等函数,以及"OK"和"NO"的代码区
栈溢出发生在fscanf函数处,不如在fscanf下,strcmp之上,设置一个断点,再次运行后,函数会停在那里。
之后,按“F7”向下运行,碰到子程序,就会自动进入子程序。果然在"004013D1"处发生了跳转,其汇编代码中CALL也是一种跳转的代码。查看到了str所在的栈。
注意:在这里设置一个断点
5.看到栈的信息
可以看到文本文件输入的"AAAAA…“在栈道中一目了然:
这里就是OD中栈的信息:
~
该结构与之前的类似:
左边的"41414141"是16进制,中间的“AAA”是你输入的字符串,右边类似伪代码
~
当你在文本中输入不同数目的A时,你会发现A是从上往下增长的,输入不同的A,然后restart重新运行,再按F9 .
~
A明显从“0060FEE0”处往下增长,
~
在栈中看到(下图)在“0060FEFC”处存的是"RETURN from"函数,可以得知函数运行到此处时会进行跳转,这就是所谓的"ret”,跳转地址。
~
在上图可以看到“RETURN”右边的地址为“00401407”说明函数运行到这里会跳转到“00401407”,从“RETURN…”一串英文的意思也可以看出。那么只要将文本中输入的A的数量增加,那么,A就会覆盖其正确的地址。
~
“0060FEFC”处存放了要返回的地址,而其上面就是文本输入的A,A往下溢出会影响其地址。
~
因为A会往下堆积,溢出到“RETURN ”处,只要将A们的最后四位改成其他地址,那么函数就会跳转到别的地方。
~
6.修改文本,制造栈溢出
从上图看出从开头的地址到跳转地址有7行,即28个十六进制。
~
那么,在文本中先输入28个A,再加入attack()函数的地址,返回地址就会被覆盖。
~
用HxD进行编辑:
编译后,再用OD,Ctrl+F2,重新来过,不停按F9,来到这里:
可以看到原本的“0060FEFC”即返回地址,已经变成了,attack()函数的入口,上面全是AAAAA,而这地址就是刚刚输入的。
~
再看看函数的运行结果:
果然
~
7. 结果
成功了。原理与上次的一样,有点复杂,大家想的话可以细看。感谢阅读。
来源:oschina
链接:https://my.oschina.net/u/4411125/blog/4673223