缓冲区溢出原理详解

article/2025/9/17 5:21:52

下面将有实例引入缓冲区溢出的介绍:

void main()

{

int i=0;

int a[]={1,2,3,4,5,6,7,8,9,10};

for(i=0;i<=10;i++)

{

a[i]=0;printf("Hello World!\n");

}

}

首先,这段代码会出现死循环,为什么?因为数组溢出了,而溢出的位置正好是变量i的位置,所以当i=10时,a[10]的位置正好是i的位置,所以i会被重新赋值为0,从而导致无线循环,这是缓冲区溢出最简单的实例演示。

要了解缓存区溢出原理,首先必须得明白程序运行时在内存中的情况。深层次的原理这里不讨论,我们只需要知道在函数调用时会发生如下步骤:

1、将被调用函数的下一条指令地址压入栈(保存被调用函数的下一条指令)

2、将当前的EPB压入栈(保持当前的基址)

3、将ESP值赋给EPB(改变基址)

4、移动ESP指针(开辟空间,以便保存函数执行时需要的数据,如保存函数内定义的变量)

……函数运行完毕后,将会执行如下操作……

5、将EPB出栈(还原调用前的基址)

6、将EIP出栈(返回到调用函数的下一条指令)

此时的内存模型如下:

在这里插入图片描述

根据上面的流程及内测模型,我们可以知道,缓冲区下面就是EBP与EIP,而EIP是直接影响程序的执行流程,正常情况下它保存的是函数返回的地址,如果我们在操作缓冲区时出现异常,导致缓冲区后面的EBP与EIP被修改了,就会改变程序的执行流程,甚至引起缓冲区溢出攻击。

现在回到第一个实例:

在详细剖析程序前,我们还需要知道一个知识点,在上面的内存模型中,我们在函数内定义的变量是保存在缓冲区中,那么具体在缓冲区内部是如何分配的呢?通常情况下,都是从下往上顺序分配的,即先定义的变量在下面,后定义的变量在上面,如:

在这里插入图片描述

试想一下:如果数组a的范围越界了,覆盖掉了i的值那会这样?

上面给出的是内存的抽象模型,下面将给出在VS2010调试中它的内存情况 如下图:

缓冲区溢出原理详解

有底色的数据区分别是:数组a(10*4个字节),变量i(一个字节),EBP(4字节),EIP(4字节)。显然如果数组寻址越界,就可能覆盖掉变量i的值,例如:这个实例运行中当i=10时,执行下面代码:

a[i]=0;

printf(“Hello World!\n”);

当执行a[10]=0后,内存情况如下图:

缓冲区溢出原理详解

显然,数组a的最大范围是a[9],但这里越界了,而a[10]正好是变量i的地址,故变量i的值被覆盖了,变成了0,所以程序会不停地循环。你可试下a[12]=0看会出现什么情况,a[12]正好是保持的是EIP的地址。

通过上面的例子,我想对缓冲区溢出应该有了最基本的认识,下面在看第2例子:

代码:

#include “stdafx.h”

#include

#include

void fuzprin()

{

printf(“test”);

}

void gettest1()

{

char str[11]={‘0’};

}

void main()

{

gettest1()

}

我们的目的是要在gettest1函数中添加溢出代码,改变EIP从而使执行fuzprin函数。

在这里插入图片描述
通过第一个实例的,我们知道只要找到保存EIP的地址就可以直接修改,关键是找到这个地址,我们打开VS2010在调试中内存情况如下:

缓冲区溢出原理详解

底色部分分别是数组str(11个字节)、EBP(4字节)、EIP(4字节),所以我们知道保存EIP的地址是str[16]开始的4个字节(0x002e161e,注意是倒放的),只要改写掉这4个字节就能改变程序的流程,算法如下:

1、找到函数fuzprin的地址假设为:ap

2、用ap的地址改写保存有EIP的地址的内容。

具体代码如下:

void gettest1()

