您的位置:首页 > 编程语言

一份简单的代码演示缓冲区溢出的危害

2014-01-19 14:08 323 查看
最近学习到《深入理解计算机系统》这边书的3.12节的缓冲区溢出,于是写了个简单的测试代码演示了一下通过缓冲区溢出是如何神不知鬼不觉的运行一段代码的。先上代码运行后再分析:
#include <stdio.h>
void hit()
{
unsigned char buff[ 100 ] =
{
0,0,0,0,	//返回地址
'B','O','M','B','\0',
0x83,0xc4,0x80,             //add    $0xffffff80,%esp
0x8b,0x44,0x24,0x0c,        //mov    0x0c(%esp),%eax
0xff,0xf0,                  //push   %eax
0x55,                      	//push   %ebp
0x89,0xe5,                  //mov    %esp,%ebp
0x83,0xec,0x18,             //sub    $0x18,%esp
0xc7,0x04,0x24,0,0,0,0,    	//movl   $0x402080,(%esp)
0xe8,0,0,0,0,          		//call   401278 <_puts>
0xc9,                      	//leave
0xc3,                      	//ret
};
*(unsigned int*)&buff[27] = (unsigned int)&buff[4];
*(unsigned int*)&buff[32] = (unsigned int)puts - (unsigned int)&buff[36];
*(unsigned int*)&buff[0] = *(unsigned int*)&buff[sizeof(buff)+12];
/* 缓冲区溢出:buff[sizeof(buff)+12]的数据被修改
* 然而编译的结果可以看到buff[sizeof(buff)+12]这个地址刚好是
* hit函数返回到main时所保存的main函数的下一条指令地址
* main函数的栈帧被破坏,结果导致错误指令的执行
*/
*(unsigned int*)&buff[sizeof(buff)+12] = (unsigned int)&buff[9];
}
void main()
{
/*
* 如果栈帧不被破坏,则hit函数无任何意义
* 栈被破坏,神不知鬼不觉的运行了一个函数 puts("BOMB");
*/
hit();
printf("\n\n%08x\n",puts);
}
然后我在cygwin中编译运行这段代码:
gcc 版本 4.8.2 (GCC)

hp@hp-PC ~/c
$ gcc y.c

hp@hp-PC ~/c
$ ./a.exe
BOMB

004012e8
从代码上看,hit函数什么也没做就是往buff内填充数据,然后是输出的puts函数的地址,但是运行后却发现多了一个BOMB的输出。再来看看hit函数的汇编代码。
hp@hp-PC ~/c
$ gcc -c y.c && objdump -d y.o

y.o:     文件格式 pe-i386

Disassembly of section .text:

00000000 <_hit>:
0:   55                      push   %ebp
1:   89 e5                   mov    %esp,%ebp
3:   57                      push   %edi
4:   53                      push   %ebx
5:   83 ec 70                sub    $0x70,%esp
8:   8d 5d 94                lea    -0x6c(%ebp),%ebx
b:   b8 00 00 00 00          mov    $0x0,%eax
10:   ba 19 00 00 00          mov    $0x19,%edx
15:   89 df                   mov    %ebx,%edi
17:   89 d1                   mov    %edx,%ecx
19:   f3 ab                   rep stos %eax,%es:(%edi)
1b:   c6 45 98 42             movb   $0x42,-0x68(%ebp)
1f:   c6 45 99 4f             movb   $0x4f,-0x67(%ebp)
23:   c6 45 9a 4d             movb   $0x4d,-0x66(%ebp)
27:   c6 45 9b 42             movb   $0x42,-0x65(%ebp)
2b:   c6 45 9d 83             movb   $0x83,-0x63(%ebp)
2f:   c6 45 9e c4             movb   $0xc4,-0x62(%ebp)
33:   c6 45 9f 80             movb   $0x80,-0x61(%ebp)
37:   c6 45 a0 8b             movb   $0x8b,-0x60(%ebp)
3b:   c6 45 a1 44             movb   $0x44,-0x5f(%ebp)
3f:   c6 45 a2 24             movb   $0x24,-0x5e(%ebp)
43:   c6 45 a3 0c             movb   $0xc,-0x5d(%ebp)
47:   c6 45 a4 ff             movb   $0xff,-0x5c(%ebp)
4b:   c6 45 a5 f0             movb   $0xf0,-0x5b(%ebp)
4f:   c6 45 a6 55             movb   $0x55,-0x5a(%ebp)
53:   c6 45 a7 89             movb   $0x89,-0x59(%ebp)
57:   c6 45 a8 e5             movb   $0xe5,-0x58(%ebp)
5b:   c6 45 a9 83             movb   $0x83,-0x57(%ebp)
5f:   c6 45 aa ec             movb   $0xec,-0x56(%ebp)
63:   c6 45 ab 18             movb   $0x18,-0x55(%ebp)
67:   c6 45 ac c7             movb   $0xc7,-0x54(%ebp)
6b:   c6 45 ad 04             movb   $0x4,-0x53(%ebp)
6f:   c6 45 ae 24             movb   $0x24,-0x52(%ebp)
73:   c6 45 b3 e8             movb   $0xe8,-0x4d(%ebp)
77:   c6 45 b8 c9             movb   $0xc9,-0x48(%ebp)
7b:   c6 45 b9 c3             movb   $0xc3,-0x47(%ebp)
7f:   8d 45 94                lea    -0x6c(%ebp),%eax
82:   83 c0 1b                add    $0x1b,%eax
85:   8d 55 94                lea    -0x6c(%ebp),%edx
88:   83 c2 04                add    $0x4,%edx
8b:   89 10                   mov    %edx,(%eax)
8d:   8d 45 94                lea    -0x6c(%ebp),%eax
90:   83 c0 20                add    $0x20,%eax
93:   ba 00 00 00 00          mov    $0x0,%edx
98:   8d 4d 94                lea    -0x6c(%ebp),%ecx
9b:   83 c1 24                add    $0x24,%ecx
9e:   29 ca                   sub    %ecx,%edx
a0:   89 10                   mov    %edx,(%eax)
a2:   8d 45 94                lea    -0x6c(%ebp),%eax
a5:   8d 55 94                lea    -0x6c(%ebp),%edx
a8:   83 c2 70                add    $0x70,%edx
ab:   8b 12                   mov    (%edx),%edx
ad:   89 10                   mov    %edx,(%eax)
af:   8d 45 94                lea    -0x6c(%ebp),%eax
b2:   83 c0 70                add    $0x70,%eax
b5:   8d 55 94                lea    -0x6c(%ebp),%edx
b8:   83 c2 09                add    $0x9,%edx
bb:   89 10                   mov    %edx,(%eax)
bd:   83 c4 70                add    $0x70,%esp
c0:   5b                      pop    %ebx
c1:   5f                      pop    %edi
c2:   5d                      pop    %ebp
c3:   c3                      ret

