扫一扫
分享文章到微信
扫一扫
关注官方公众号
至顶头条
一:shellcode基本算法分析
在程序中,执行一个shell的程序是这样写的:
shellcode.c ------------------------------------------------------------------------ #include void main() { char *name[2]; name[0] = "/bin/sh" name[1] = NULL; execve(name[0], name, NULL); } ------------------------------------------------------------------------ |
execve函数将执行一个程序。他需要程序的名字地址作为第一个参数。一个内容为该程序的argv[i](argv[n-1]=0)的指针数组作为第二个参数,以及(char*) 0作为第三个参数。
我们来看以看execve的汇编代码:
[nkl10]$Content$nbsp;gcc -o shellcode -static shellcode.c [nkl10]$Content$nbsp;gdb shellcode (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 ;保存ebx 0x80002c0 <__execve+4>: movl $0xb,%eax ;eax=0xb,eax指明第几号系统调用。 0x80002c5 <__execve+9>: movl 0x8(%ebp),%ebx ;ebp+8是第一个参数"/bin/sh\0" 0x80002c8 <__execve+12>: movl 0xc(%ebp),%ecx ;ebp+12是第二个参数name数组的地址 0x80002cb <__execve+15>: movl 0x10(%ebp),%edx ;ebp+16是第三个参数空指针的地址。 ;name[2-1]内容为NULL,用来存放返回值。 0x80002ce <__execve+18>: int $0x80 ;执行0xb号系统调用(execve) 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. |
经过以上的分析,可以得到如下的精简指令算法:
movl $execve的系统调用号,%eax movl "bin/sh\0"的地址,%ebx movl name数组的地址,%ecx movl name[n-1]的地址,%edx int $0x80 ;执行系统调用(execve) |
当execve执行成功后,程序shellcode就会退出,/bin/sh将作为子进程继续执行。可是,如果我们的execve执行失败,(比如没有/bin/sh这个文件),CPU就会继续执行后续的指令,结果不知道跑到哪里去了。所以必须再执行一个exit()系统调用,结束shellcode.c的执行。
我们来看以看exit(0)的汇编代码:
(gdb) disassemble _exit Dump of assembler code for function _exit: 0x800034c <_exit>: pushl %ebp 0x800034d <_exit+1>: movl %esp,%ebp 0x800034f <_exit+3>: pushl %ebx 0x8000350 <_exit+4>: movl $0x1,%eax ;1号系统调用 0x8000355 <_exit+9>: movl 0x8(%ebp),%ebx ;ebx为参数0 0x8000358 <_exit+12>: int $0x80 ;引发系统调用 0x800035a <_exit+14>: movl 0xfffffffc(%ebp),%ebx 0x800035d <_exit+17>: movl %ebp,%esp 0x800035f <_exit+19>: popl %ebp 0x8000360 <_exit+20>: ret 0x8000361 <_exit+21>: nop 0x8000362 <_exit+22>: nop 0x8000363 <_exit+23>: nop End of assembler dump. |
看来exit(0)〕的汇编代码更加简单:
movl $0x1,%eax ;1号系统调用 movl 0,%ebx ;ebx为exit的参数0 int $0x80 ;引发系统调用 |
那么总结一下,合成的汇编代码为:
movl $execve的系统调用号,%eax movl "bin/sh\0"的地址,%ebx movl name数组的地址,%ecx movl name[n-1]的地址,%edx int $0x80 ;执行系统调用(execve) movl $0x1,%eax ;1号系统调用 movl 0,%ebx ;ebx为exit的参数0 int $0x80 ;执行系统调用(exit) |
如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。