您当前的位置:首页 > 电脑百科 > 程序开发 > 编程百科

如何读懂栈溢出攻击,从这五点入手

时间:2022-03-29 09:12:52  来源:  作者:linux上的码农

什么是栈

  • 简单来说,栈 是一种 LIFO(Last In Frist Out,后进先出) 形式的数据结构。栈一般是从高地址向低地址增长,并且栈支持 push(入栈) 和 pop(出栈) 两个操作。如下图所示:

 

如何读懂栈溢出攻击,从这五点入手

 

 

 

  • push 操作先将 栈顶(sp指针) 向下移动一个位置,然后将数据写入到新的栈顶;而 pop 操作会从 栈顶 读取数据,并且将 栈顶(sp指针) 向上移动一个位置。
  • 例如,将 0x100 压入栈,过程如下图所示:

 

如何读懂栈溢出攻击,从这五点入手

 

 

  • 我们再来看看 出栈 操作,如下图所示:

 

如何读懂栈溢出攻击,从这五点入手

 

更多linux内核视频教程文档资料免费领取后台私信【内核】自行获取.

如何读懂栈溢出攻击,从这五点入手

 

Linux内核源码/内存调优/文件系统/进程管理/设备驱动/网络协议栈-学习视频教程-腾讯课堂

栈帧

  • 栈帧,也就是 Sack Frame,其本质就是一种栈,只是这种栈专门用于保存函数调用过程中的各种信息(参数,返回地址,本地变量等)。
  • 栈帧 有 栈顶 和 栈底 之分,其中栈顶的地址最低,栈底的地址最高。SP(栈指针) 就是一直指向栈顶的。在 x86 的 32 位 CPU 中,我们用 %ebp 寄存器指向栈底,也就是基址指针;用 %esp 寄存器指向栈顶,也就是栈指针。下面是一个栈帧的示意图:

 

如何读懂栈溢出攻击,从这五点入手

 

 

  • 一般来说,我们将 %ebp 到 %esp 之间区域当做栈帧。并不是整个栈空间只有一个栈帧,每调用一个函数,就会生成一个新的栈帧。
  • 在函数调用过程中,我们将调用函数的函数称为:调用者(caller),将被调用的函数称为:被调用者(callee)。在这个过程中:
  1. 调用者 需要知道在哪里获取 被调用者 返回的值(一般存放到 %eax 寄存器)。
  2. 被调用者 需要知道传入的参数在哪里和调用完后的返回地址在哪里。
  3. 我们需要保证在 被调用者 返回后,%ebp 和 %esp 寄存器的值应该和调用前一致。

函数调用

  • 现在,我们来看看函数调用时,栈帧是如何变化的。
  • 我们以一个函数调用的实例来解说,代码如下:
// stack.c

int add_func(int a, int b)
{
    int c, d;

    c = a;
    d = b;

    return c + d;
}

int mAIn(int argc, char *argv[])
{
    int total;

    total = add_func(1, 2);

    return 0;
}

  • 我们使用命令 gcc -S -m32 stack.c 来编译上面的代码,获取的汇编代码如下所示(去掉一些无关紧要的信息):
add_func:
    pushl   %ebp                // 保存ebp寄存器到栈
    movl    %esp, %ebp          // 把ebp进程设置为esp的值
    subl    $16, %esp           // 为局部变量申请空间
    movl    8(%ebp), %eax       // 把参数a保存到eax寄存器中
    movl    %eax, -8(%ebp)      // 把eax寄存器的值保存到局部变量c中(c = a)
    movl    12(%ebp), %eax      // 把参数b保存到eax寄存器中
    movl    %eax, -4(%ebp)      // 把eax寄存器到值保存到局部变量d中(d = b)
    movl    -8(%ebp), %edx      // 把d的值保存到edx寄存器中
    movl    -4(%ebp), %eax      // 把c的值保存到eax寄存器中
    addl    %edx, %eax          // 将eax寄存器与edx寄存器的值相加,保存到eax中(返回值)
    leave
    ret                         // 函数返回
    ...

  • 可能汇编代码比较难看懂,我们用下面的插图来说明这个调用过程:

 

如何读懂栈溢出攻击,从这五点入手

 

 

  • 如上图所示,调用过程如下:
  1. 在 main() 函数调用 add_func() 函数前,先将调用 add_func() 函数的参数压栈。
  2. 在调用 add_func() 函数时,会将 返回地址 压栈,接着进入 add_func() 函数。
  3. add_func() 函数执行时,会将原来的 ebp寄存器 的值压栈,然后把 ebp寄存器 的设置为 esp寄存器 的值。
  4. 接着 add_func() 函数会为局部变量申请空间,也就是将 esp寄存器 向下移动。
  5. 然后把局部变量 c 设置为参数 a 的值,局部变量 d 设置为 参数 b 的值。
  6. 最后将局部变量 c 和 d 的值相加,放置到 eax寄存器 中(C语言规定以 eax寄存器 传递返回值),然后调用 ret 指令返回到 main() 函数。

