当前位置:编程问答 > 网站相关 >

缓冲区溢出

缓冲区溢出通常是向数组中写数据时,       写入的数据的长度超出了数组原始定义的大小。
比如前面你定义了 int buff[10],那么只有 buff[0] - buff[9]的空间是我们定义 buff 时
申请的合法空间,但后来往里面写入数据时出现了 buff[12]=0x10 则越界了。C 语言常用的
strcpy、sprintf、strcat 等函数都非常容易导致缓冲区溢出问题。
 
 
  查阅 C 语言编程的书籍时通常会告诉你程序溢出后会发生不可预料的结果。在网络安
全领域,缓冲区溢出利用的艺术在于让这个“不可预料的结果”变为我们期望的结果。
 
看下面这个演示程序:buf.c
/* buffer overflow example by watercloud@xfocus.org */
#include<stdio.h>
void why_here(void)   /*这个函数没有任何地方调用过 */
{
        printf("why u here ?!\n");
        _exit(0);
}
int main(int argc,char * argv[])
{
        int buff[1];
        buff[2]=(int)why_here;
        return 0;
}
 
在命令行用 VC 的命令行编译器编译(在 Linux 下用 gcc 编译并运行也是同样结果):
C:\Temp>cl buf.c
运行程序:
C:\Temp>buf.exe
why u here ?!
 
 
仔细分析程序和打印信息,你可以发现程序中我们没有调用过 why_here 函数,但该函数却
在运行的时候被调用了!!
 
 
这里唯一的解释是 buff[2]=why_here;操作导致了程序执行流程的变化。
 
要解释此现象需要理解一些 C 语言底层(和计算机体系结构相关)及一些汇编知识,尤其是
“栈”和汇编中 CALL/RET 的知识,如果这方面你尚有所欠缺的话建议参考一下相关书籍,
否则后面的内容会很难跟上。
 
 
假设你已经有了对栈的基本认识,我们来理解一下程序运行情况:
进入 main 函数后的栈内容下:
[ eip ][ ebp ][ buff[0] ]
高地址      <----    低地址
 
以上 3 个存储单元中 eip 为 main 函数的返回地址,buff[0]单元就是 buff 申明的一个 int
空间。程序中我们定义 int buff[1],那么只有对 buff[0]的操作才是合理的(我们只申请
了一个 int 空间) 而我们的 buff[2]=why_here 操作超出了 buff 的空间,
           ,                                     这个操作越界了,
也就是溢出了。溢出的后果是: 对 buff[2]赋值其实就是覆盖了栈中的 eip 存放单元的数
据,将 main 函数的返回地址改为了 why_here 函数的入口地址。这样 main 函数结束后返回
的时候将这个地址作为了返回地址而加以运行。
 
 
 
上面这个演示是缓冲区溢出最简单也是最核心的溢出本质的演示,需要仔细的理解。如果还
不太清楚的话可以结合对应的汇编代码理解。
 
用 VC 的命令行编译器编译的时候指定 FA 参数可以获得对应的汇编代码(Linux 平台可以用
gcc 的-S 参数获得):
 
 
C:\Temp>cl /FA tex.c
C:\Temp>type tex.asm
        TITLE   tex.c
        .386P
include listing.inc
if @Version gt 510
.model FLAT
else
_TEXT SEGMENT PARA USE32 PUBLIC 'CODE'
_TEXT ENDS
_DATA SEGMENT DWORD USE32 PUBLIC 'DATA'
_DATA ENDS
CONST SEGMENT DWORD USE32 PUBLIC 'CONST'
CONST     ENDS
_BSS      SEGMENT DWORD USE32 PUBLIC 'BSS'
_BSS      ENDS
$$SYMBOLS           SEGMENT BYTE USE32 'DEBSYM'
$$SYMBOLS           ENDS
_TLS      SEGMENT DWORD USE32 PUBLIC 'TLS'
_TLS      ENDS
FLAT      GROUP _DATA, CONST, _BSS
          ASSUME    CS: FLAT, DS: FLAT, SS: FLAT
endif
 
INCLUDELIB LIBC
INCLUDELIB OLDNAMES
 
_DATA     SEGMENT
$SG775 DB      'why u here ?!', 0aH, 00H
_DATA ENDS
PUBLIC _why_here
EXTRN     _printf:NEAR
EXTRN     __exit:NEAR
_TEXT     SEGMENT
_why_here PROC NEAR
        push    ebp
        mov     ebp, esp
        push    OFFSET FLAT:$SG775
        call    _printf
        add         esp, 4
        push        0
        call        __exit
        add         esp, 4
        pop         ebp
        ret         0
_why_here ENDP
_TEXT ENDS
 
PUBLIC    _main
_TEXT     SEGMENT
_buff$   = -4                                      ; size = 4
_argc$   =8                                        ; size = 4
_argv$   = 12                                      ; size = 4
_main     PROC NEAR
          push    ebp
          mov     ebp, esp
          push    ecx
        mov     DWORD PTR _buff$[ebp+8], OFFSET FLAT:_why_here
        xor     eax, eax
        mov     esp, ebp
        pop     ebp
        ret     0
_main   ENDP
_TEXT   ENDS
END
 
这个例子中我们溢出 buff 后覆盖了栈中的函数返回地址,由于覆盖数据为栈中的数据,所
以也称为栈溢出。对应的,如果溢出覆盖发生在堆中,则称为堆溢出,发生在已初始化数据
区的则称为已初始化数据区溢出。
 
实施对缓冲区溢出的利用(即攻击有此问题的程序)需要更多尚未涉及的主题:
 1. shellcode 功能
  2. shellcode 存放和地址定位
  3. 溢出地址定位
 
 
这些将在以后的章节中详细讲解。
 
 
SHELLCODE 基础
 
    溢出发生后要控制溢出后的行为关键就在于 shellcode 的功能。shellcode 其实就是一
段机器码。因为我们平时顶多用汇编写程序,绝对不会直接用机器码编写程序,所以感觉
shellcode 非常神秘。这里让我们来揭开其神秘面纱。
 
 
看看程序 shell0.c:
#include<stdio.h>
int add(int x,int y) {
        return x+y;
}
int main(void) {
        re
补充:综合编程 , 安全编程 ,
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,