堆栈溢出技术从入门到精通

发布者:Dingsir1902最新更新时间:2018-11-22 来源: eefocus关键字:堆栈  溢出技术 手机看文章 扫描二维码
随时随地手机看文章

虽然溢出在程序开发过程中不可完全避免,但溢出对系统的威胁是巨大的,由于系统的特殊性,溢出发生时攻击者可以利用其漏洞来获取系统的高级权限root,因此本文将详细介绍堆栈溢出技术……


在您开始了解堆栈溢出前,首先你应该了解win32汇编语言,熟悉寄存器的组成和功能。你必须有堆栈和存储分配方面的基础知识,有关这方面的计算机书籍很多,我将只是简单阐述原理,着重在应用。其次,你应该了解linux,本讲中我们的例子将在linux上开发。


1、首先复习一下基础知识。


从物理上讲,堆栈是就是一段连续分配的内存空间。在一个程序中,会声明各种变量。静态全局变量是位于数据段并且在程序开始运行的时候被加载。而程序的动态的局部变量则分配在堆栈里面。


从操作上来讲,堆栈是一个先入后出的队列。他的生长方向与内存的生长方向正好相反。我们规定内存的生长方向为向上,则栈的生长方向为向下。压栈的操作push=ESP-4,出栈的操作是pop=ESP+4.换句话说,堆栈中老的值,其内存地址,反而比新的值要大。请牢牢记住这一点,因为这是堆栈溢出的基本理论依据。


在一次函数调用中,堆栈中将被依次压入:参数,返回地址,EBP。如果函数有局部变量,接下来,就在堆栈中开辟相应的空间以构造变量。函数执行结束,这些局部变量的内容将被丢失。但是不被清除。在函数返回的时候,弹出EBP,恢复堆栈到函数调用的地址,弹出返回地址到EIP以继续执行程序。


在C语言程序中,参数的压栈顺序是反向的。比如func(a,b,c)。在参数入栈的时候,是:先压c,再压b,最后a。在取参数的时候,由于栈的先入后出,先取栈顶的a,再取b,最后取c。这些是汇编语言的基础知识,用户在开始前必须要了解这些知识。


2、现在我们来看一看什么是堆栈溢出。


运行时的堆栈分配


堆栈溢出就是不顾堆栈中数据块大小,向该数据块写入了过多的数据,导致数据越界,结果覆盖了老的堆栈数据。


例如程序一:


      #include  
int main ( ) 

char name[8]; 
printf("Please type your name: "); 
gets(name); 
printf("Hello, %s!", name); 
return 0; 
}


编译并且执行,我们输入ipxodi,就会输出Hello,ipxodi!。程序运行中,堆栈是怎么操作的呢?


在main函数开始运行的时候,堆栈里面将被依次放入返回地址,EBP。


我们用gcc -S 来获得汇编语言输出,可以看到main函数的开头部分对应如下语句:


      pushl %ebp 
movl %esp,%ebp 
subl $8,%esp

首先他把EBP保存下来,,然后EBP等于现在的ESP,这样EBP就可以用来访问本函数的局部变量。之后ESP减8,就是堆栈向上增长8个字节,用来存放name[]数组。最后,main返回,弹出ret里的地址,赋值给EIP,CPU继续执行EIP所指向的指令。


堆栈溢出


现在我们再执行一次,输入ipxodiAAAAAAAAAAAAAAA,执行完gets(name)之后,由于我们输入的name字符串太长,name数组容纳不下,只好向内存顶部继续写‘A’。由于堆栈的生长方向与内存的生长方向相反,这些‘A’覆盖了堆栈的老的元素。 我们可以发现,EBP,ret都已经被‘A’覆盖了。在main返回的时候,就会把‘AAAA’的ASCII码:0x41414141作为返回地址,CPU会试图执行0x41414141处的指令,结果出现错误。这就是一次堆栈溢出。


3、如何利用堆栈溢出