函数返回

  • 上面介绍了 函数调用 的过程,现在我们来介绍一下函数调用完毕后,从被调用函数返回到原来的函数过程是如何处理的。
  • 从 add_func() 函数的汇编代码可以看到,当被调用函数执行完毕返回到调用函数前,会执行 leave 指令,这条指令等价于:
movl %ebp, %esp
popl %ebp

  • 这两条汇编指令的意思是,将 esp寄存器 和 ebp寄存器 恢复到调用函数前的值。
  • 然后,调用 ret 指令返回到原来的函数。ret 指令会从栈顶获取 返回地址,然后跳转到(jmp指令)此地址继续执行。这时的 栈帧 的结构如下图所示:

 

如何读懂栈溢出攻击,从这五点入手

 

 

栈溢出攻击

  • 前面说了那么,都是为了 栈溢出攻击 这节作铺垫的。通过前面的学习,我们知道调用函数的 参数 、执行完函数后的 返回地址 和被调用函数的 局部变量 都是存放在栈中的。
  • 如果在调用函数时,不小心将 返回地址 覆盖了,那么调用完函数后,将不会跳转到原来的函数继续执行,而是跳转到覆盖后的地址执行。如下图所示:

 

如何读懂栈溢出攻击,从这五点入手

 

 

  • 那么,怎样才能把 返回地址 覆盖呢?我们可以通过下面的例子来说明:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdint.h>

#define PTR_SIZE 8   // 指针的大小
#define EBP_SIZE 8   // ebp寄存器的大小

void inject_callback()
{
    printf("inject_callback called...n");
    exit(0);
}

void func_call(char *addr, int len)
{
    char tmpBuf[16] = {0xff};

    memcpy(tmpBuf + 16 + EBP_SIZE, addr, len);

    printf("func_call called...n");
}

int main(int argc, char** argv)
{
    uint64_t injectPtr = (uint64_t)&inject_callback;

    func_call(&injectPtr, PTR_SIZE);

    printf("main exited...n");

    return 0;
}

  • 我们使用以下命令编译上面代码,并且执行:
$ gcc stack-overflow.c -fno-stack-protector -o stack-overflow
$ ./stack-overflow
func_call called...
inject_callback called...

在编译上面程序时,一定要加上 -fno-stack-protector 参数,否则将会触发栈溢出保护,导致执行失败。

  • 在上面的代码中,我们并没有直接调用 inject_callback() 函数,而是通过把 inject_callback() 函数的地址复制到 func_call() 函数的局部变量 tmpBuf 中。
  • 由于局部变量 tmpBuf 的类型为字符串数组,而且大小为 16 个字节。但我们复制数据是从 24(16 + 8)处开始复制,已经超出了局部变量 tmpBuf 的大小,如下图所示:

 

如何读懂栈溢出攻击,从这五点入手

 

 

  • 从上图可以看出,func_call() 函数在调用 memcpy() 函数复制数据时,由于不小心用 inject_callback() 函数的地址覆盖了返回地址,导致 func_call() 函数执行完毕后,跳转到 inject_callback() 函数处执行。
  • 这就是 栈溢出攻击 的原理,而导致 栈溢出攻击 的原因就是:调用 memcpy()、strcpy() 等函数复制数据时,没有对数据的长度进行验证,从而 返回地址 被复制的数据覆盖了。
  • 黑客可以利用 栈溢出攻击 来把函数的返回地址修改成入侵代码的地址,从而实现攻击的目的。


