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

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

为此我们在项目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即可,如下:

//IDR_STUB1  STUB   "D:\\Users\\壳编写3\\PackBase\\Debug\\Stub.dll"
IDR_STUB1   STUB  "D:\\Users\\壳编写3\\Pack Base\\Release\\Stub.dll"

运行结果如下:




源码:http://download.csdn.net/detail/obuyiseng/9406707

阅读更多
个人分类: 壳相关
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