{

char str[11]={‘0’};

int p=(int)&fuzprin;//获取函数fuzprin地址

char ap[4];//将函数fuzprin地址分为4个字节

ap[0]=p>>24&0x000000FF;//分离地址的前2位

ap[1]=p<<8>>24&0x000000FF;

ap[2]=p<<16>>24&0x000000FF;

ap[3]=p<<24>>24&0x000000FF;//分离地址的后两位

str[16]=ap[3];//用fuzprin地址后两位改写保存EIP地址的前两位

str[17]=ap[2];

str[18]=ap[1];

str[19]=ap[0];//用fuzprin地址前两位改写保存EIP地址的后两位

}

上面的代码可能有人看不太明白,这里用具体的例子讲解下:

假设保存EIP的地址0X001e1356,而此时str[16]=56,str[17]=13,str[18]=1e,str[19]=00,假设函数fuzprin的地址为:0x004514ba,我们要把这个地址分离成字节:00,45,14,ba,可以通过移位运算来实现,分离之后,就可以改写EIP的地址。这里具体的实现过程不要求能看懂,但思想一定要懂!思想就是:获取fuzprin的地址,然后改写返回EIP的地址!

添加溢出代码后,程序的运行结果如下图:

缓冲区溢出原理详解

可以看到,程序已经被改写了,我们的目的达到了,但却弹出了错误框,为什么会这样?因为我们并非通过正常的函数调用跳到fuzprin函数,所以函数执行完后,没有返回地址,而是直接往下执行,fuzprin函数下面的机器指令未知,所以可能就会出现错误!你可以通过fuzprin函数后面的加上JMP指令跳回来解决,在这里我们没有必要再讨论,因为我们的目的是改写EIP了解缓冲区溢出。

再次强调:不要纠结于如何实现溢出的技巧,而是要清晰明白溢出的原理!思想很重要!

下面来看实例3:

#include “stdafx.h”

#include

#include

void fuzprin()

{

printf(“test”);

}

void gettest()

{

char str[11]={‘0’};

scanf("%s",str);

printf("%s\n",str);

}

void main()

{

gettest1();

}

我们的目的是在gettest()中添加溢出代码,使得我们可以手动输入经过构造的特殊字符以改写程序流程去执行fuzprin(),是不是更接近于实际的应用了?

首先来看下gettest函数,这里面有个scanf函数,所以我们可以手动输入字符来使得缓冲区溢出,这里的内存模型可实例2的一样,就不再画了,通过实例2的内存模型我们可以知道str(11个字节),EBP(4字节),EIP(4字节),所以str+16就是返回EIP的地址,于是我们可以这样输入:

aaaaaaaaaaaaaaaaXXXX,16个a之后接上fuzprin函数的地址就能改写掉返回EIP的地址。

上面就是我们的思路,下面是实现算法,再强调一遍:思路很重要,实现是次要的!

void gettest()

{

char str[11]={‘0’};

int p=(int)&fuzprin;

char ap[4];

ap[0]=p>>24&0x000000FF;

ap[1]=p<<8>>24&0x000000FF;

ap[2]=p<<16>>24&0x000000FF;

ap[3]=p<<24>>24&0x000000FF;//前面都一样,就是获取fuzprin地址并分离成字节

printf("\n");

printf("%c",ap[3]);

printf("%c",ap[2]);

printf("%c",ap[1]);

printf("%c",ap[0]);//输出函数的地址的ascall符号

printf("\n");

scanf("%s",str);//输入,构造溢出字符

printf("%s\n",str);

}

程序运行结果,如下图:

缓冲区溢出原理详解

已成功改写程序流程!我们构造的输入是:aaaaaaaaaaaaaaaa在跟上fuzprin函数地址的ascall符号,这里我们之所以先输出fuzprin的ascall的符号,是为了获取fuzprin的地址,并且要以ascall符号输入才行,而这个地址的ascall符号可能是特殊符号不太好手动输入的,所以我们先打印出来,然后复制、粘贴即可得到该ascall符号。

