由於我們在編寫殼的部分比較簡單,那么我們在編寫加殼的過程中難免要復雜些。我們要完成加殼的操作必然會要讀取被加殼程序的各種信息,並保存到一個結構中,為了便於后面的操作。還有在操作上只能讀取源文件,將加殼后的文件要保存到另外的文件中去。
為此我們在項目Pack_Dll中,我們完成加殼的操作:
1.讀取被加殼程序的PE信息
2.對相應的區段進行處理(加密)
3.將殼(Stub)部分添加到加殼程序中
4.加殼操作
5.1. 讀取被加殼程序的PE信息
在Pack_Dll.h文件中定義一個結構如下:
// 用來保存殼(Stub)中用到的PE信息
typedef struct _GLOBAL_PARAM { BOOL bShowMessage; // 是否顯示解密信息 DWORD dwOEP; // 程序入口點 PBYTE lpStartVA; // 起始虛擬地址(被異或加密區) PBYTE lpEndVA; // 結束虛擬地址(被異或加密區) }GLOBAL_PARAM, *PGLOBAL_PARAM;
5.2. 對相應的區段進行處理(加密)
給代碼區段進行加密,並為其添加可讀屬性。
void Pretreatment(PBYTE lpCodeStart, PBYTE lpCodeEnd, PE_INFO stcPeInfo) { // 1. 加密指定區域 while (lpCodeStart < lpCodeEnd) { *lpCodeStart ^= 0x15; lpCodeStart++; } // 2. 給第一個區段附加上可寫屬性 PDWORD pChara = &(stcPeInfo.pSectionHeader->Characteristics); *pChara = *pChara | IMAGE_SCN_MEM_WRITE; }
5.3. 將殼(Stub)部分添加到加殼程序中
我們要想將Stub部分添加到被加殼程序中去,就需要獲取到Stub的信息。而我們已經在3.2的操作中將Stub工程產生的Stub.dll做為資源成為了項目Pack_Dll的一部分,那么我們就需要讀取生成的Pack_Dll.dll並從中以資源的形式獲取到Stub.dll句柄。然后提取Stub部分的關鍵信息,將Stub作為新的區段添加到被加殼程序中。為此我們還需要進行重定位和修復OEP。
需要添加頭文件
#include <stdlib.h> #include "resource.h" //導入資源 #include "ProcessingPE.h" //PE操作 #include <winuser.h> //資源轉換 在Pack_Dll.cpp文件中的Implantation方法中完成即可。 DWORD Implantation(LPVOID &lpFileData, DWORD dwSize, CProcessingPE* pobjPE, PE_INFO stcPeInfo, GLOBAL_PARAM stcParam) { // 1. 在資源中讀取文件內容 HRSRC hREC = NULL; // 資源對象 HGLOBAL hREC_Handle = NULL; // 資源句柄 DWORD dwStubSize = NULL; // 文件大小 LPVOID lpResData = NULL; // 資源數據指針 HMODULE hModule = GetModuleHandle(L"Pack_Dll.dll"); if (!(hREC = FindResource(hModule, MAKEINTRESOURCE(IDR_STUB1), L"STUB"))) return false; if (!(hREC_Handle = LoadResource(hModule, hREC))) return false; if (!(lpResData = LockResource(hREC_Handle))) return false; if (!(dwStubSize = SizeofResource(hModule, hREC))) return false; // 2. 提取Stub部分的關鍵信息 CProcessingPE objProcPE; PE_INFO stcStubPeInfo; PBYTE lpData = new BYTE[dwStubSize]; // 2.1 將Stub復制到臨時緩沖區,防止重復操作 CopyMemory(lpData, lpResData, dwStubSize); // 2.2 獲取Stub的PE信息 objProcPE.GetPeInfo(lpData, dwStubSize, &stcStubPeInfo); // 2.3 算出代碼段的相關信息(默認第一個區段為代碼段) PBYTE lpText = (PBYTE)(stcStubPeInfo.pSectionHeader->PointerToRawData + (DWORD)lpData); DWORD dwTextSize = stcStubPeInfo.pSectionHeader->SizeOfRawData; // 3. 添加區段 DWORD dwNewSectionSize = 0; IMAGE_SECTION_HEADER stcNewSection = { 0 }; PVOID lpNewSectionData = pobjPE->AddSection(L".LiPass", dwTextSize, IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_EXECUTE, &stcNewSection, &dwNewSectionSize); // 4. 對Stub部分進行的重定位操作 // 新的加載地址 = (新區段的起始RVA - Stub的".Text"區段的起始RVA) + 映像基址 DWORD dwLoadImageAddr = (stcNewSection.VirtualAddress - stcStubPeInfo.pSectionHeader->VirtualAddress) + stcPeInfo.dwImageBase; objProcPE.FixReloc(dwLoadImageAddr); // 5. 寫入配置參數 // 5.1 獲取Stub的導出變量地址 PVOID lpPatam = objProcPE.GetExpVarAddr(L"g_stcParam"); // 5.2 保存配置信息到Stub中 CopyMemory(lpPatam, &stcParam, sizeof(GLOBAL_PARAM)); // 6. 將Stub復制到新區段中 CopyMemory(lpNewSectionData, lpText, dwTextSize); // 7. 計算並設置新OEP DWORD dwNewOEP = 0; // 7.1 計算新OEP DWORD dwStubOEP = stcStubPeInfo.dwOEP; DWORD dwStubTextRVA = stcStubPeInfo.pSectionHeader->VirtualAddress; DWORD dwNewSectionRVA = stcNewSection.VirtualAddress; dwNewOEP = (dwStubOEP - dwStubTextRVA) + dwNewSectionRVA; // 7.2 設置新OEP pobjPE->SetOEP(dwNewOEP); pobjPE->SetDLL(); // 8. 釋放資源,函數返回 delete[] lpData; FreeResource(hREC_Handle); return dwNewSectionSize; }
5.4. 加殼操作
先讀取PE信息,並進行加密處理。然后將殼部分追加到程序中,並保存為新的文件。
在Pack_Dll.cpp文件中的Pack方法中完成即可。
BOOL Pack(CString strPath) { CProcessingPE objProcPE; // PE處理對象 PE_INFO stcPeInfo; // PE信息 HANDLE hFile_In; HANDLE hFile_Out; DWORD dwFileSize; LPVOID lpFileImage; WCHAR szOutPath[MAX_PATH] = { 0 }; // 1. 生成輸出文件路徑 LPWSTR strSuffix = PathFindExtension(strPath); // 獲取文件的后綴名 wcsncpy_s(szOutPath, MAX_PATH, strPath, wcslen(strPath)); // 備份目標文件路徑到szOutPath PathRemoveExtension(szOutPath); // 將szOutPath中保存路徑的后綴名去掉 wcscat_s(szOutPath, MAX_PATH, L"_Pack"); // 在路徑最后附加“_Pack” wcscat_s(szOutPath, MAX_PATH, strSuffix); // 在路徑最后附加剛剛保存的后綴名 // 2. 獲取文件信息,並映射進內存中 if (INVALID_HANDLE_VALUE == (hFile_In = CreateFile(strPath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL))) { return false; } if (INVALID_FILE_SIZE == (dwFileSize = GetFileSize(hFile_In, NULL))) { CloseHandle(hFile_In); return false; } if (!(lpFileImage = VirtualAlloc(NULL, dwFileSize * 2, MEM_COMMIT, PAGE_READWRITE))) { CloseHandle(hFile_In); return false; } DWORD dwRet; if (!ReadFile(hFile_In, lpFileImage, dwFileSize, &dwRet, NULL)) { CloseHandle(hFile_In); VirtualFree(lpFileImage, 0, MEM_RELEASE); return false; } // 3. 獲取PE文件信息 objProcPE.GetPeInfo(lpFileImage, dwFileSize, &stcPeInfo); // 4. 獲取目標文件代碼段的起始結束信息 // 讀取第一個區段的相關信息,並將其加密(默認第一個區段為代碼段) PBYTE lpStart = (PBYTE)(stcPeInfo.pSectionHeader->PointerToRawData + (DWORD)lpFileImage); PBYTE lpEnd = (PBYTE)((DWORD)lpStart + stcPeInfo.pSectionHeader->SizeOfRawData); PBYTE lpStartVA = (PBYTE)(stcPeInfo.pSectionHeader->VirtualAddress + stcPeInfo.dwImageBase); PBYTE lpEndVA = (PBYTE)((DWORD)lpStartVA + stcPeInfo.pSectionHeader->SizeOfRawData); // 5. 對文件進行預處理 Pretreatment(lpStart, lpEnd, stcPeInfo); // 6. 植入Stub DWORD dwStubSize = 0; GLOBAL_PARAM stcParam = { 0 }; stcParam.dwOEP = stcPeInfo.dwOEP + stcPeInfo.dwImageBase; stcParam.lpStartVA = lpStartVA; stcParam.lpEndVA = lpEndVA; dwStubSize = Implantation(lpFileImage, dwFileSize, &objProcPE, stcPeInfo, stcParam); // 7. 將處理完成后的結果寫入到新文件中 if (INVALID_HANDLE_VALUE != (hFile_Out = CreateFile(szOutPath, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ, NULL, OPEN_ALWAYS, 0, NULL))) { DWORD dwRet = 0; WriteFile(hFile_Out, lpFileImage, dwStubSize + dwFileSize, &dwRet, NULL); } // 8. 釋放相關資源並返回 CloseHandle(hFile_In); CloseHandle(hFile_Out); VirtualFree(lpFileImage, 0, MEM_RELEASE); return true; }
六 編寫界面
在Pack BaseDlg.cpp文件中進行完善即可。
#include "../Pack_Dll/Pack_Dll.h" #ifdef _DEBUG #pragma comment(lib, "../Debug/Pack_Dll.lib") #else #pragma comment(lib, "../Release/Pack_ Dll.lib") #endif void CPackBaseDlg::OnBnClickedButton2() { UpdateData(true); //MessageBox(m_pathStr, m_pathStr, 0); if (!Pack(m_pathStr)) { MessageBox(L"加密失敗-_-!"); } else { MessageBox(L"加密成功!"); } }
七 運行結果如下
在使用靜態編譯的時候,要是以Release版本進行輸出的時候,一定要將Stub項目的輸出目錄進行更改回去。
由於之前一直使用Debug方式進行調試,使用Release版后,需要將Pack_Dll項目中Pack_Dll.rc的資源路徑進行修改,將Debug修改成Release即可
————————————————
版權聲明:本文為CSDN博主「布衣僧」的原創文章,遵循CC 4.0 by-sa版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/oBuYiSeng/article/details/50528622