缓冲区溢出解密二

所属分类: 网络安全 / 加密解密 阅读数: 107
收藏 0 赞 0 分享

而如果ESP被PUSH到堆栈,这是堆栈的表示:
|_parametre_I___| EBP 12
|_parametre II__| EBP 8
|_return adress_| EBP 4
|___saved_ESP___| EBP ESP
|_local var I __| EBP-4
|_local var II__| EBP-8
在上面的图中,变量I 和II是传递给函数的参数。在返回地址和保存ESP之后,var I和II是函数的局部变量。现在,如果我们总结所有我们所讲的,当调用一个函数的时候:
1.我们保存老的堆栈指针,PUSH它到堆栈 2.我们保存下一个指令的地址(返回地址),PUSH它到堆栈。3.我们开始执行程序指令。
当我们调用一个函数时,上面3步都做了。
让我们在一个生动的例子中看堆栈的操作。
a.c :
void f(int a, int b, int c)
{
char z[4];
}
void main()
{
f(1, 2, 3);
} 用-g标志编译这个从而能够调试:
[murat@victim murat]$ gcc -g a.c -o a
让我们看看这里发生了什么:
[murat@victim murat]$ gdb -q ./a
(gdb) disas main
Dump of assembler code for function main:
0x8048448 : pushl 雙
0x8048449 : movl %esp,雙
0x804844b : pushl $0x3
0x804844d : pushl $0x2
0x804844f : pushl $0x1
0x8048451 : call 0x8048440
0x8048456 : addl $0xc,%esp
0x8048459 : leave
0x804845a : ret
End of assembler dump.
(gdb)
以上可见,main()函数中第一个指令是:
0x8048448 : pushl 雙
它支持老的指针,并把它压入堆栈。接着,拷贝老的堆栈指针倒ebp寄存器:
0x8048449 : movl %esp,雙
因而,从那时起,在函数中,我们将用EBP引用函数的局部变量。这两个指令被称为”程序引入”。接着,我们反序PUSH函数f()的参数到堆栈中。
0x804844b : pushl $0x3
0x804844d : pushl $0x2
0x804844f : pushl $0x1
我们调用这个函数:
0x8048451 : call 0x8048440
如我们已经通过CALL调用解释的那样,我们PUSH指令addl $0xc,%esp的地址0x8048456到堆栈。函数RET调用后,我们加12或者十六进制中的0xc(因为我们推入3个参数到堆栈中,每一个分配了4个字节(整型))。 接着我们离开main()函数,并且返回:
0x8048459 : leave
0x804845a : ret
好,在函数f()内部发生了什么呢?
(gdb)
disas f
Dump of assembler code for function f:
0x8048440 : pushl 雙
0x8048441 : movl %esp,雙
0x8048443 : subl $0x4,%esp
0x8048446 : leave
0x8048447 : ret
End of assembler dump.
(gdb)
开始两个指令都是一样的。它们是程序引入。接着我们看a:
0x8048443 : subl $0x4,%esp
从ESP减去了4个字节。这是为局部变量z分配空间。记得我们定义它为char z[4]?它是一个4字节的字符数组。最后,在末尾,函数返回:
0x8048446 : leave
0x8048447 : ret

