Java入门:缓冲区溢出编程心得

Java入门:缓冲区溢出编程心得2010-07-16 11:43 中国IT实验室 佚名 
关键字:Java 
  前言:网上关于缓冲区溢出的资料也有很多,但我在阅读过程中发现介绍的都不是很明了,而且各网站也只是转贴老外的那篇译文而已,不仅内容有缺损,而且程序也无法调通,因为GCC版本不一样.经过几天的琢磨,终于明白了真正的原理,特地写出来分享.


  测试环境:


  $ gcc -v


  Reading specs from /usr/lib/gcc-lib/i386-redhat-linux/3.2.3/specs


  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-linux


  Thread model: posix


  gcc version 3.2.3 20030502 (Red Hat Linux 3.2.3-24)


  $ gdb -v


  GNU gdb Red Hat Linux (6.0post-0.20031117.6rh)


  Copyright 2003 Free Software Foundation, Inc.


  GDB is free software, covered by the GNU General Public License, and you are


  welcome to change it and/or distribute copies of it under certain conditions.


  Type "show copying" to see the conditions.


  There is absolutely no warranty for GDB. Type "show warranty" for details.


  This GDB was configured as "i386-redhat-linux-gnu".


  $ uname -a


  Linux candy 2.4.21-9.EL #1 Thu Jan 8 17:03:13 EST 2004 i686 athlon i386 GNU/Linux


  实例:


  网上和我的这个实例雷同的也有,但是他们的是无法正确实现的.因为关键的跳转代码没有计算正确.(GCC版本问题,呵呵)


  /************


  * a.c


  ************/


  void function(void)


  {


  char buffer[5];


  int* ret;


  ret=buffer+28;


  (*ret)+=10;


  }


  void main()


  {


  int x;


  x=0;


  function();


  x=1;


  printf("%d\n",x);


  return;


  }


  /*end*/


  懂C语言的人都会认为最后的输出结果是1,可惜输出结果为0.为什么呢?请听解释.


  实例分析:


  相关堆栈的基础知识我就不罗嗦了,网上的介绍很多.


  关键问题在于如何确定源代码


  ret=buffer+28;


  (*ret)+=10;


  中的28 和 10


  编译(会有warning,不用管他.)


  $gcc -g -o a a.c //加上-g 用来在gdb中调试


  $gdb a


  (gdb)disas main //得到反汇编代码 如下:


  Dump of assembler code for function main:


  0x08048366 : push %ebp


  0x08048367 : mov %esp,%ebp


  0x08048369 : sub $0x8,%esp


  0x0804836c : and $0xfffffff0,%esp


  0x0804836f : mov $0x0,%eax


  0x08048374 : sub %eax,%esp


  0x08048376 : movl $0x0,0xfffffffc(%ebp)


  0x0804837d : call 0x8048348


  0x08048382 : movl $0x1,0xfffffffc(%ebp)


  0x08048389 : sub $0x8,%esp


  0x0804838c : pushl 0xfffffffc(%ebp)


  0x0804838f : push $0x8048474


  0x08048394 : call 0x8048288


  0x08048399 : add $0x10,%esp


  0x0804839c : leave


  0x0804839d : ret


  End of assembler dump.


  (gdb)disas function


  Dump of assembler code for function function:


  0x08048348 : push %ebp


  0x08048349 : mov %esp,%ebp


  0x0804834b : sub $0x28,%esp


  0x0804834e : lea 0xffffffe8(%ebp),%eax


  0x08048351 : add $0x1c,%eax


  0x08048354 : mov %eax,0xffffffe4(%ebp)


  0x08048357 : mov 0xffffffe4(%ebp),%edx


  0x0804835a : mov 0xffffffe4(%ebp),%eax


  0x0804835d : mov (%eax),%eax


  0x0804835f : add $0xa,%eax


  0x08048362 : mov %eax,(%edx)


  0x08048364 : leave


  0x08048365 : ret


  End of assembler dump.


  可以得知当main中执行 0x0804837d : call 0x8048348 时 会将下一条指令的地址保存在堆栈中. 即 0x08048382 我们的目的就是要想这个值修改成下一条指令的地址 0x08048389 这样就达到了屏蔽 x=1 这条语句了. 关键问题在于如何寻找保存0x08048382这个值的地址....


  继续使用gdb


  (gdb) l //显示源代码(因为编译时用了 -g 参数)


  5


  6 ret=buffer+28;


  7 (*ret)+=10;


  8 }


  9


  10 void main()


  11 {


  12 int x;


  13


  14 x=0;


  (gdb)b 6 // 在关键处下断点 观察内存的值


  Breakpoint 1 at 0x804834e: file a.c, line 6.


  (gdb)b 7


  Breakpoint 2 at 0x8048357: file a.c, line 7.


  (gdb)r


  Breakpoint 1, function () at rr.c:6


  6 ret=buffer+28;


  (gdb)i reg //观察寄存器的值 (注意ebp esp eip)


  eax 0x0 0


  ecx 0xbffff01c -1073745892


  edx 0xbfffefa0 -1073746016


  ebx 0xb75d4e58 -1218621864


  esp 0xbfffef50 0xbfffef50


  ebp 0xbfffef78 0xbfffef78


  esi 0xbffff014 -1073745900


  edi 0xb75d273c -1218631876


  eip 0x804834e 0x804834e


  eflags 0x200286 2097798


  cs 0x23 35


  ss 0x2b 43


  ds 0x2b 43


  es 0x2b 43


  fs 0x0 0


  gs 0x33 51


  看见esp的值为0xbfffef50


  接着查看内存中0xbfffef50后面的数据内容


  (gdb)x/20x $esp


  0xbfffef50: 0x080483a0 0x08049564 0xbfffef68 0x08048265


  0xbfffef60: 0x00000000 0x00000000 0xbfffef88 0x080483ba


  0xbfffef70: 0xb74ca4f3 0xb75d4e58 0xbfffef88 0x08048382


  0xbfffef80: 0xb7600020 0x00000000 0xbfffefe8 0xb74b5748


  0xbfffef90: 0x00000001 0xbffff014 0xbffff01c 0x00000000


  可得到 在0xbfffef7c 中保存着 最初我们需要寻找的0x08048382 那么0xbfffef7c就是我们的程序里ret所要存储的内容了.


  (gdb)p &buffer


  $1 = (char (*)[5]) 0xbfffef60


  因此得到我们的第一个数据28 至于10则可以从反汇编的代码得到(移到下一条指令).


  (gdb)n


  (gdb)n //之后我们可以看到 0x08048382 变成了 0x0804838c


  (gdb)c


  Continuing.


  0


  Program exited with code 02.


  但真正想实现溢出提高权限 则需要shellcode 具体的定位方式需要具体分析,但原理和我上面讲的是一样的了.


原文出自【比特网】,转载请保留原文链接:http://soft.chinabyte.com/database/440/11430940.shtml
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值