Tags:栈溢出   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,不构成投资建议。投资者据此操作,风险自担。如有任何标注错误或版权侵犯请与我们联系,我们将及时更正、删除。
▌相关推荐
黑客软件漏洞分析0基础教学 初级栈溢出 入门到地狱
初级栈溢出_A_初识数组越界今夜月明星稀 本想来点大道理申明下研究思路啥的,,但稍微调整一下讲课的顺序。从今天开始,将用3~4次给大家做一下栈溢出的扫盲。 栈溢出的文章网上还...【详细内容】
2022-11-10  Search: 栈溢出  点击:(352)  评论:(0)  加入收藏
如何读懂栈溢出攻击,从这五点入手
什么是栈 简单来说,栈 是一种 LIFO(Last In Frist Out,后进先出) 形式的数据结构。栈一般是从高地址向低地址增长,并且栈支持 push(入栈) 和 pop(出栈) 两个操作。如下图所示: pus...【详细内容】
2022-03-29  Search: 栈溢出  点击:(346)  评论:(0)  加入收藏
栈溢出漏洞原理详解与利用
和我一样,有一些计算机专业的同学可能一直都在不停地码代码,却很少关注程序是怎么执行的,也不会考虑到自己写的代码是否会存在栈溢出漏洞,借此机会我们一起走进栈溢出。...【详细内容】
2020-04-10  Search: 栈溢出  点击:(336)  评论:(0)  加入收藏
栈溢出SROP攻击
原创:treebacker合天智汇原创投稿活动:http://link.zhihu.com/?target=https%3A//mp.weixin.qq.com/s/Nw2VDyvCpPt_GG5YKTQuUQ高级ROP-SROP利用在刷题时碰到这个考察点,有点震...【详细内容】
2019-10-10  Search: 栈溢出  点击:(755)  评论:(0)  加入收藏
▌简易百科推荐
Meta如何将缓存一致性提高到99.99999999%
介绍缓存是一种强大的技术,广泛应用于计算机系统的各个方面,从硬件缓存到操作系统、网络浏览器,尤其是后端开发。对于Meta这样的公司来说,缓存尤为重要,因为它有助于减少延迟、扩...【详细内容】
2024-04-15    dbaplus社群  Tags:Meta   点击:(1)  评论:(0)  加入收藏
SELECT COUNT(*) 会造成全表扫描?回去等通知吧
前言SELECT COUNT(*)会不会导致全表扫描引起慢查询呢?SELECT COUNT(*) FROM SomeTable网上有一种说法,针对无 where_clause 的 COUNT(*),MySQL 是有优化的,优化器会选择成本最小...【详细内容】
2024-04-11  dbaplus社群    Tags:SELECT   点击:(1)  评论:(0)  加入收藏
10年架构师感悟:从问题出发,而非技术
这些感悟并非来自于具体的技术实现,而是关于我在架构设计和实施过程中所体会到的一些软性经验和领悟。我希望通过这些分享,能够激发大家对于架构设计和技术实践的思考,帮助大家...【详细内容】
2024-04-11  dbaplus社群    Tags:架构师   点击:(2)  评论:(0)  加入收藏
Netflix 是如何管理 2.38 亿会员的
作者 | Surabhi Diwan译者 | 明知山策划 | TinaNetflix 高级软件工程师 Surabhi Diwan 在 2023 年旧金山 QCon 大会上发表了题为管理 Netflix 的 2.38 亿会员 的演讲。她在...【详细内容】
2024-04-08    InfoQ  Tags:Netflix   点击:(5)  评论:(0)  加入收藏
即将过时的 5 种软件开发技能!
作者 | Eran Yahav编译 | 言征出品 | 51CTO技术栈(微信号:blog51cto) 时至今日,AI编码工具已经进化到足够强大了吗?这未必好回答,但从2023 年 Stack Overflow 上的调查数据来看,44%...【详细内容】
2024-04-03    51CTO  Tags:软件开发   点击:(9)  评论:(0)  加入收藏
跳转链接代码怎么写?
在网页开发中,跳转链接是一项常见的功能。然而,对于非技术人员来说,编写跳转链接代码可能会显得有些困难。不用担心!我们可以借助外链平台来简化操作,即使没有编程经验,也能轻松实...【详细内容】
2024-03-27  蓝色天纪    Tags:跳转链接   点击:(16)  评论:(0)  加入收藏
中台亡了,问题到底出在哪里?
曾几何时,中台一度被当做“变革灵药”,嫁接在“前台作战单元”和“后台资源部门”之间,实现企业各业务线的“打通”和全域业务能力集成,提高开发和服务效率。但在中台如火如荼之...【详细内容】
2024-03-27  dbaplus社群    Tags:中台   点击:(13)  评论:(0)  加入收藏
员工写了个比删库更可怕的Bug!
想必大家都听说过删库跑路吧,我之前一直把它当一个段子来看。可万万没想到,就在昨天,我们公司的某位员工,竟然写了一个比删库更可怕的 Bug!给大家分享一下(不是公开处刑),希望朋友们...【详细内容】
2024-03-26  dbaplus社群    Tags:Bug   点击:(9)  评论:(0)  加入收藏
我们一起聊聊什么是正向代理和反向代理
从字面意思上看,代理就是代替处理的意思,一个对象有能力代替另一个对象处理某一件事。代理,这个词在我们的日常生活中也不陌生,比如在购物、旅游等场景中,我们经常会委托别人代替...【详细内容】
2024-03-26  萤火架构  微信公众号  Tags:正向代理   点击:(14)  评论:(0)  加入收藏
看一遍就理解:IO模型详解
前言大家好,我是程序员田螺。今天我们一起来学习IO模型。在本文开始前呢,先问问大家几个问题哈~什么是IO呢?什么是阻塞非阻塞IO?什么是同步异步IO?什么是IO多路复用?select/epoll...【详细内容】
2024-03-26  捡田螺的小男孩  微信公众号  Tags:IO模型   点击:(10)  评论:(0)  加入收藏
站内最新
站内热门
站内头条