我们已经制造了一次堆栈溢出。其原理可以概括为:由于字符串处理函数(gets,strcpy等等)没有对数组越界加以监视和限制,我们利用字符数组写越界,覆盖堆栈中的老元素的值,就可以修改返回地址。


在上面的例子中,这导致CPU去访问一个不存在的指令,结果出错。事实上,当堆栈溢出的时候,我们已经完全的控制了这个程序下一步的动作。如果我们用一个实际存在指令地址来覆盖这个返回地址,CPU就会转而执行我们的指令。


在UINX/linux系统中,我们的指令可以执行一个shell,这个shell将获得和被我们堆栈溢出的程序相同的权限。如果这个程序是setuid的,那么我们就可以获得root shell。下一讲将叙述如何书写一个shell code。


如何书写一个shell code


一:shellcode基本算法分析


在程序中,执行一个shell的程序是这样写的:


      shellcode.c 
------------------------------------------------------------------------ 
#include  
void main() { 
char *name[2]; 
name[0] = "/bin/sh" 
name[1] = NULL; 
execve(name[0], name, NULL); 

------------------------------------------------------------------------


execve函数将执行一个程序。他需要程序的名字地址作为第一个参数。一个内容为该程序的argv[i](argv[n-1]=0)的指针数组作为第二个参数,以及(char*) 0作为第三个参数。


我们来看以看execve的汇编代码:


      [nkl10]$Content$nbsp;gcc -o shellcode -static shellcode.c 
[nkl10]$Content$nbsp;gdb shellcode 
(gdb) disassemble __execve 
Dump of assembler code for function __execve: 
0x80002bc 


经过以上的分析,可以得到如下的精简指令算法:


      movl $execve的系统调用号,%eax 
movl "bin/sh\0"的地址,%ebx 
movl name数组的地址,%ecx 
movl name[n-1]的地址,%edx 
int $0x80 ;执行系统调用(execve)


当execve执行成功后,程序shellcode就会退出,/bin/sh将作为子进程继续执行。可是,如果我们的execve执行失败,(比如没有/bin/sh这个文件),CPU就会继续执行后续的指令,结果不知道跑到哪里去了。所以必须再执行一个exit()系统调用,结束shellcode.c的执行。


我们来看以看exit(0)的汇编代码:


      (gdb) disassemble _exit 
Dump of assembler code for function _exit: 
0x800034c 


看来exit(0)〕的汇编代码更加简单:


   movl $0x1,%eax ;1号系统调用 
movl 0,%ebx ;ebx为exit的参数0 
int $0x80 ;引发系统调用


那么总结一下,合成的汇编代码为:


      movl $execve的系统调用号,%eax 
movl "bin/sh\0"的地址,%ebx 
movl name数组的地址,%ecx 
movl name[n-1]的地址,%edx 
int $0x80 ;执行系统调用(execve) 
movl $0x1,%eax ;1号系统调用 
movl 0,%ebx ;ebx为exit的参数0 
int $0x80 ;执行系统调用(exit)


关键字:堆栈  溢出技术 引用地址:堆栈溢出技术从入门到精通

上一篇:关于程序效率的问题,你有思考过吗?
下一篇:嵌入式C语言编程小知识总结

推荐阅读最新更新时间:2024-03-16 16:18

ATmega168 堆栈指针
堆栈指针主要用来保存临时数据、局部变量和中断/ 子程序的返回地址。堆栈指针总是指向堆栈的顶部。要注意AVR 的堆栈是向下生长的,即新数据推入堆栈时,堆栈指针的数值将减小。 堆栈指针指向数据SRAM 堆栈区。在此聚集了子程序堆栈和中断堆栈。ATmega168 在调用子程序和使能中断之前必须定义堆栈空间,且堆栈指针必须指向高于0xFF 的地址空间。使用PUSH指令将数据推入堆栈时指针减一;而子程序或中断返回地址推入堆栈时指针将减二。使用POP 指令将数据弹出堆栈时,堆栈指针加一;而用RET 或RETI 指令从子程序或中断返回时堆栈指针加二。 AVR的堆栈指针由I/O空间中的两个8位寄存器实现。实际使用的位数与具体器件有关。请注意某些A
[单片机]
ATmega168 <font color='red'>堆栈</font>指针
人工智能走向终端应用 赛灵思推出专用软件堆栈
   人工智能 (AI)从云端服务器走向网络边缘,直接内建到各类物联网(IoT)装置,已经成为挡不住的发展趋势。有鉴于此,现场可编程门阵列(FPGA)供货商 赛灵思 (Xilinx)宣布,将在其现有的嵌入式视觉解决方案基础上,强化对机器学习(MachineLearning)等 人工智能 功能的支持,并推出reVISION软件堆栈。下面就随嵌入式小编一起来了解一下相关内容吧。    赛灵思 工业、科学、医疗(ISM)营销资深技术经理罗霖表示, 人工智能 已经成为科技产业发展的重要趋势,而且从核心(数据中心)往边缘(各类联网装置)扩散的态势十分明显。不过,由于缺乏对应的函式库(Library)等软件堆栈辅助,应用开发者经常必须从头到
[嵌入式]
一步步写STM32 OS【三】PendSV与堆栈操作
一、什么是PendSV PendSV是可悬起异常,如果我们把它配置最低优先级,那么如果同时有多个异常被触发,它会在其他异常执行完毕后再执行,而且任何异常都可以中断它。更详细的内容在《Cortex-M3 权威指南》里有介绍,下面我摘抄了一段。 OS 可以利用它“缓期执行”一个异常——直到其它重要的任务完成后才执行动 作。悬起 PendSV 的方法是:手工往 NVIC的 PendSV悬起寄存器中写 1。悬起后,如果优先级不够 高,则将缓期等待执行。 PendSV的典型使用场合是在上下文切换时(在不同任务之间切换)。例如,一个系统中有两个就绪的任务,上下文切换被触发的场合可以是: 1、执行一个系统调用 2、系统滴答定时器(S
[单片机]
一步步写STM32 OS【三】PendSV与<font color='red'>堆栈</font>操作
研究人员确定最佳锂金属电池堆栈压力 显著提高性能
据外媒报道,一个由材料科学家和化学家组成的研究团队确定了锂金属电池(LMB)在电池运行期间需要承受的最佳堆栈压力,可产生最佳性能。该研究团队成员主要来自加州大学圣地亚哥分校(University of California San Diego)、密歇根州立大学(Michigan State University)、爱达荷州国家实验室(Idaho National Laboratory)和通用汽车研发中心(General Motors Research and Development Center)。 (图片来源:加州大学圣地亚哥分校) 用锂金属代替石墨做电池负极是部分电池研发领域的终极目标。这些锂金属电池将有可能把当前最
[汽车电子]
研究人员确定最佳锂金属电池<font color='red'>堆栈</font>压力 显著提高性能
第四节:PIC系列单片机程序存储器及堆栈
PIC16C5X内部有384~2K的只读程序存贮器,下面论述其结构和堆栈。 §1.4.1 程序存储器结构 PIC16C5X程序存储器结构如图1.3所示: 从上图可看出,PIC程序存储器采用分页结构,每页长0.5K。因此对于PIC16C52程序存储器在1页之内,而对于PIC16C54和PIC15C55程序存储器容量为1页,PIC16C56和PIC16C57 的容量则分别为2页和4页。页面地址由状态寄存器f3的第5位和第6位(PA0、PA1)确定。程序转移时,在本页内可直接进行;在需跨页跳转时(GOTO、CALL指令),则必须根据将要跳转去的页面,把f3中的PA0、PA1位置成相应的值。具体请参考f3寄存器描述及§2.7.2
[单片机]
第四节:PIC系列单片机程序存储器及<font color='red'>堆栈</font>
多核与多线程技术的区别到底在哪里?
毫无疑问的,“多核”、“多线程”此二词已快成为当今处理器架构设计中的两大显学,如同历史战国时代以“儒”、“墨”两大派的显学,只不过当年两大治世思想学派是争得你死我亡,而多核、多线程则是相互兼容并蓄,今日几乎任何处理器都朝同时具有多核多线程的路线发展迈进。 虽然两词到处可见,但可有人知此二者的实际差异?在执行设计时又是以何者为重?到底是该多核优先还是多线程提前?关于此似乎大家都想进一步了解,本文以下试图对此进行个中差异的解说,并尽可能在不涉及实际复杂细节的情形下,让各位对两者的机制观念与差别性有所理解。 行程早于线程 若依据信息技术的发展历程,在软件程序执行时的再细分、再切割的小型化单位上,先是有行程(Process),之
[工业控制]
64层堆栈是3D NAND的「甜蜜点」?
  64层 堆栈 的3D  NAND 正跨越较平面 NAND 更具成本效益的门坎,预计将在未来18个月内成为市场主流...下面就随网络通信小编一起来了解一下相关内容吧。   Western Digital(WD)内存技术执行副总裁Siva Sivaram日前指出,64层 堆栈 的3D NAND 正跨越较平面NAND更具成本效益的门坎。   在最近接受《EE Times》的访问中,Siva Sivaram将64层3D NAND定义为一种「开创性技术」(seminal technology),可望应用于WD逾50种产品线。 他预计今年WD约有一半的产品线都将采用3D NAND,其中有75%都是64层3D NAND。 「64层是我们认
[网络通信]
TI堆栈式DC/DC降压转换器激发高电流FPGA和处理器电源潜能
德州仪器(TI)推出业界首款可堆叠多至四个集成电路(IC)的新型40-A SWIFTTM DC/DC降压转换器。TPS546D24A PMBus降压转换器可在85°C的环境温度下提供高达160A的输出电流,比市场上其他功率集成电路高四倍。在众多40A DC/DC转换器中,TPS546D24A效率更高,能够在高性能数据中心、企业计算、医疗、无线基础设施以及有线网络应用中将功耗降低1.5W。 缩小电源尺寸并优化热性能 解决方案尺寸和热性能是工程师为现代现场可编程门阵列(FPGA)设计电源的两个关键考虑因素。TPS546D24A降压转换器凭借其独特的可堆叠性解决了这两个问题。它带有一个提供可选内部补偿网络的PMBus
[电源管理]
TI<font color='red'>堆栈</font>式DC/DC降压转换器激发高电流FPGA和处理器电源潜能
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
  • 学习ARM开发(16)
    ARM有很多东西要学习,那么中断,就肯定是需要学习的东西。自从CPU引入中断以来,才真正地进入多任务系统工作,并且大大提高了工作效率。采 ...
  • 学习ARM开发(17)
    因为嵌入式系统里全部要使用中断的,那么我的S3C44B0怎么样中断流程呢?那我就需要了解整个流程了。要深入了解,最好的方法,就是去写程序 ...
  • 学习ARM开发(18)
    上一次已经了解ARM的中断处理过程,并且可以设置中断函数,那么它这样就可以工作了吗?答案是否定的。因为S3C44B0还有好几个寄存器是控制中 ...
  • 嵌入式系统调试仿真工具
    嵌入式硬件系统设计出来后就要进行调试,不管是硬件调试还是软件调试或者程序固化,都需要用到调试仿真工具。 随着处理器新品种、新 ...
  • 最近困扰在心中的一个小疑问终于解惑了~~
    最近在驱动方面一直在概念上不能很好的理解 有时候结合别人写的一点usb的例子能有点感觉,但是因为arm体系里面没有像单片机那样直接讲解引脚 ...
  • 学习ARM开发(1)
  • 学习ARM开发(2)
  • 学习ARM开发(4)
  • 学习ARM开发(6)
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved