Ⅰ 什么是c语言缓冲区溢出漏洞怎么利用谁可以提供详细的资料
缓冲区溢出漏洞入门介绍
文/hokersome
一、引言
不管你是否相信,几十年来,缓冲区溢出一直引起许多严重的安全性问题。甚至毫不夸张的说,当前网络种种安全问题至少有50%源自缓冲区溢出的问题。远的不说,一个冲击波病毒已经令人谈溢出色变了。而作为一名黑客,了解缓冲区溢出漏洞则是一门必修课。网上关于溢出的漏洞的文章有很多,但是大多太深或者集中在一个主题,不适合初学者做一般性了解。为此,我写了这篇文章,主要是针对初学者,对缓冲区溢出漏洞进行一般性的介绍。
缓冲区溢出漏洞是之所以这么多,是在于它的产生是如此的简单。只要C/C++程序员稍微放松警惕,他的代码里面可能就出现了一个缓冲区溢出漏洞,甚至即使经过仔细检查的代码,也会存在缓冲区溢出漏洞。
二、溢出
听我说了这些废话,你一定很想知道究竟什么缓冲区溢出漏洞,溢出究竟是怎么发生的。好,现在我们来先弄清楚什么是溢出。以下的我将假设你对C语言编程有一点了解,一点点就够了,当然,越多越好。
尽管缓冲区溢出也会发生在非C/C++语言上,但考虑到各种语言的运用程度,我们可以在某种程度上说,缓冲区溢出是C/C++的专利。相信我,如果你在一个用VB写的程序里面找溢出漏洞,你将会很出名。回到说C/C++,在这两种使用非常广泛的语言里面,并没有边界来检查数组和指针的引用,这样做的目的是为了提高效率,而不幸的是,这也留下了严重的安全问题。先看下面一段简单的代码:
#include<stdio.h>
void main()
{
char buf[8];
gets(buf);
}
程序运行的时候,如果你输入“Hello”,或者“Kitty”,那么一切正常,但是如果输入“Today is a good day”,那么我得通知你,程序发生溢出了。很显然,buf这个数组只申请到8个字节的内存空间,而输入的字符却超过了这个数目,于是,多余的字符将会占领程序中不属于自己的内存。因为C/C++语言并不检查边界,于是,程序将看似正常继续运行。如果被溢出部分占领的内存并不重要,或者是一块没有使用的内存,那么,程序将会继续看似正常的运行到结束。但是,如果溢出部分占领的正好的是存放了程序重要数据的内存,那么一切将会不堪设想。
实际上,缓冲区溢出通常有两种,堆溢出和堆栈溢出。尽管两者实质都是一样,但由于利用的方式不同,我将在下面分开介绍。不过在介绍之前,还是来做一些必要的知识预备。
三、知识预备
要理解大多数缓冲区溢出的本质,首先需要理解当程序运行时机器中的内存是如何分配的。在许多系统上,每个进程都有其自己的虚拟地址空间,它们以某种方式映射到实际内存。我们不必关心描述用来将虚拟地址空间映射成基本体系结构的确切机制,而只关心理论上允许寻址大块连续内存的进程。
程序运行时,其内存里面一般都包含这些部分:1)程序参数和程序环境;2)程序堆栈,它通常在程序执行时增长,一般情况下,它向下朝堆增长。3)堆,它也在程序执行时增长,相反,它向上朝堆栈增长;4)BSS 段,它包含未初始化的全局可用的数据(例如,全局变量); 5)数据段,它包含初始化的全局可用的数据(通常是全局变量);6)文本段,它包含只读程序代码。BSS、数据和文本段组成静态内存:在程序运行之前这些段的大小已经固定。程序运行时虽然可以更改个别变量,但不能将数据分配到这些段中。下面以一个简单的例子来说明以上的看起来让人头晕的东西:
#include<stdio.h>
char buf[3]="abc";
int i;
void main()
{
i=1
return;
}
其中,i属于BBS段,而buf属于数据段。两者都属于静态内存,因为他们在程序中虽然可以改变值,但是其分配的内存大小是固定的,如buf的数据大于三个字符,将会覆盖其他数据。
与静态内存形成对比,堆和堆栈是动态的,可以在程序运行的时候改变大小。堆的程序员接口因语言而异。在C语言中,堆是经由 malloc() 和其它相关函数来访问的,而C++中的new运算符则是堆的程序员接口。堆栈则比较特殊,主要是在调用函数时来保存现场,以便函数返回之后能继续运行。
四、堆溢出
堆溢出的思路很简单,覆盖重要的变量以达到自己的目的。而在实际操作的时候,这显得比较困难,尤其是源代码不可见的时候。第一,你必须确定哪个变量是重要的变量;第二,你必须找到一个内存地址比目标变量低的溢出点;第三,在特定目的下,你还必须让在为了覆盖目标变量而在中途覆盖了其他变量之后,程序依然能运行下去。下面以一个源代码看见的程序来举例演示一次简单的堆溢出是如何发生的:
#include "malloc.h"
#include "string.h"
#include "stdio.h"
void main()
{
char *large_str = (char *)malloc(sizeof(char)*1024);
char *important = (char *)malloc(sizeof(char)*6);
char *str = (char *)malloc(sizeof(char)*4);
strcpy(important,"abcdef");//给important赋初值
//下面两行代码是为了看str和important的地址
printf("%d/n",str);
printf("%d/n",important);
gets(large_str);//输入一个字符串
strcpy(str, large_str);//代码本意是将输入的字符串拷贝到str
printf("%s/n",important);
}
在实际应用中,这样的代码当然是不存在的,这只是一个最简单的实验程序。现在我们的目标是important这个字符串变成"hacker"。str和important的地址在不同的环境中并不是一定的,我这里是7868032和7868080。很好,important的地址比str大,这就为溢出创造了可能。计算一下可以知道,两者中间隔了48个字节,因此在输入溢出字符串时候,可以先输入48个任意字符,然后再输入hakcer回车,哈哈,出来了,important成了"hacker"。
五、堆栈溢出
堆溢出的一个关键问题是很难找到所谓的重要变量,而堆栈溢出则不存在这个问题,因为它将覆盖一个非常重要的东西----函数的返回地址。在进行函数调用的时候,断点或者说返回地址将保存到堆栈里面,以便函数结束之后继续运行。而堆栈溢出的思路就是在函数里面找到一个溢出点,把堆栈里面的返回地址覆盖,替换成一个自己指定的地方,而在那个地方,我们将把一些精心设计了的攻击代码。由于攻击代码的编写需要一些汇编知识,这里我将不打算涉及。我们这里的目标是写出一个通过覆盖堆栈返回地址而让程序执行到另一个函数的堆栈溢出演示程序。
因为堆栈是往下增加的,因此,先进入堆栈的地址反而要大,这为在函数中找到溢出点提供了可能。试想,而堆栈是往上增加的,我们将永远无法在函数里面找到一个溢出点去覆盖返回地址。还是先从一个最简单的例子开始:
void test(int i)
{
char buf[12];
}
void main()
{
test(1);
}
test 函数具有一个局部参数和一个静态分配的缓冲区。为了查看这两个变量所在的内存地址(彼此相对的地址),我们将对代码略作修改:
void test(int i)
{
char buf[12];
printf("&i = %d/n", &i);
printf("&buf[0] = %d/n", buf);
}
void main()
{
test(1);
}
需要说明的是,由于个人习惯的原因,我把地址结果输出成10进制形式,但愿这并不影响文章的叙述。在我这里,产生下列输出:&i = 6684072 &buf[0] = 6684052。这里我补充一下,当调用一个函数的时候,首先是参数入栈,然后是返回地址。并且,这些数据都是倒着表示的,因为返回地址是4个字节,所以可以知道,返回地址应该是保存在从6684068到6684071。因为数据是倒着表示的,所以实际上返回地址就是:buf[19]*256*256*256+buf[18]*256*256+buf[17]*256+buf[16]。
我们的目标还没有达到,下面我们继续。在上面程序的基础,修改成:
#include <stdio.h>
void main()
{
void test(int i);
test(1);
}
void test(int i)
{
void come();
char buf[12];//用于发生溢出的数组
int addr[4];
int k=(int)&i-(int)buf;//计算参数到溢出数组之间的距离
int go=(int)&come;
//由于EIP地址是倒着表示的,所以首先把come()函数的地址分离成字节
addr[0]=(go << 24)>>24;
addr[1]=(go << 16)>>24;
addr[2]=(go << 8)>>24;
addr[3]=go>>24;
//用come()函数的地址覆盖EIP
for(int j=0;j<4;j++)
{
buf[k-j-1]=addr[3-j];
}
}
void come()
{
printf("Success!");
}
一切搞定!运行之后,"Success!"成功打印出来!不过,由于这个程序破坏了堆栈,所以系统会提示程序遇到问题需要关闭。但这并不要紧,因为至少我们已经迈出了万里长征的第一步。
Ⅱ 用C语言编译6度隔离理论
我不明白 六度隔离 理论,请在 补充回答 里说明。
比如一共30人,分别是1到30号。
而且,1号只认识2号,2号只认识3号……
那么,1号认识30号就需要28个人了。
所以,六度隔离 理论是不是有什么具体说明和限制,请说明,谢谢。
--------------------------------我来补充回答了--------------------------------
对不起,请不要复制网上的理论!
那个我在当初回答你的问题时就看过了,而且比你复制的全多了。
我有些不理解这个理论,具体不理解的地方也写在上面了。
所以希望你可以给我解释,然后我才能帮你编程,明白?
Ⅲ 沙漏C语言命令
用解析几何的做法比较好,就是那两条直线外的点为空白,直线内的区域为*即可,使用坐标法解。给你个框架,自己添加个头文件和return,你应该知道怎么做吧。
for(inti=0;i<9;i++)
for(intj=0;j<9;j++)
if(j>i&&(j-9<9-i))
printf("*");
else
printf("");
printf(" ");
Ⅳ C语言鼠标如何显示沙漏,求代码
循环调用API函数SetCursor设置鼠标光标,就可以了吧?我的C语言后半没学好,之前用Vb做过。
Vb的VB声明
Declare Function SetCursor Lib "user32" Alias "SetCursor" (ByVal hCursor As Long) As Long
说明
将指定的鼠标指针设为当前指针
返回值
Long,前一个指针的值
参数表
参数 类型及说明
hCursor Long,要设为当前指针的一个指针的句柄。如设为零,表示不显示任何指针
注解
在vb里这个函数不能很好的工作,因为vb习惯在不同的时间将指针变回原来的样子
该API函数是调用User32.dll动态库的
Ⅳ 关于C语言的:一个程序的漏洞修补
我觉得这题最好用switch分支,而且既然在“printf("请选择运算符号(1为加,2为减,3为乘,4为除,5为关闭程序),程序会自动生成一个运算数不超过2位数的算术式:"); ”输入字母时判断为错误,我觉得后面就没有再输入答案的必要了,所以我改为在“printf("请选择运算符号(1为加,2为减,3为乘,4为除,5为关闭程序),程序会自动生成一个运算数不超过2位数的算术式:"); ”前加一个" Loop:",把continue改为goto Loop;虽然在C中goto语句最好不使用,但我觉得这题足取!
Ⅵ c语言打印沙漏
写一个函数a,用于打印一行, 弄几个参数, 分别控制前面的空格的数量和*的熟练
写个函数b, 在里面调用a, 传入不同的参数, 自己多练练, 没人会往你手里塞钱的, 需要自己探索
Ⅶ 为什么C语言变量的地址每一次运行都是一样的,在360隔离沙箱里运行也是一样的
变量地址是由编译器决定的
360隔离沙箱是不让程序写入磁盘,不是不让程序加载内存
Ⅷ c语言:打印沙漏求大神讲解意思
#include<stdio.h>
intmain()
{intsum,b,i,q,t,k,j,g,N;
charc;
sum=1;b=1;
scanf("%d%c",&N,&c);
for(i=1;sum<=N;i++)
{ b=b+2;//3+5+...
sum=sum+b*2;}//当sum大于N时结束循环,所需要的sum应为sum-2*b
i=i-1;
q=i;//保存沙漏的下半部分有多少行
sum=sum-2*b;//最大的沙漏所需要的字符数
k=0;
for(j=i;j>=1;j--)//后面没什么好说的,就是正常的分成上下两部分,然后找行数和每行空格、字符数的关系
{for(g=1;g<=k;g++)
printf("");
for(t=1;t<=2*j-1;t++)
printf("%c",c);
printf(" ");
k++;
}
k=k-2;
for(j=2;j<=q;j++)
{for(g=1;g<=k;g++)
printf("");
for(t=1;t<=2*j-1;t++)
printf("%c",c);
printf(" ");
k--;}
printf("%d",N-sum);
return0;
}
Ⅸ c语言 输出*形沙漏
#include <stdio.h >
void main ()
{
int i ,j, k, n;
scanf ("%d ",&n);
for (i =0 ;i<n;i++)
{
for (j =0 ;j <2*n;j++)
printf ("*");
printf ("\n");
}
for (i=1; i<=n-2;i++)
{for (j =1 ;j <=i;j++)
printf (" ");
for (k =1;k<=2*n-2*i;k++)
printf ("*");
printf ("\n");}
for (i =2;i<=n-2;i++)
{for(j =2;j>=i;j--)
{printf (" ");
}
for(k=1;k<=2*n-2*i;k++)
printf("*");
printf ("\n");}
for (i =0;i<n;i++)
{for (j=0;j<2*n;j++)
printf ("*");
printf ("\n");}
}
因电脑故障这个程序没有调试,若有错误请您见谅
Ⅹ C语言如何将一段程序隔离出来正在编程,急急急!如题 谢谢了
首先,可以用中断,第二简单的比如,用一个标志位,i=xx;while(i--){一直在执行的语句 };{过段时间才执行的程序;},i=xx; 使用中断就可以了 查看原帖>>