栈溢出逆向实验
一、实验背景
1.内存的不同用途
缓冲区溢出是在大缓冲区中的数据向小缓冲区复制的过程中,由于没有注意小缓冲区的边界,“撑爆”了较小的缓冲区,从而冲掉了和小缓冲区相邻内存区域的其他数据而引起的内存问题。缓冲溢出是最常见的内存错误之一,也是攻击者入侵系统时所用到的最强大、最经典的一类漏洞利用方式。成功地利用缓冲区溢出漏洞可以修改内存中变量的值,甚至可以劫持进程,执行恶意代码,最终获得主机的控制权。要透彻地理解这种攻击方式,我们需要回顾一些计算机体系架构方面的基础知识,搞清楚 CPU、寄存器、内存是怎样协同工作而让程序流畅执行的。
根据不同的操作系统,一个进程可能被分配到不同的内存区域去执行。但是不管什么样的操作系统、什么样的计算机架构,进程使用的内存都可以按照功能大致分成以下 4 个部分。
(1)代码区:这个区域存储着被装入执行的二进制机器代码,处理器会到这个区域取指并执行。
(2)数据区:用于存储全局变量等。
(3)堆区:进程可以在堆区动态地请求一定大小的内存,并在用完之后归还给堆区。动态分配和回收是堆区的特点。
(4)栈区:用于动态地存储函数之间的调用关系,以保证被调用函数在返回时恢复到母函数中继续执行。
2.栈
从计算机科学的角度来看,栈指的是一种数据结构,是一种先进后出的数据表。栈的最常见操作有两种:压栈(PUSH)、弹栈(POP);用于标识栈的属性也有两个:栈顶(TOP)、栈底(BASE)。可以把栈想象成一操扑克牌。
·PUSH:为栈增加一个元素的操作叫做 PUSH,相当于在这螺扑克牌的最上面再放上一张。
·POP:从栈中取出一个元素的操作叫做 POP,相当于从这操扑克牌取出最上面的一张。
·TOP:标识栈顶位置,并且是动态变化的。每做一次 PUSH 操作,它都会自增 1;相反,每做一次 POP 操作,它会自减 1。栈顶元素相当于扑克牌最上面一张,只有这张牌的花色是当前可以看到的。
·BASE:标识栈底位置,它记录着扑克牌最下面一张的位置。BASE 用于防止栈空后继续弹栈(牌发完时就不能再去揭牌了)。很明显,一般情况下,BASE 是不会变动的。内存的栈区实际上指的就是系统栈。系统栈由系统自动维护,它用于实现高级语言中函数的调用。对于类似 C 语言这样的高级语言,系统栈的 PUSH、POP 等堆栈平衡细节是透明的。
一般说来,只有在使用汇编语言开发程序的时候,才需要和它直接打交道。
二、实验目的
探究发生栈溢出的原因以及导致的后果。
三、实验内容
1.IDA 静态分析
首先打开 IDA,将.exe 文件拖入 IDA,找到 main 函数,按快捷键 F5 查看其伪代码,如图。
再查看 verify_password 函数,如下图。
通过以上对伪代码分析可以对该程序有一个初步的认识。
2.ollydbg 动态分析
将程序拖到 od 中打开,找到 main 函数。
根据“常识”,在 GetCommandLineA 后不远处就是 main 入口,在 main 之前会有(三个)连续的压栈操作。
找到 scanf 函数。
进入函数,首先看见的就是常规操作,将前栈基址入栈,抬高栈顶(给局部变量申请空间),之后可以看到在调用 strcmp 函数之前将他的两个参数从右至左入栈,静态值“1234567”是写在程序的数据段中的,另一个是参数 password,在第一个(只有一个)参数即[arg.1]位置。strcmp 执行结果在 eax 寄存器中,然后将结果赋值给变量 authentication,即第一个变量,就是[local.1]位置(图里不小心画到 strcpy 参数入栈里了)。然后进行 strcpy 函数的参数入栈,从右至左是 password 和 buffer,buffer 就是第二个参数(因为长度是 8,所以[local.3]),将他们入栈之后调用 strcpy,将 password 内容拷贝到 buffer 里。然后(进行清理栈空间操作后)返回。
回到 IDA,点击 verify_password 中的 dest
看一下 Dest 在 ebp-0xC 的地址空间,而用于返回的临时变量是在 ebp-0x4的栈空间,这样如过复制的内存长于 8 个字节,则会溢出一个\x00 字节到临时变量的空间,因为 strcpy 会在复制后补上一个\x00 结束符。strcmp 函数的返回值有 0,1,-1 三种情况。
1.如果是 1,溢出的\x00 刚好覆盖了最后一个字节,使得临时变量变为 0。
2.如果是-1,由于是负数,有最高位符号位的存在,是无法变成 0 的。
这里就会出现栈溢出。栈溢出就是指栈中的(缓冲区)内容被写入了大于原本(申请的)大小的内容,导致多余的内容覆盖了缓冲区后面的其他地址空间内原有的内容。
打开程序测试:
可知需要输入的密码长度等于 8,并且与 1234567 的 strcmp 结果是正数即可通过测试