明白实例2,我们再来看实例3,代码如下:

#include “stdafx.h”

#include

#include

void fuzprin()

{

printf(“test”);

}

void gettest2()

{

char buf[11]={‘0’};

FILE *fp;

fp = fopen(“fuz.txt”, “r”);

  if(!fp) {

perror(“fopen”);

}

fread(buf, 20, 1, fp);

fclose(fp);

}

void main()

{

void *(p)=&fuzprin;//获取fuzprin地址,方便调试

gettest2();

}

同样目的是改写程序流程,使得函数fuzprin得以执行,但这里是通过构造特殊文件来实现缓存区溢出,并改写EIP的。函数 gettest2的流程是读取fuz.txt的文件,然后保存至缓冲区buf,但读取的长度是20大于buf的长度,所以会出现溢出,通过上面的实例2,我想应该对缓冲区溢出改写EIP有了足够的了解,所以这里不再详讲,直接给出思路:通过在下断点获取fuzprin的地址然后将该地址以16进制的形式写入fuz.txt文件的16、17、18、19个字节出,即可完成。过程图如下:

缓冲区溢出原理详解

上图是调试过程中的获取函数fuzprin地址并改写文件fuz.txt的过程图,注意画圈的地方。

改写之后结果如下:

缓冲区溢出原理详解

目的达到,会报错属正常情况。如果你想练习,你可以把文件指针定义在buf数组之上,即:

FILE *fp;

char buf[11]={‘0’};

进行改写试试!结合实例1的讲解,如果你真的通过本文了解缓冲区溢出,那么你很容易就能实现!如果你能实现了,说明缓冲区溢出的基本原理你已经掌握了!

完整实验代码如下:

#include “stdafx.h”

#include

#include

/by 潇阳残霜

void fuzprin()

{

printf(“test”);

}

void gettest1()

{

char str[11]={‘0’};

int p=(int)&fuzprin;

char ap[4];

ap[0]=p>>24&0x000000FF;

ap[1]=p<<8>>24&0x000000FF;

ap[2]=p<<16>>24&0x000000FF;

ap[3]=p<<24>>24&0x000000FF;

str[16]=ap[3];

str[17]=ap[2];

str[18]=ap[1];

str[19]=ap[0];

}

void gettest()

{

char str[11]={‘0’};

int p=(int)&fuzprin;

char ap[4];

ap[0]=p>>24&0x000000FF;

ap[1]=p<<8>>24&0x000000FF;

ap[2]=p<<16>>24&0x000000FF;

ap[3]=p<<24>>24&0x000000FF;

printf("\n");

printf("%c",ap[3]);

printf("%c",ap[2]);

printf("%c",ap[1]);

printf("%c",ap[0]);

printf("\n");

scanf("%s",str);

printf("%s\n",str);

}

void gettest2()

{

char buf[11]={‘0’};

FILE *fp;

fp = fopen(“fuz.txt”, “r”);

  if(!fp) {

perror(“fopen”);

}

fread(buf, 20, 1, fp);

fclose(fp);

// printf("%s",buf);

}

void main()

{

///by 潇阳残霜

//int i=0;

//int a[]={1,2,3,4,5,6,7,8,9,10};

//for(i=0;i<=10;i++)

//{

// a[i]=0;

// printf(“Hello World!\n”);

//}

//gettest();

gettest1();

//void *§=&fuzprin;

//gettest2();

}

转载来源:http://blog.sina.com.cn/s/blog_50d705670102yrng.html转载来源


http://chatgpt.dhexx.cn/article/SBpjgfuo.shtml

相关文章

C语言 缓存区溢出 3221225725

目录 问题描述解决办法&#xff1a; 问题描述 DEV-C报错 Process exited after 4.03 seconds with return value 3221225725 原因 数组定义的容量太大 - 五十万起步的样子 而且每次循环都会再定义一次&#xff0c;导致缓存区溢出 解决办法&#xff1a; 思路来源&#xff1a…

什么是缓冲区溢出?有什么危害?原因是什么?

