详情:
① 程序返回地址(EBP+4)的重要性
最近复现漏洞让我乐此不疲,是真的好玩!内心的激动简直无法形容,先来看第一个程序:定义了一个Attack函数,里面有一个死循环;main函数里定义了一个整型数组,大小为5个字节,并且全都赋值为0,也叫初始化;后面将Attack(地址值)这个值赋给 arr[6]。
其中有趣的是主函数中并没有去调用Attack函数去执行,但结果令人意外。这个程序竟然可以运行起来,而且它恰好执行了Attack函数,到底发生了什么呢,一探究竟之。
为了知根知底,需要回到汇编层面去研究它,这里列出整个过程,并配以解释。以下是它的反汇编,下面的演示说明都是基于此;
首先,为了了解程序到底干了什么,逆向一般会一步一步解析代码的执行过程,也就是去画堆栈图;
这也是很多野路子突破上层的限制时,寻找突破口的关键。
第一步,记录原始堆栈结构,EBP(栈底)、ESP(栈顶),将这个图想象成没有盖的杯子
第二步,下图中紫色的地方就是我们所熟悉的缓冲区,像缓冲区溢出攻击也就是针对这个区间的,在逆向中,我们总结的经验是( EBP -4) 以下是局部变量,(EBP + 8) 以上是函数参数;这里是说存储的位置
第三步,局部变量初始化
第四步,从下图中,可以发现用红框标注的地方就是重要的点,它就是 EBP + 4 (函数的返回地址),还记得最开始
程序中的那行代码么? arr[6] = (int)Attack; 就是由于这行代码导致在程序执行的过程中,将Attack函数所在程序的地址
提前压入了堆栈,导致在程序快结束时,由于RETN命令将堆栈里的值弹出来了(RETN的作用如图所示),而且正好就是EIP,即CPU;
这段程序不是随便写的,是特意构造的,简直太巧妙了。
从图中也可以看出来,程序结束后,还是有那么多的东西,其实这就是程序运行后,驻留在内存中的。它会随着
程序的不断运行而将其湮灭;正如徐志摩的诗:轻轻的我走了,不带走一片云彩;对于函数调用而言,悄悄地我走了,留下一堆垃圾
② 探究为什么会有信息安全,它的本质究竟是什么
首先,还是先来看一个程序,先定义了一个常量数组,里面有一堆数据;接下来定义了一个结构指针函数,在这个main函数里将常量数组的地址赋值给了结构函数变量f,先提前说明一下,这里我们着重讨论的是代码 or 数据?
第一步,定位关键函数,地址为 0x423300
第二步,红框中的内容就是常量数据中解析出来的,其实常量数组中的内容就是从代码里抠出来的硬编码而已;
所以它不是数据,而是代码,并且可执行
第三步,尝试在0x423300下断点,弹出了错误,大概意思是这里是数据区而不是代码区不能设置断点,
如果要强制下断,是不会起作用的;其实这里面涉及到一种加壳的思想,比如破解软件最重要的一步就是脱壳,
而如果要对软件做保护就是要将代码隐藏起来,不让分析的人不那么容易找到,从精神上摧垮他,这也是做逆向最难和最好玩的地方
回归主题,对于正向程序员和逆向人员最大的不同在于,逆向的人眼里是没有代码区和数据区之分的,想让它是啥就是啥,
上面就是最好的佐证;所以为什么会有信息安全,它的本质就是CPU不能区分代码和数据。就像世界级黑客大佬所言,现在上层的限制是越来越多,那如何才能突破限制呢?唯有底层而已。