首 页文章中心

Linux学习网

您的位置Linux学习网 > Linux综合 > 文章内容

缓冲区溢出编程心得

作者:佚名  来源:不详  发布时间:2007-12-21 16:48:00
前言:网上关于缓冲区溢出的资料也有很多,但我在阅读过程中发现介绍的都不是很明了,而且各网站也只是转贴老外的那篇译文而已,不仅内容有缺损,而且程序也无法调通,因为GCC版本不一样.经过几天的琢磨,终于明白了真正的原理,特地写出来分享.HBCLinux联盟
HBCLinux联盟
测试环境:HBCLinux联盟
$ gcc -vHBCLinux联盟
Reading specs from /usr/lib/gcc-lib/i386-redhat-linux/3.2.3/specsHBCLinux联盟
Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --enable-shared --enable-threads=posix --disable-checking --with-system-zlib --enable-__cxa_atexit --host=i386-redhat-linuxHBCLinux联盟
Thread model: posixHBCLinux联盟
gcc version 3.2.3 20030502 (Red Hat Linux 3.2.3-24)HBCLinux联盟
HBCLinux联盟
$ gdb -vHBCLinux联盟
GNU gdb Red Hat Linux (6.0post-0.20031117.6rh)HBCLinux联盟
Copyright 2003 Free Software Foundation, Inc.HBCLinux联盟
GDB is free software, covered by the GNU General Public License, and you areHBCLinux联盟
welcome to change it and/or distribute copies of it under certain conditions.HBCLinux联盟
Type "show copying" to see the conditions.HBCLinux联盟
There is absolutely no warranty for GDB. Type "show warranty" for details.HBCLinux联盟
This GDB was configured as "i386-redhat-linux-gnu".HBCLinux联盟
HBCLinux联盟
$ uname -aHBCLinux联盟
Linux candy 2.4.21-9.EL #1 Thu Jan 8 17:03:13 EST 2004 i686 athlon i386 GNU/LinuxHBCLinux联盟
HBCLinux联盟
实例:HBCLinux联盟
网上和我的这个实例雷同的也有,但是他们的是无法正确实现的.因为关键的跳转代码没有计算正确.(GCC版本问题,呵呵)HBCLinux联盟
/************HBCLinux联盟
* a.cHBCLinux联盟
************/HBCLinux联盟
void function(void)HBCLinux联盟
{HBCLinux联盟
char buffer[5];HBCLinux联盟
int* ret;HBCLinux联盟
HBCLinux联盟
ret=buffer+28;HBCLinux联盟
(*ret)+=10;HBCLinux联盟
}HBCLinux联盟
HBCLinux联盟
void main()HBCLinux联盟
{HBCLinux联盟
int x;HBCLinux联盟
HBCLinux联盟
x=0;HBCLinux联盟
function();HBCLinux联盟
HBCLinux联盟
x=1;HBCLinux联盟
printf("%d\n",x);HBCLinux联盟
HBCLinux联盟
return;HBCLinux联盟
}HBCLinux联盟
/*end*/HBCLinux联盟
HBCLinux联盟
懂C语言的人都会认为最后的输出结果是1,可惜输出结果为0.为什么呢?请听解释.HBCLinux联盟
HBCLinux联盟
实例分析:HBCLinux联盟
相关堆栈的基础知识我就不罗嗦了,网上的介绍很多.HBCLinux联盟
关键问题在于如何确定源代码HBCLinux联盟
ret=buffer+28;HBCLinux联盟
(*ret)+=10;HBCLinux联盟
中的28 和 10HBCLinux联盟
HBCLinux联盟
编译(会有warning,不用管他.)HBCLinux联盟
$gcc -g -o a a.c //加上-g 用来在gdb中调试HBCLinux联盟
HBCLinux联盟
$gdb aHBCLinux联盟
(gdb)disas main //得到反汇编代码 如下:HBCLinux联盟
Dump of assembler code for function main:HBCLinux联盟
0x08048366 : push %ebpHBCLinux联盟
0x08048367 : mov %esp,%ebpHBCLinux联盟
0x08048369 : sub $0x8,%espHBCLinux联盟
0x0804836c : and $0xfffffff0,%espHBCLinux联盟
0x0804836f : mov $0x0,%eaxHBCLinux联盟
0x08048374 : sub %eax,%espHBCLinux联盟
0x08048376 : movl $0x0,0xfffffffc(%ebp)HBCLinux联盟
0x0804837d : call 0x8048348 HBCLinux联盟
0x08048382 : movl $0x1,0xfffffffc(%ebp)HBCLinux联盟
0x08048389 : sub $0x8,%espHBCLinux联盟
0x0804838c : pushl 0xfffffffc(%ebp)HBCLinux联盟
0x0804838f : push $0x8048474HBCLinux联盟
0x08048394 : call 0x8048288HBCLinux联盟
0x08048399 : add $0x10,%espHBCLinux联盟
0x0804839c : leaveHBCLinux联盟
0x0804839d : retHBCLinux联盟
End of assembler dump.HBCLinux联盟
HBCLinux联盟
(gdb)disas functionHBCLinux联盟
Dump of assembler code for function function:HBCLinux联盟
0x08048348 : push %ebpHBCLinux联盟
0x08048349 : mov %esp,%ebpHBCLinux联盟
0x0804834b : sub $0x28,%espHBCLinux联盟
0x0804834e : lea 0xffffffe8(%ebp),%eaxHBCLinux联盟
0x08048351 : add $0x1c,%eaxHBCLinux联盟
0x08048354 : mov %eax,0xffffffe4(%ebp)HBCLinux联盟
0x08048357 : mov 0xffffffe4(%ebp),%edxHBCLinux联盟
0x0804835a : mov 0xffffffe4(%ebp),%eaxHBCLinux联盟
0x0804835d : mov (%eax),%eaxHBCLinux联盟
0x0804835f : add $0xa,%eaxHBCLinux联盟
0x08048362 : mov %eax,(%edx)HBCLinux联盟
0x08048364 : leaveHBCLinux联盟
0x08048365 : retHBCLinux联盟
End of assembler dump.HBCLinux联盟
HBCLinux联盟
可以得知当main中执行 0x0804837d : call 0x8048348 < function> 时 会将下一条指令的地址保存在堆栈中. 即 0x08048382 我们的目的就是要想这个值修改成下一条指令的地址 0x08048389 这样就达到了屏蔽 x=1 这条语句了. 关键问题在于如何寻找保存0x08048382这个值的地址....HBCLinux联盟
HBCLinux联盟
继续使用gdbHBCLinux联盟
(gdb) l //显示源代码(因为编译时用了 -g 参数)HBCLinux联盟
5HBCLinux联盟
6 ret=buffer+28;HBCLinux联盟
7 (*ret)+=10;HBCLinux联盟
8 }HBCLinux联盟
9HBCLinux联盟
10 void main()HBCLinux联盟
11 {HBCLinux联盟
12 int x;HBCLinux联盟
13HBCLinux联盟
14 x=0;HBCLinux联盟
HBCLinux联盟
(gdb)b 6 // 在关键处下断点 观察内存的值HBCLinux联盟
Breakpoint 1 at 0x804834e: file a.c, line 6.HBCLinux联盟
(gdb)b 7HBCLinux联盟
Breakpoint 2 at 0x8048357: file a.c, line 7.HBCLinux联盟
(gdb)r HBCLinux联盟
Breakpoint 1, function () at rr.c:6HBCLinux联盟
6 ret=buffer+28;HBCLinux联盟
(gdb)i reg //观察寄存器的值 (注意ebp esp eip)HBCLinux联盟
eax 0x0 0HBCLinux联盟
ecx 0xbffff01c -1073745892HBCLinux联盟
edx 0xbfffefa0 -1073746016HBCLinux联盟
ebx 0xb75d4e58 -1218621864HBCLinux联盟
esp 0xbfffef50 0xbfffef50HBCLinux联盟
ebp 0xbfffef78 0xbfffef78HBCLinux联盟
esi 0xbffff014 -1073745900HBCLinux联盟
edi 0xb75d273c -1218631876HBCLinux联盟
eip 0x804834e 0x804834eHBCLinux联盟
eflags 0x200286 2097798HBCLinux联盟
cs 0x23 35HBCLinux联盟
ss 0x2b 43HBCLinux联盟
ds 0x2b 43HBCLinux联盟
es 0x2b 43HBCLinux联盟
fs 0x0 0HBCLinux联盟
gs 0x33 51HBCLinux联盟
HBCLinux联盟
看见esp的值为0xbfffef50HBCLinux联盟
接着查看内存中0xbfffef50后面的数据内容HBCLinux联盟
(gdb)x/20x $espHBCLinux联盟
0xbfffef50: 0x080483a0 0x08049564 0xbfffef68 0x08048265HBCLinux联盟
0xbfffef60: 0x00000000 0x00000000 0xbfffef88 0x080483baHBCLinux联盟
0xbfffef70: 0xb74ca4f3 0xb75d4e58 0xbfffef88 0x08048382HBCLinux联盟
0xbfffef80: 0xb7600020 0x00000000 0xbfffefe8 0xb74b5748HBCLinux联盟
0xbfffef90: 0x00000001 0xbffff014 0xbffff01c 0x00000000HBCLinux联盟
可得到 在0xbfffef7c 中保存着 最初我们需要寻找的0x08048382 那么0xbfffef7c就是我们的程序里ret所要存储的内容了.HBCLinux联盟
(gdb)p &bufferHBCLinux联盟
$1 = (char (*)[5]) 0xbfffef60HBCLinux联盟
因此得到我们的第一个数据28 至于10则可以从反汇编的代码得到(移到下一条指令).HBCLinux联盟
HBCLinux联盟
(gdb)nHBCLinux联盟
(gdb)n //之后我们可以看到 0x08048382 变成了 0x0804838cHBCLinux联盟
HBCLinux联盟
(gdb)cHBCLinux联盟
Continuing.HBCLinux联盟
0HBCLinux联盟
HBCLinux联盟
Program exited with code 02.HBCLinux联盟
HBCLinux联盟
但真正想实现溢出提高权限 则需要shellcode 具体的定位方式需要具体分析,但原理和我上面将的是一样的了.HBCLinux联盟
HBCLinux联盟
收藏本页到: 365Key | del.icio.us | | 添加到雅虎收藏+
  • 网站帮助 - 广告合作 - 网站地图