好,让我们看另外一个例子:
b.c :
void f(int a, int b, int c)
{
char foo1[6];
char foo2[9];
}
void main()
{
f(1,2,3);
}
编译并且启动gdb,解析f:
[murat@victim murat]$ gcc -g b.c -o b
[murat@victim murat]$ gdb -q ./b
(gdb) disas f
Dump of assembler code for function f:
0x8048440 : pushl 雙
0x8048441 : movl %esp,雙
0x8048443 : subl $0x14,%esp
0x8048446 : leave
0x8048447 : ret
End of assembler dump.
(gdb)
可以看出,从ESP中减去了0x14(20字节),尽管foo1和foo2的总长度只有9 6=15。这样的原因是,内存,还有堆栈,在4字节框架下编址。这意味着,你不能简单的PUSH 1字节数据到堆栈中。或者4字节或者为空。 f()北调用时,堆栈将象这样:
|_______$1_______| EBP 16
|_______$2_______| EBP 12
|_______$3_______| EBP 8
|_return address_| EBP 4
|___saved_ESP____| EBP ESP
|______foo1______| EBP-4
|______foo1______| EBP-8
|______foo2______| EBP-12
|______foo2______| EBP-16
|______foo2______| EBP-20
你可以相信,当我们对f001装载超过8个字节对和对foo2超过12个字节,我们将溢出他们的空间。如果你对foo1写入超过4个字节,你将重写被保护的EBP,而且……如果你写入超过4个字节,你将重写返回地址……而这不正是我们都想要的吗?这是内存溢出的基础……让我设法用一段简单的代码稍微阐明一下这种现象,假设我们有这样的代码:
c.c :
#include
void f(char *str)
{
char foo[16];
strcpy(foo, str);
}
void main()
{
char large_one[256];
memset(large_one, 'A', 255);
f(large_one);
}
[murat@victim murat]$ make c
cc -W -Wall -pedantic -g c.c -o c
[murat@victim murat]$ ./c
Segmentation fault (core dumped)
[murat@victim murat]$
我们在上面做的是简单的写255字节到一个只能容纳16字节的数组里。我们传递了一个256字节的大数组作为一个参数给f()函数。在函数内部,没有边界检测我们拷贝了整个large_one到foo,溢出了foo和其它数据。因此缓冲区被填写了,同样的strcpy()用A填写了内存的其它部分,包括返回地址。
这里是用gdb生成核文件代码的检查:
[murat@victim murat]$ gdb -q c core
Core was generated by `./c'.
Program terminated with signal 11, Segmentation fault.
find_solib: Can't read pathname for load map: Input/output error
#0 0x41414141 in ?? ()
(gdb)
可以看出,CPU在EIP中看到0x41414141(041是字母A的十六进制ASCII码),试图存储和执行此处的指令。然而,0x41414141不是我们的程序被允许存储的内存地址。最后操作系统发了一个SIGSEGV(Segmentation Violation)段侵犯信号给程序并且停止了任何进一步的操作。
我们调用f()时,堆栈看起来象这样:
|______*str______| EBP 8
|_return address_| EBP 4
|___saved_ESP____| EBP ESP
|______foo1______| EBP-4
|______foo1______| EBP-8
|______foo1______| EBP-12
|______foo1______| EBP-16
strcpy()从foo1的开头,EBP-16开始,拷贝large_one到foo,没有边界检查,用A填充了整个堆栈。
现在我们能够重写返回地址,如果我们放一些其它的内存段地址,我们能在那里执行指令码?答案是肯定的。假如我们放了一些 /bin/sh spawn出的指令在一些内存地址中,而我们把这个地址放到我们溢出的这个函数返回地址中,我们就能spawn出一个shell,而且很有可能,既然你已经对setuid二进制程序感兴趣了,我们将spawn出一个root shell。
更多精彩内容其他人还在看

详述破解技术中的暴力破解原理

不可不说一下学习破解的三个阶段:   初级,修改程序,用ultraedit等工具修改exe文件,称暴力破解,简称爆破。   中级,追出软件的注册码。   高级,写出注册机。   先说这爆破。所谓爆破,就是指通过修改可执行文件的源文件,来达到相应的目
收藏 0 赞 0 分享

简单不求人 轻松让你击破ATA硬盘密码

有些人利用ATA密码来保护储存在计算机硬盘中的数据,但是在大多数情况下攻击者都能轻松破译ATA密码,全面访问硬盘中的数据。 在美国,盗取个人及企业计算系统中的敏感信息已成为增长速度最快的罪行之一。据Gartner,IDC等分析机构统计,有近80%的笔记本电脑存有公司的
收藏 0 赞 0 分享

恢复MySQL密码笔记

因为MySQL密码存储于数据库mysql中的user表中 所以只需要将我windows 2003下的MySQL中的user表拷贝过来覆盖掉就行了 在c:mysqldatamysql(linux 则一般在/var/lib/mysql/mysql/)目录下有三个user表相关
收藏 0 赞 0 分享

验证码破解技术

所谓验证码,就是将一串随机产生的数字或符号,生成一幅图片,图片里加上一些干扰象素(防止OCR),由用户肉眼识别其中的验证码信息, 输入表单提交网站验证,验证成功后才能使用某项功能。不少网站为了防止用户利用机器人自动注册、登录、灌水,都采用了 验证码技术。
收藏 0 赞 0 分享

软件破解技术-注册机和补丁制作

概念介绍  何为注册机?注册机就是针对某一软件,通过一定算法算出注册码的程序。我们写注册机时,一般都要了解注册码的算法(这当然是通过跟踪调试了解的),之后用汇编语言或其它高级语言来把算法还原。这样大家可根据自己的要求输入注册码,如根据自己的姓名,
收藏 0 赞 0 分享

Linux系统中密码破解大全

(一)Linux 系统密码破解   1.在grub选项菜单按E进入编辑模式   2.编辑kernel那行 /init 1 (或/single)   3.按B重启   4.进入后执行下列命令   root@#passwd root (设置roo
收藏 0 赞 0 分享

教你在15秒内破解出cmos密码的方法

如果你只想"15秒绿色环保型"请直接看方法3:   *如果你想对cmos有个深入的了解或揪出本文理解的不足,请看方法0,1,2,3-:)   ----CMOS (Award)密码简介与破解0--3法----   计算机启动时,由存放在主板
收藏 0 赞 0 分享

OllyDBG反汇编破解Radmin密码

Radmin 是一款很不错的服务器管理 无论是 远程桌面控制 还是 文件传输 速度都很快 很方便 这样也形成了 很多服务器都装了 radmin这样的 现在你说 4899默认端口 没密码的 服务器你上哪找? 大家都知道radmin的密码都是32位m
收藏 0 赞 0 分享

破解PCAnyWhere远程连接的密码

由于NT的机器一般使用PCAnyWhere进行远程管理,Win2K的机器一般使用了终端进行远程管理,因此如果能够得到PCAnyWhere远程连接的帐号和密码,那么就能远程连接到主机。   问题的关键就是要得到PCAnyWhere的密码文件(*.CIF),然后使用PCa
收藏 0 赞 0 分享

软件破解之“动态跟踪分析”

一、SOFTICE 配制 虽然大部分 VB 程序仍调用 Win32 API 函数,但如想在 VB dll 运行库中设断的话,你就必须把 VB dll 运行库加入 SOFTICE 配制里去。 下例是在 win95/98 下你把相关的 VB DLL 运行库加入
收藏 0 赞 0 分享
查看更多