缓冲区溢出是指当计算机向缓冲区填充数据时超出了缓冲区本身的容量&#xff0c;溢出的数据覆盖在合法数据上。 危害有以下两点&#xff1a; 1、程序崩溃&#xff0c;导致拒绝服务 2、跳转并且执行一段恶意代码 原因&#xff1a;造成缓冲区溢出的主要原因是程序中没有仔细检查用…

什么是缓冲区溢出?有说明危害?

缓存溢出 缓存溢出(Buffer overflow) &#xff0c;是指在存在缓存溢出安全漏洞的计算机中&#xff0c;攻击者可以用超出常规长度的字符数来填满-一个域&#xff0c;通常是内存区地址。在某些情况下&#xff0c;这些过量的字符能够作为“可执行”代码来运行。从而使得攻击者可以…

缓存区溢出的原理分析和防范

1.前言 缓冲区溢出(buffer-overflow)是一种非常普遍、同时非常危险的漏洞&#xff0c;在各种操作系统、应用软件中广泛存在。缓冲区溢出攻击是利用缓冲区溢出漏洞所进行的攻击&#xff0c;轻则可以导致程序失败、系统关机等&#xff0c;重则可以利用它执行非授权指令&#xff0…

缓存溢出

缓存溢出&#xff08;Buffer overflow&#xff09;&#xff0c;是指在存在缓存溢出安全漏洞的计算机中&#xff0c;攻击者可以用超出常规长度的字符数来填满一个域&#xff0c;通常是内存区地址。在某些情况下&#xff0c;这些过量的字符能够作为“可执行”代码来运行。从而使得…

逆向基础:软件手动脱壳技术入门

前言&#xff1a; 大家好&#xff0c;我是周杰伦 这里整合了一下之前自己学习软件手工脱壳的一些笔记和脱文&#xff0c;希望能给新学软件逆向和脱壳的童鞋们一点帮助。 1 一些概念 1.1 加壳 加壳的全称应该是可执行程序资源压缩&#xff0c;是保护文件的常用手段。加壳过…

iOS逆向之脱壳工具creakerXI+,最简单、最适合新手的脱壳工具

在学习iOS逆向中&#xff0c;脱壳是必备技能之一&#xff0c;在网上看教程有使用 Clutch 和 dumpdecrypted 但是&#xff0c;不知道 是我操作问题&#xff0c;还是手机版本&#xff0c;以及APP版本更新问题 尝试了几次&#xff0c;都无法成功脱壳 最后在网上看到有大神分享其…

【How2RE】 UPX壳及脱壳方式

0x00 什么是壳 壳是另外在PE文件中包含的代码&#xff0c;并且不影响PE文件正常的执行。而壳也分为很多种&#xff0c;这里从UPX壳开始介绍。 0x01 压缩壳 压缩的分类 压缩的目的就是将体积大的可执行文件缩小的过程。分为损失压缩和非损失压缩两种。损失压缩是指不能100%还…

脱壳(中) 脱壳的方法

那些年我们一起脱过的衣裳&#xff0d;脱壳(中) 珈蓝夜宇 2015/10/29 10:42 0x01 我能在万花从中脱去壳的衣裳!&#xff08;续&#xff09; 3.3ESP定律法 3.3.1ESP定律介绍 ESP定律法是脱壳的利器&#xff0c;是国外友人发现的。有了ESP定律&#xff0c;可以方便我们脱掉大多…

脱壳简单总结

title: 脱壳 date: 2021-07-05 14:37:06 tags: RE 脱壳 1.概述&#xff1a; 1.壳&#xff1a; 一&#xff1a;加壳的目的&#xff1a;为了隐藏程序真正的OEP&#xff08;入口点&#xff09;&#xff0c;防止被破解。 二&#xff1a;加壳软件是一种在编译好可执行文件之后&…

最新乐加固脱壳详细教程(有图有真相)

