這是對shellcode學習的一個初步實踐,采用經典的winexec shellcode函數來做實踐,采用的工具是VC6.0作為擷取工具。其過程如下:
1.書寫正常的執行代碼:
<span style="font-family: Arial, Helvetica, sans-serif;">#include "stdafx.h"</span>
#include <windows.h>
int main(int argc, char* argv[])
{
char buff[9];
buff[0]='c';
buff[1]='a';
buff[2]='l';
buff[3]='c';
buff[4]='.';
buff[5]='e';
buff[6]='x';
buff[7]='e';
buff[8]='\0';
WinExec(buff,SW_HIDE);return 0;
}
2.對程式進行編譯後,F10來debug一下,然後按Alt+8檢視彙編代碼,該程式的彙編代碼如下:
55 push ebp
8B EC mov ebp,esp
83 EC 4C sub esp,4Ch
53 push ebx
56 push esi
57 push edi
8D 7D B4 lea edi,[ebp-4Ch]
B9 13 00 00 00 mov ecx,13h
B8 CC CC CC CC mov eax,0CCCCCCCCh
F3 AB rep stos dword ptr [edi]
19: char buff[9];
20: buff[0]='c';
C6 45 F4 63 mov byte ptr [ebp-0Ch],63h
21: buff[1]='a';
C6 45 F5 61 mov byte ptr [ebp-0Bh],61h
22: buff[2]='l';
C6 45 F6 6C mov byte ptr [ebp-0Ah],6Ch
23: buff[3]='c';
C6 45 F7 63 mov byte ptr [ebp-9],63h
24: buff[4]='.';
C6 45 F8 2E mov byte ptr [ebp-8],2Eh
25: buff[5]='e';
C6 45 F9 65 mov byte ptr [ebp-7],65h
26: buff[6]='x';
C6 45 FA 78 mov byte ptr [ebp-6],78h
27: buff[7]='e';
C6 45 FB 65 mov byte ptr [ebp-5],65h
28: buff[8]='\0';
C6 45 FC 00 mov byte ptr [ebp-4],0
29: WinExec(buff,SW_HIDE);
8B F4 mov esi,esp
6A 00 push 0
8D 45 F4 lea eax,[ebp-0Ch]
50 push eax
FF 15 14 A2 42 00 call dword ptr [KERNEL32_NULL_THUNK_DATA (0042a214)]
3B F4 cmp esi,esp
E8 2F 00 00 00 call __chkesp (00401090)
其中
0042a214
是 WinExec的執行位址的存放位址,到0x0042a214下去檢視函數位址:

可以看出,該函數位址為0x7605f22e,然後對彙編代碼進行整理後獲得的彙程式設計式如下:
</pre><pre code_snippet_id="394634" snippet_file_name="blog_20140616_7_9412625" name="code" class="cpp">#include "stdafx.h"
#include <windows.h>
int main(int argc, char* argv[]){
__asm{
//儲存現場
push ebp
mov ebp,esp
push ebx
push esi
push edi
//設定第一個參數
mov byte ptr [ebp-0Ch],63h
mov byte ptr [ebp-0Bh],61h
mov byte ptr [ebp-0Ah],6Ch
mov byte ptr [ebp-9],63h
mov byte ptr [ebp-8],2Eh
mov byte ptr [ebp-7],65h
mov byte ptr [ebp-6],78h
mov byte ptr [ebp-5],65h
mov byte ptr [ebp-4],0
//設定第二個參數
push 3
//壓棧
lea eax,[ebp-0Ch]
push eax
//call winexec
mov eax,0x7605F22E
call eax
//恢複現場
mov esp,ebp
pop ebp
}
}
3.儲存後對其進行編譯并debug,同樣按Alt+8來檢視:
__asm{
<span style="color:#ff0000;">55 </span>push ebp
<span style="color:#ff0000;">8B EC</span> mov ebp,esp
<span style="color:#ff0000;">53 </span> push ebx
<span style="color:#ff0000;">56 </span> push esi
<span style="color:#ff0000;">57</span> push edi
<span style="color:#ff0000;">C6 45 F4 63</span> mov byte ptr [ebp-0Ch],63h
<span style="color:#ff0000;">C6 45 F5 61</span> mov byte ptr [ebp-0Bh],61h
<span style="color:#ff0000;">C6 45 F6 6C</span> mov byte ptr [ebp-0Ah],6Ch
<span style="color:#ff0000;">C6 45 F7 63</span> mov byte ptr [ebp-9],63h
<span style="color:#ff0000;">C6 45 F8 2E </span> mov byte ptr [ebp-8],2Eh
<span style="color:#ff0000;">C6 45 F9 65</span> mov byte ptr [ebp-7],65h
<span style="color:#ff0000;">C6 45 FA 78 </span> mov byte ptr [ebp-6],78h
<span style="color:#ff0000;">C6 45 FB 65</span> mov byte ptr [ebp-5],65h
<span style="color:#ff0000;">C6 45 FC 00</span> mov byte ptr [ebp-4],0
<span style="color:#ff0000;">6A 03</span> push 3
<span style="color:#ff0000;">8D 45 F4 </span> lea eax,[ebp-0Ch]
<span style="color:#ff0000;">50 </span> push eax
<span style="color:#ff0000;">B8 2E F2 05 76</span> mov eax,7605F22Eh
<span style="color:#ff0000;">FF D0</span> call eax
<span style="color:#ff0000;">8B E5 </span> mov esp,ebp
<span style="color:#ff0000;">5D</span> pop ebp
}
頭部紅色的部分就是要擷取的shellcode,在記憶體中的情況如下:
提取後的shellcode為:
char buff[] =
"\x55\x8B\xEC\x53\x56\x57\xC6"
"\x45\xF4\x63\xC6\x45\xF5\x61"
"\xC6\x45\xF6\x6C\xC6\x45\xF7"
"\x63\xC6\x45\xF8\x2E\xC6\x45"
"\xF9\x65\xC6\x45\xFA\x78\xC6"
"\x45\xFB\x65\xC6\x45\xFC\x00"
"\x6A\x03\x8D\x45\xF4\x50\xB8"
"\x2E\xF2\x05\x76\xFF\xD0\x8B"
"\xE5\x5D";
int main(){
__asm{
lea eax,buff;
call eax;
}
return 0;
}
最後成功彈出了calc.exe
當然,查詢函數入口位址時,也可以用depends對編譯好的程式進行檢視,檢視方式是:
dll的基位址(base)+函數偏移(entry point)位址
如Winexec的入口位址為,kernal.dll的位址+winexec的偏移位址就是函數的入口位址。