本文經原作者授權,節選自《Windows黑客編程技術詳解》一書。文末有福利哦!!

-----------------------------------------------------------------

病毒木馬之所以會廣泛使用資源釋放技術,是因爲它可以使程序變得更簡潔。如果程序額外需要加載一些DLL文件、文本文件、圖片文件,或者其他的音/視頻文件等,則可以把它們作爲資源插入到程序裏,等到程序運行後,再把它們釋放到本地上。這樣做的好處是編譯出來的程序只有一個exe文件,而不需要附帶其他文件,因而程序變得很簡潔。只需把exe植入到用戶計算機上,而不需要連同其他文件一起植入,這降低了被發現的風險。

2.3.1 資源插入的步驟

在介紹資源釋放技術之前,先介紹如何向程序中插入資源。資源插入不需要編碼操作,只需手動設置VS開發環境即可完成。

本節以“520”這個沒有文件類型的文件作爲演示實例,向大家介紹文件作爲資源插入到程序中的步驟,其他類型的插入也是類似的。其中,“520”的文件內容如圖2-5所示。

打開項目工程之後,在解決方案中,選擇“添加”,選中“資源”。本節演示的是插入自定義資源,所以單擊“自定義(C)...”按鈕。資源添加對話框,如圖2-6所示。

然後,在“新建自定義資源”對話框中,輸入“資源類型”,如“MYRES”,然後單擊確定”。新建自定義資源對話框,如圖2-7所示。

在設置好自定義資源的類型之後,接着回到“添加資源”對話框。選中剛新建的“MYRES”資源類型,然後單擊右側的“導入(M)...”按鈕來選擇導入文件。

經過上述步驟後便完成了插入資源的操作。

2.3.2 函數介紹 1.FindResource函數

確定模塊中指定類型和名稱的資源所在位置。

函數聲明

HRSRC FindResource(

HMODULE hModule,

LPCWSTR lpName,

LPCWSTR lpType)

參數

hModule[in]

處理包含資源的可執行文件模塊。若hModuleNULL,則系統從當前進程的模塊中裝載資源。

lpName[in]

指定資源名稱。

lpType[in]

指定資源類型。

返回值

如果函數運行成功,那麼返回值爲指定資源信息塊的句柄。可將這個句柄傳遞給LoadResource函數來獲得這些資源。如果函數運行失敗,則返回值爲NULL

2.SizeofResource函數

獲取指定資源的字節數。

函數聲明

DWORD SizeofResource(

HMODULE hModule,

HRSRC hResInfo)

參數

hModule[in]

包含資源的可執行文件模塊的句柄。若hModuleNULL,則系統從當前進程的模塊中裝載資源。

hResInfo[in]

資源句柄。此句柄必須由函數FindResourceFindResourceEx來創建。

返回值

如果函數運行成功,則返回值爲資源的字節數;如果函數運行失敗,則返回值爲零。

3.LoadResource函數

裝載指定資源到全局存儲器。

函數聲明

HGLOBAL LoadResource(

HMODULE hModule,

HRSRC hResInfo)

參數

hModule[in]

處理資源可執行文件的模塊句柄。若hModuleNULL,則系統從當前進程的模塊中裝載資源。

hResInfo[in]

資源句柄。此句柄必須由函數FindResourceFindResourceEx來創建。

返回值

如果函數運行成功,則返回值爲相關資源數據的句柄。如果函數運行失敗,則返回值爲NULL

4.LockResource函數

鎖定資源並得到資源在內存中第一個字節的指針。

函數聲明

LPVOID LockResource(

HGLOBAL hResData)

參數

hResData[in]

裝載資源的句柄。函數LoadResource可以返回這個句柄。

返回值

如果裝載資源被鎖住了,則返回值是資源第一個字節的指針;反之則爲NULL

2.3.3 實現原理

爲方便開發人員獲取程序裏的資源,Windows提供了一系列帶有操作資源的WIN32 API函數。所以,程序實現也是基於這些WIN32 API函數進行操作的。

首先,通過FindResource定位程序裏的資源,主要是根據“資源類型”和“資源名稱”進行定位,從而獲取資源信息塊的句柄。