一、前言声明&#xff1a; 本次破解是基于Xposed Installer框架&#xff0c;具体使用方法请上网查询。假设你已经安装好框架&#xff0c;按照下面的步骤&#xff0c;实现乐加固加固脱壳修复DEX&#xff0c;并且重打包运行。本次选择脱壳的APP是小猿搜题&#xff0c;特此声明&a…

脱壳之简单加密壳

一、简单分析与解密 脱壳最重要的三步&#xff1a;找原始OEP&#xff0c;转存文件&#xff0c;修复文件   压缩壳按照这三步就可以完成脱壳&#xff0c;而加密壳因为对PE文件的信息进行了加密处理&#xff0c;找到OEP只是刚开始&#xff0c;还需要将加密之后的代码、数据进行…

iOS完美脱壳

iOS端IPA脱壳 背景&#xff1a;在软件安全领域中&#xff0c;我们与黑产做对抗时&#xff0c;不是被动防守&#xff0c;自己也可以做攻击方&#xff0c;来验证我方软件是否安全。 关于iOS端逆向分析如&#xff1a;虚拟定位、虚拟设备、修改内存等&#xff0c;始终离不开脱壳。…

脱壳工具:Youpk的使用详解

一. Youpk概述 Youpk基于ART的主动调用的脱壳机&#xff0c;主要针对dex整体加固和各式各样的dex抽取加固。 目前 Youpk 只支持 pixel 1代。所以必须需要 pixel 1代手机&#xff0c;而且需要刷入对应的系统。 Youpk可以处理大部分的加固&#xff0c;一些企业版的加固也能处理…

使用upx脱壳工具脱壳

使用upx脱壳工具脱壳&#xff08;攻防世界新手第七题为例simple-unpack&#xff09; 查壳工具链接&#xff1a;https://www.52pojie.cn/thread-437586-1-1.html 脱壳工具链接&#xff1a;https://github.com/upx/upx/releases 先查壳 一般做到逆向的部分题的时候&#xff0c…

脱壳工具:反射大师的使用详解

一. 反射大师概述 一个脱壳插件工具&#xff0c;需要在 Xposed 环境中使用&#xff0c;支持市面上大多数加密壳。 反射大师简单容易使用&#xff0c;能脱掉大多数壳&#xff0c;很值得使用 二. 下载Xposed和反射大师 Xposed &#xff0c;一款可以在不修改 Android APK 的情…

逆向工具之脱壳神器反射大师(附脱壳环境搭建、脱壳实战)

相信点击进入这篇博客的小伙伴都知道并且搞过App逆向&#xff0c;不过有时候会遇到各种加壳的App&#xff0c;不让你反编译。但是道高一尺&#xff0c;魔高一丈&#xff0c;有正向加密&#xff0c;就有逆向解密。此篇博客博主带大家搭建脱壳环境&#xff0c;并且手动脱一个加了…

手动脱壳教程

一、什么是壳&#xff1f; 壳是指在一个程序的外面再包裹上另一段代码&#xff0c;保护里面的代码不被非法修改或反编译的的程序。它们一般先于程序运行&#xff0c;拿到控制权&#xff0c;然后完成它们保护软件的任务。 二、壳的加载过程 1、保存程序入口参数 …

简单脱壳教程笔记

文章目录 1、手脱UPX壳简介&#xff1a;脱壳&#xff1a;笔记&#xff1a;方法1&#xff1a;单步跟踪&#xff08;需要有耐心&#xff09;一、使用ODE插件二、tools按钮选择LordPE进行脱壳&#xff08;提前在SETUP PATHS里添加好&#xff09; 方法2&#xff1a;ESP定律法方法3&…

常用编程语言开发工具

编程语言开发工具可分为文本开发工具 和 集成开发工具。 文本开发工具的特点是 体积小&#xff0c;功能也不弱。 集成开发工具的特点是 体积大&#xff0c;功能强大。 1.文本编辑器 widows 下的 notepad&#xff08;记事本&#xff09; Unix下的 vim &#xff0c;这两个工具系…