栈破坏的分析

在程序运行中,栈主要用来保存局部变量,函数参数,函数调用的返回地址以及栈底。以x86为例,与栈关系比较大的几个寄存器主要是:

ebp:基址指针寄存器(extended base pointer),其内存放着一个指针,该指针永远指向系统栈最上面一个栈帧的底部

esp:栈指针寄存器(extended stack pointer),其内存放着一个指针,该指针永远指向系统栈最上面一个栈帧的栈顶

eip:指令寄存器(extended instruction pointer),其内存放着一个指针,该指针永远指向下一条等待执行的指令地址

在函数的一层层调用过程中每个函数都会有自己的一段栈,一般把它叫做函数的栈帧。每个函数的栈帧都保存了自己的局部变量,自己栈帧底的值,返回地址以及上一次函数的参数。这样文字描述比较抽象,下面用一个例子和图表来说明。假设程序中函数的调用关系是:funcA调用funcB,funcB调用funcC,funcA->funcB->funcC,用伪代码来表示就是:

funcC()
{
.....
}

funcB()
{
...
  funcC();
...
}

funcA()
{
...
  funcB();
...
}

那么这个调用关系的函数栈帧就可以用下面这个图来大致描述:

从这个图上可以看到,首先栈是从高地址往低地址延展,所以funcA在上面高地址处,funcC在低地址处。每个函数栈帧的结构都差不多,这里主要就是要说明一些图片里面的:返回地址,保存的ebp。返回地址指的是被调用函数的返回地址,保存的ebp是指自己的栈帧底部的值。已funcB为例,返回地址就是funcC返回到funcB的地址,保存的ebp就是funcB的栈帧底的值。

程序在正常运行中,就是通过这样的方式保存了每个函数的现场,当返回的时候就可以恢复如初。如果程序运行过程中出现错误导致crash,我们也可以使用gdb工具通过分析coredump文件,查看函数调用关系来确定问题出现的范围。但是如果函数的栈帧被破坏掉了,就是返回地址核保存的ebp值出错,这样gdb是没办法获取函数的调用关系,也就无法确定问题的大致范围,会造成问题难以处理。不过如果好好的理解上面这个函数栈帧图后,还是可以通过自己手动去分析。下面具体看下分析的过程。

下面这个是测试用的源码:

char names[] = "book cat dog building vegetable curry";
  
void func(void)
{
    char buf[5];
    strcpy(buf,names);
}

int main(void)
{
     func();                                                                                                                                                             
     return 1;
}

 这个函数是使用了strcpy的一个漏洞,通过names里面的值把函数的栈帧全部给填充了,造成栈帧破坏。
下面先编译这个程序:

gcc -g -fno-stack-protector -o stack_test stack_test.c  #这里关闭了栈保护,来模拟堆栈完全破坏的情况

运行程序后,会coredump,产生core文件,使用gdb加载coredump文件和可执行文件。可以看到,栈被破坏都无法显示调用关系了,所以也就无法确定问题出现的情况。

看下寄存器的信息

可以看到,ebp和esp的值都不是太对,按道理ebp应该和esp不会差太多,eip表示的是代码执行地址

按照x86 ELF文件的布局,正常应该在0x08040000附近

根据函数调用栈的关系,可以知道调用函数的时候会将ebp和返回地址压栈,函数返回的时候,会先将ebp弹出,然后弹出返回地址给eip,eip就是pc指针,cpu就会跳转到eip保存的地址里面去。这里正是因为eip的值不正确,导致程序异常退出了。我们知道,栈的方向是从高地址向低地址方向生长,而数据是从低地址向高地址,所以栈被破坏应该是从某个地址往高地址方向,也就是外层函数的栈被破坏了,但是正在执行的这个函数,有部分栈并没有被破坏,是有可能寻找到一些信息的。

将esp前面的一段内存输出,看看情况可以看到这段内存里面,按照地址从高到低,保存了eip和ebp的值,同时可以看到红框的两个地址,很明显是代码的执行地址(0x0804xxxx),可以看下这两个地址的代码是什么

 

先看看0x0804a040

可以看到,没有反汇编出函数名

下面看看0x08048422地址

可以看到,反汇编出函数名为:func,然后就可以定位到问题,应该就在func函数里面。

 

 

 

 

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值