其次,根據上面獲取的資源信息塊的句柄,利用SizeofResource獲取資源的大小之後,再通過LoadResource把資源加載到程序內存中。

接着,通過LockResource鎖定加載到內存中的資源,防止程序中的其他操作影響這塊內存。其中,返回值就是資源在進程內存中的起始地址。

最後,根據資源大小以及進程內存的起始地址,可將資源數據讀取出來並保存爲本地文件

經過上述4個步驟,便可以定位出資源,並將其釋放到本地磁盤。它的原理就是通過PE文件結構,確定資源在PE文件中的偏移和大小。

在資源釋放過程中,要特別注意一點就是,必須明確資源所在的模塊,要指明所在模塊句柄並且統一。因爲文件可以以資源的形式插入到DLL文件中,所以當DLL加載到其他進程時,資源所在模塊仍是該DLL模塊。要想成功釋放資源,則需要先通過GetModuleHandle函數獲取該DLL模塊的句柄。否則,資源釋放會因爲指定了錯誤模塊而失敗。

2.3.4 編程實現

BOOL FreeMyResource(UINT uiResouceName, char *lpszResourceType, char *lpszSaveFileName)

{

// 獲取指定模塊裏的資源

HRSRC hRsrc = ::FindResource(NULL, MAKEINTRESOURCE(uiResouceName), lpszResourceType);

if (NULL == hRsrc)

{

ShowError("FindResource");

return FALSE;

}

// 獲取資源的大小

DWORD dwSize = ::SizeofResource(NULL, hRsrc);

if (0 >= dwSize)

{

ShowError("SizeofResource");

return FALSE;

}

// 將資源加載到內存裏

HGLOBAL hGlobal = ::LoadResource(NULL, hRsrc);

if (NULL == hGlobal)

{

ShowError("LoadResource");

return FALSE;

}

// 鎖定資源

LPVOID lpVoid = ::LockResource(hGlobal);

if (NULL == lpVoid)

{

ShowError("LockResource");

return FALSE;

}

// 保存資源爲文件

FILE *fp = NULL;

fopen_s(&fp, lpszSaveFileName, "wb+");

if (NULL == fp)

{

ShowError("LockResource");

return FALSE;

}

fwrite(lpVoid, sizeof(char), dwSize, fp);

fclose(fp);

return TRUE;

}

2.3.5 測試

本節創建一個MFC工程項目,按照上述步驟插入資源,並按照上述的實現原理來編碼實現,調用封裝好的資源釋放函數進行資源釋放的測試。資源釋放的時候,將其保存爲txt格式文件。

單擊對話框中“釋放”按鈕後,提示資源釋放成功,如圖2-8所示。然後查看目錄,本地成功地生成“520.txt”文件,打開文件查看內容,它與之前插入的“520”文件中的內容相同,如圖2-9所示。資源釋放成功。

2.3.6 小結

資源釋放技術的實現原理並不是很複雜,只需理清WIN32 API函數的調用關係以及函數作用即可。要特別注意一點,明確資源所在的模塊,如果資源包含在DLL文件中,則可以在DllMain中或是通過GetModuleHandle函數獲取DLL模塊的句柄。

安全小貼士

可以根據PE結構中的資源表IMAGE_RESOURCE_DIRECTORY來解析PE文件中包含的所有資源,並且獲取資源的偏移地址及數據大小。例如,常用的資源編輯工具eXeScope就是根據資源表來枚舉PE文件中的資源的。

-------------------------------------------

福利時間到了

說明:

在),第一章送出三本書。同時第二章(,,2.3節),我們每一節仍然會送出一本書,也就是參與本節的活動,會增加你的中獎概率。在前四章更新完畢之後,會統一公佈中獎名單,並組織線上答疑活動,和本書作者親密交流。

本篇文章 會送出一本書,參與辦法如下(微信訂閱號打開請忽略1,2,3步驟):

  1. 找到本篇文章並打開
  2. 點擊文章下的“在看”按鈕。
  3. 文章下留言,談體會
  4. 拉你的朋友過來爲你的留言點贊 ------------------------------------------------------ 明天我們繼續推送2.3節《資源釋放技術》

覺得很贊請掃碼讚賞

(內含送書福利)

滲透測試入門指南與路線規劃(全文版)

相關文章