壳的编写(4)-- 进行加壳操作

由于我们在编写壳的部分比较简单,那么我们在编写加壳的过程中难免要复杂些。我们要完成加壳的操作必然会要读取被加壳程序的各种信息,并保存到一个结构中,为了便于后面的操作。还有在操作上只能读取源文件,将加壳后的文件要保存到另外的文件中去。

为此我们在项目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

原文地址:https://www.cnblogs.com/luckywolfzyy/p/11384968.html