文逸首页 小文论坛 文逸博客 精华文章
 首页 | 新闻 | 论坛 | 博客 | 专题 | FTP | 金融 | 微博 | 图库 | MyHome | 搜索 | 登陆 | 注册 | 帮助 | 设为首页  ·在线人数: 4272
 §您的位置:文逸首页 > jxkgd 's home > 【理论研究】专栏 > 缓冲区溢出原理.
jxkgd 的主页网址:http://wonyen.net/home.aspx?id=jxkgd 给我留言

 § jxkgd  的【理论研究】专栏

  作者:jxkgd  发表时间: 2005/5/12 12:52:17    查看: 2436     评论: 2
标题: 缓冲区溢出原理学习(二)

一个简单的堆栈例子
example1.c:
------------------------------------------------------------------
void function(int a, int b, int c) {
   char buffer1[5];
   char buffer2[10];
}
 
void main() {
  function(1,2,3);
}
------------------------------------------------------------------
    使用gcc的-S选项编译, 以产生汇编代码输出:
       $ gcc -S -o example1.s example1.c
 
    通过查看汇编语言输出, 我们看到对function()的调用被翻译成:
        pushl $3
        pushl $2
        pushl $1
        call function
  
    以从后往前的顺序将function的三个参数压入栈中, 然后调用function()。 指令call会把指令指针(IP)也压入栈中。 我们把这被保存的IP称为返回地址(RET)。 在函数中所做的第一件事情是例程的序幕工作:
        pushl %ebp
        movl %esp,%ebp
        subl $20,%esp
 
    将帧指针EBP压入栈中。 然后把当前的SP复制到EBP, 使其成为新的帧指针。 我们把这个被保存的FP叫做SFP。 接下来将SP的值减小, 为局部变量保留空间。
 
    内存只能以字为单位寻址。 一个字是4个字节, 32位。 因此5字节的缓冲区会占用8个字节(2个字)的内存空间, 而10个字节的缓冲区会占用12个字节(3个字)的内存空间。 这就是为什么SP要减掉20的原因。 这样我们就可以想象function()被调用时堆栈的模样(每个空格代表一个字节):
内存低地址                                            内存高地址
           buffer2       buffer1   sfp   ret   a     b     c
<------   [            ][        ][    ][    ][    ][    ][    ]
堆栈顶部                                                 堆栈底部

制造缓冲区溢出
    现在试着修改我们第一个例子, 让它可以覆盖返回地址, 而且使它可以执行任意代码。堆栈中在buffer1[]之前的是SFP, SFP之前是返回地址。 ret从buffer1[]的结尾算起是4个字节。应该记住的是buffer1[]实际上是2个字即8个字节长。 因此返回地址从buffer1[]的开头算起是12个字节。 我们会使用这种方法修改返回地址, 跳过函数调用后面的赋值语句'x=1;', 为了做到这一点我们把返回地址加上8个字节。 代码看起来是这样的:
 example3。c:
--------------------------------------------------------------------
void function(int a, int b, int c) {
   char buffer1[5];
   char buffer2[10];
   int *ret;
 
   ret = buffer1 + 12;
   (*ret) += 8;
}
 
void main() {
  int x;
 
  x = 0;
  function(1,2,3);
  x = 1;
  printf("%d\n",x);
}
-------------------------------------------------------------------
    我们把buffer1[]的地址加上12, 所得的新地址是返回地址储存的地方。 我们想跳过赋值语句而直接执行printf调用。

如何知道应该给返回地址加8个字节呢? 我们先前使用过一个试验值(比如1), 编译该程序, 祭出工具gdb:
 
-----------------------------------------------------------------
[aleph1]$ gdb example3
GDB is free software and you are welcome to 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。
GDB 4。15 (i586-unknown-linux), Copyright 1995 Free Software Foundation, Inc...
(no debugging symbols found)...
(gdb) disassemble main
Dump of assembler code for function main:
0x8000490 :       pushl  %ebp
0x8000491 :     movl   %esp,%ebp
0x8000493 :     subl   $0x4,%esp
0x8000496 :     movl   $0x0,0xfffffffc(%ebp)
0x800049d :    pushl  $0x3
0x800049f :    pushl  $0x2
0x80004a1 :    pushl  $0x1
0x80004a3 :    call   0x8000470 
0x80004a8 :    addl   $0xc,%esp
0x80004ab :    movl   $0x1,0xfffffffc(%ebp)
0x80004b2 :    movl   0xfffffffc(%ebp),%eax
0x80004b5 :    pushl  %eax
0x80004b6 :    pushl  $0x80004f8
0x80004bb :    call   0x8000378 
0x80004c0 :    addl   $0x8,%esp
0x80004c3 :    movl   %ebp,%esp
0x80004c5 :    popl   %ebp
0x80004c6 :    ret
0x80004c7 :    nop
------------------------------------------------------------------
 
    我们看到当调用function()时, RET会是0x8004a8, 我们希望跳过在0x80004ab的赋值指令。 下一个想要执行的指令在0x8004b2。 简单的计算告诉我们两个指令的距离为8字节。

 

分享到:


 §评论: 缓冲区溢出原理学习(二)

  回复者:wonyen    回复时间:2005/5/12 14:55:41    [第1评]
不错  再接再厉!


1 条评论;  每页显示 15 条评论;   1 / 1               ↑到页首




您未登陆,发表评论时请填写:用户名 密码 注册新用户  
 评论: 缓冲区溢出原理学习(二)
内容 (8000字以内)
 (CTRL+ENTER提交) 
  关闭窗口  
用户登陆
我要发表文章
搜 索
§jxkgd 的网志导航
感想随笔(0)
生活休闲(0)
饮食健康(0)
自然妙趣(0)
潮流时尚(0)
游览见闻(0)
情感绿洲(2)
娱乐搞笑(0)
读图时代(3)
影音视听(0)
商业新知(0)
理论研究(6)
时事纵横(0)
社会文化(0)
文学欣赏(0)
教育学习(2)
§jxkgd 的友情链接
关于文逸 | 小文论坛 | 文逸博客 | 文逸金融 | 精华文章网站地图 | 联系我们 | 隐私保护
 Copyright© WWW.WONYEN.NET 2003 - 2021  闽ICP备09016518号-16   本站最高 10508 人同时在线,发生时间 2005-5-17 5:09:15 
 文逸科技 制作维护