000000c4 <_main>:
c4:   55                      push   %ebp
c5:   89 e5                   mov    %esp,%ebp
c7:   83 e4 f0                and    $0xfffffff0,%esp
ca:   83 ec 10                sub    $0x10,%esp
cd:   e8 00 00 00 00          call   d2 <_main+0xe>
d2:   e8 29 ff ff ff          call   0 <_hit>
d7:   c7 44 24 04 00 00 00    movl   $0x0,0x4(%esp)
de:   00
df:   c7 04 24 00 00 00 00    movl   $0x0,(%esp)
e6:   e8 00 00 00 00          call   eb <_main+0x27>
eb:   c9                      leave
ec:   c3                      ret
ed:   90                      nop
ee:   90                      nop
ef:   90                      nop

hp@hp-PC ~/c
$
hit函数什么也没做,但是buff的缓冲区溢出了,在sizeof(buff) + 12的位置上写入了一个地址。然而这个位置却恰好是,main函数中hit();调用后面的一条指令地址,在汇编语句上就是 d7: c7 44 24 04 00 00 00 movl $0x0,0x4(%esp) 这条指令的地址。代码进入hit函数后的栈帧如下:
|
|
| 返回地址 |
|   %ebp   |          <- %ebp
|   %edi   |
|   %ebx   |
|
|   ...
|
| 0xc3,                  ret
| c9                     leave
| e8 0 0 0 0           	 call   <_puts>
| c7 04 24 0 0 0 0     	 movl   $0,(%esp)
| 83 ec 18               sub    $0x18,%esp
| 89 e5                  mov    %esp,%ebp
| 55                     push   %ebp
| ff f0                  push   %eax
| 8b 44 24 0c            mov    0x0c(%esp),%eax
| 83 c4 80               add    $0xffffff80,%esp
| B  O  M  B \0
| 返回地址 |         <-  buff  将原始的返回地址存储在buff中
|
|          |        <-  %esp
main函数的call 0<_hit> 指令调用后,就进入_hit函数,首先将 %ebp %edi %ebx 顺序压入堆栈,然后将 %esp指针进去0x70,在栈上为buff数组分配空间。buff数组中填入了危险的数据,这些数据是病毒指令,注意栈图上列出来的指令是倒置的。当hit函数的ret指令开始运行时,栈帧如下:
|          |
|    ...
|
| 病毒地址 |
|   %ebp   |
|   %edi   |
|   %ebx   |
|
|   ...
|
| 0xc3,                  ret
| c9                     leave
| e8 0 0 0 0           	 call   401278 <_puts>
| c7 04 24 0 0 0 0     	 movl   $0,(%esp)        <- %eip
| 83 ec 18               sub    $0x18,%esp
| 89 e5                  mov    %esp,%ebp
| 55                     push   %ebp
| ff f0                  push   %eax
| 8b 44 24 0c            mov    0x0c(%esp),%eax
| 83 c4 80               add    $0xffffff80,%esp
| B  O  M  B \0
| 返回地址 |              将原始的返回地址存储在buff中
|
|
将原始的返回地址存储在buff中将原始的返回地址存储在buff中
虽然hit函数的栈帧被释放了,为buff分配的栈空间已经收回去了,%esp的指针已经指向了返回地址处,但栈上存储的病毒数据并未被清空。接着ret指令执行完成后,就要跳转到第一个病毒代码运行,病毒代码是在栈上运行的。病毒地址就指向了 buff+9的地址处,这就是一条 add    $0xffffff80,%esp 指令。
ret运行完,并执行完病毒的6条指令后的栈空间如下:
	|          ||    ...|| 病毒地址 ||   %ebp   ||   %edi   ||   %ebx   |||   ...|| 0xc3,                  ret| c9                     leave| e8 0 0 0 0           	 call   401278 <_puts>| c7 04 24 0 0 0 0     	 movl   $0,(%esp)        <- %eip| 83 ec 18               sub    $0x18,%esp| 89 e5                  mov    %esp,%ebp| 55                     push   %ebp| ff f0                  push   %eax| 8b 44 24 0c            mov    0x0c(%esp),%eax| 83 c4 80               add    $0xffffff80,%esp| B  O  M  B \0| 返回地址 |             将原始的返回地址存储在buff中|| 返回地址 |             把返回地址再搬回到栈上|   %ebp   |         <- %ebp|          ||    ..    ||          |         <- %esp 
在栈上的病毒指令调用了puts(BOMB)函数后,就又返回到原先的地址开始运行,神不知鬼不觉的运行了一个函数。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: