一个简单的加壳解壳程序

1、资源说明

环境:win10 vs2017

Shell.exe 壳子程序

src.exe  要加壳的源程序

2、加壳过程

获取Shell程序的路径

获取src程序的路径

将src程序读取到内存中,加密

在Shell程序中新增一个节,并将加密后的src程序追加到Shell程序的新增节中

保存加壳后的程序

3、加壳代码

#include <stdio.h>
#include <windows.h>

#define SRC_PATH "D:\\crackme.exe"
#define SHELL_PATH "D:\\myke.exe"
//**************************************************************************						
//ReadPEFile:将文件读取到缓冲区						
//参数说明:						
//lpszFile 文件路径						
//pFileBuffer 缓冲区指针						
//返回值说明:						
//读取失败返回0  否则返回实际读取的大小						
//**************************************************************************						
DWORD ReadPEFile(IN LPSTR lpszFile, OUT LPVOID* pFileBuffer)
{
	FILE* pFile = NULL;
	DWORD fileSize = 0;

	errno_t err;
	err = fopen_s(&pFile,lpszFile, "rb");
	//打开文件
	if (pFile == NULL)
	{
		return 0;
	}

	//读取文件大小
	fseek(pFile, 0, SEEK_END);
	fileSize = ftell(pFile);
	fseek(pFile, 0, SEEK_SET);

	//分配缓冲区
	*pFileBuffer = (LPVOID)malloc(fileSize);
	if (!*pFileBuffer)
	{
		fclose(pFile);
		return 0;
	}
	//将文件数据读取到缓冲区
	size_t n = fread(*pFileBuffer, fileSize, 1, pFile);
	if (!n)
	{
		free(*pFileBuffer);
		fclose(pFile);
		return 0;
	}
	//关闭文件
	fclose(pFile);
	return fileSize;

}
VOID JiaMi(LPVOID* pFileBuffer)
{

}
typedef struct _PEHEADER 
{
	//DOS头
	PIMAGE_DOS_HEADER pDosHeader;
	//NT头
	PIMAGE_NT_HEADERS pNTHeader;
	//标准PE头
	PIMAGE_FILE_HEADER pPEHeader;
	//可选PE头
	PIMAGE_OPTIONAL_HEADER32 pOptionHeader;
	//节表
	PIMAGE_SECTION_HEADER pSectionHeader;
} PEHEADER,* PPEHEADER;
VOID GetPEHeader(IN LPVOID pFileBuffer,OUT PPEHEADER peHeader)
{

	if (!pFileBuffer)
	{
		printf("缓冲取指针无效\n");
		return;
	}

	//判断是否是有效的MZ标志	
	if (*((PWORD)pFileBuffer) != IMAGE_DOS_SIGNATURE)
	{
		printf("不是有效的MZ标志\n");
		return;
	}

	peHeader->pDosHeader = (PIMAGE_DOS_HEADER)(pFileBuffer);

	//判断是否是有效的PE标志	
	if (*((PDWORD)((DWORD)pFileBuffer + peHeader->pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE)
	{
		printf("不是有效的PE标志\n");
		return;
	}
	peHeader->pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)(pFileBuffer)+peHeader->pDosHeader->e_lfanew);
	peHeader->pPEHeader = (PIMAGE_FILE_HEADER)(((DWORD)peHeader->pNTHeader) + 4);
	peHeader->pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)peHeader->pPEHeader + IMAGE_SIZEOF_FILE_HEADER);
	peHeader->pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)peHeader->pOptionHeader + peHeader->pPEHeader->SizeOfOptionalHeader);

}
DWORD GetSizeOfAlignment(IN DWORD size, DWORD alignmet)
{
	DWORD ret = size / alignmet;
	return alignmet * (ret + 1);
}
size_t DoShell(IN LPVOID srcBuffer,size_t srcSize, LPVOID shellBuffer,size_t shellSize, LPVOID* newShellBuffer)
{

	PEHEADER shellPEheader;
	GetPEHeader(shellBuffer, &shellPEheader);
	//获取shell最后一个节表的指针
	PIMAGE_SECTION_HEADER pShellLastSectionHeader = shellPEheader.pSectionHeader + (shellPEheader.pPEHeader->NumberOfSections - 1);
	
	//判断SHELL空间是否够插入一个节表
	if (shellPEheader.pOptionHeader->SizeOfHeaders - (DWORD)pShellLastSectionHeader < (0x28 * 3))
	{
		return;
	}
	size_t totalSize = GetSizeOfAlignment(srcSize,shellPEheader.pOptionHeader->FileAlignment)  + GetSizeOfAlignment(shellSize, shellPEheader.pOptionHeader->FileAlignment);
	*newShellBuffer = malloc(totalSize);
	memset(*newShellBuffer, 0, totalSize);
	memcpy(*newShellBuffer, shellBuffer, shellSize);
	PEHEADER newPEHeader;
	GetPEHeader(*newShellBuffer, &newPEHeader);
	//获取shell最后一个节表的指针
	PIMAGE_SECTION_HEADER pNewShellLastSectionHeader = newPEHeader.pSectionHeader + (newPEHeader.pPEHeader->NumberOfSections - 1);
	// 添加一个新的节(copy一份)
	//新增节表位置指针
	PIMAGE_SECTION_HEADER pNewShellNewSectionHeader = newPEHeader.pSectionHeader + (newPEHeader.pPEHeader->NumberOfSections);
	memcpy(pNewShellNewSectionHeader, pNewShellLastSectionHeader, 0x28);

	//修改新增节表内容
	pNewShellNewSectionHeader->Misc.VirtualSize = srcSize;
	pNewShellNewSectionHeader->SizeOfRawData = GetSizeOfAlignment(srcSize, newPEHeader.pOptionHeader->FileAlignment);
	//pNewShellNewSectionHeader->PointerToRawData += GetSizeOfAlignment(pShellLastSectionHeader->Misc.VirtualSize, newPEHeader.pOptionHeader->FileAlignment);
	pNewShellNewSectionHeader->PointerToRawData = (DWORD)(shellSize);
	pNewShellNewSectionHeader->VirtualAddress = GetSizeOfAlignment(pNewShellLastSectionHeader->VirtualAddress + pNewShellLastSectionHeader->SizeOfRawData, newPEHeader.pOptionHeader->SectionAlignment);

	//修改PE头中节的数量
	newPEHeader.pPEHeader->NumberOfSections += 1;
	//修改sizeOfImage的大小
	newPEHeader.pOptionHeader->SizeOfImage += GetSizeOfAlignment(srcSize, newPEHeader.pOptionHeader->SectionAlignment);
	//原有数据的最后,新增一个节的数据(内存对齐的整数倍).
	//DWORD x = (DWORD)*newShellBuffer + 0x2ff0;
	memcpy((LPVOID)((DWORD)*newShellBuffer + pNewShellNewSectionHeader->PointerToRawData), srcBuffer, srcSize);
	//6)修正新增节表的属性

	return totalSize;
}
BOOL MemeryTOFile(IN LPVOID pMemBuffer, IN size_t size, OUT LPSTR lpszFile)
{
	FILE* pFile = NULL;

	//打开文件
	fopen_s(&pFile,lpszFile, "wb+");
	if (!pFile)
	{
		printf("无法创建exe\n");
		return FALSE;
	}
	fwrite(pMemBuffer, size, 1, pFile);
	fclose(pFile);
	pFile = NULL;
	return TRUE;
}
int main()
{
	//读取shell程序
	LPVOID shellBuffer = NULL;
	size_t shellSize = ReadPEFile(SHELL_PATH, &shellBuffer);
	if (shellBuffer==NULL)
	{
		return 1;
	}
	//读取src程序
	LPVOID srcBuffer = NULL;
	size_t srcSize = ReadPEFile(SRC_PATH, &srcBuffer);
	if (srcBuffer==NULL)
	{
		free(shellBuffer);
		shellBuffer = NULL;
		return 1;
	}
	LPVOID newShellBuffer = NULL;
	size_t size = DoShell(srcBuffer, srcSize, shellBuffer,shellSize,&newShellBuffer);
	if (newShellBuffer==NULL)
	{
		free(shellBuffer);
		shellBuffer = NULL;
		free(srcBuffer);
		srcBuffer = NULL;
		return 1;
	}
	MemeryTOFile(newShellBuffer, size, "D:\\jialeke.exe");
	free(srcBuffer);
	free(shellBuffer);
	free(newShellBuffer);
	system("pause");
	return 0;
}

4、解壳过程

网上找的过程:

获取src的数据,解密

将解密后的PE文件在内存中拉伸,并存储到缓冲区中

以挂起形成创建Shell进程,并得到主线程的Context

 卸载外壳程序的文件镜像(ZwUnmapViewOfSection)

在指定的位置(src的ImageBase)申请指定大小(src的SizeOfImage)的内存(VirtualAllocEx)

如果创建失败,查看src是否包含重定位表,如果包含重定位表,就在任意位置申请(src的SizeOfImage)

如果在指定位置申请内存失败,并且没有重定位表的数据,直接返回失败

 如果内存申请成功,将新的数据复制到内存中

修正运行环境的基址和入口地址

恢复主线程执行

由于Win7及以后的系统程序执行的时候会随机分配ImageBase,用上述过程没法正常执行,修改如下

将解密后的PE文件在内存中拉伸,并存储到缓冲区中

以挂起形成创建Shell进程,并得到主线程的Context

 卸载外壳程序的文件镜像(ZwUnmapViewOfSection)

查看src是否包含重定位表,如果不包含重定位表直接返回失败

在指定的位置(Context的ImageBase)申请指定大小(src的SizeOfImage)的内存(VirtualAllocEx)

如果创建失败,直接返回失败

 如果内存申请成功,将新的数据复制到内存中

修正运行环境的基址和入口地址

恢复主线程执行

5、解壳代码,没有整理代码,只是个测试程序,凑合着看吧

#include <stdio.h>
#include <windows.h>
#include <process.h>
#include <Tlhelp32.h>
PVOID GetProcessImageBase(DWORD dwProcessId,LPVOID* path)
{
	PVOID pProcessImageBase = NULL;
	MODULEENTRY32 me32 = { 0 };
	me32.dwSize = sizeof(MODULEENTRY32);
	// 获取指定进程全部模块的快照
	HANDLE hModuleSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwProcessId);
	if (INVALID_HANDLE_VALUE == hModuleSnap)
	{
		return pProcessImageBase;
	}
	// 获取快照中第一条信息
	BOOL bRet = Module32First(hModuleSnap, &me32);
	if (bRet)
	{
		// 获取加载基址
		pProcessImageBase = (PVOID)me32.modBaseAddr;
		*path = malloc(strlen(me32.szExePath)+1);
		memset(*path, 0, strlen(me32.szExePath)+1);
		memcpy(*path, me32.szExePath, strlen(me32.szExePath));
		
	}
	// 关闭句柄
	CloseHandle(hModuleSnap);
	return pProcessImageBase;
}
//读取最后一个节数据
DWORD ReadLastSection(DWORD dwImageBase,LPVOID* dataBuffer)
{
	PIMAGE_DOS_HEADER pDosHeader = NULL;
	//NT头
	PIMAGE_NT_HEADERS pNTHeader = NULL;
	//标准PE头
	PIMAGE_FILE_HEADER pPEHeader = NULL;
	//可选PE头
	PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;
	//节表
	PIMAGE_SECTION_HEADER pSectionHeader = NULL;
	//判断是否是有效的MZ标志	
	if (*((PWORD)dwImageBase) != IMAGE_DOS_SIGNATURE)
	{
		printf("不是有效的MZ标志\n");
		return 0;
	}
	pDosHeader = (PIMAGE_DOS_HEADER)(dwImageBase);

	//判断是否是有效的PE标志	
	if (*((PDWORD)((DWORD)dwImageBase + pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE)
	{
		printf("不是有效的PE标志\n");
		return 0;
	}
	pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)(dwImageBase)+pDosHeader->e_lfanew);
	pPEHeader = (PIMAGE_FILE_HEADER)(((DWORD)pNTHeader) + 4);
	pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER);
	pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);
	WORD numberOfSections = pPEHeader->NumberOfSections;
	//最后一个节表的指针
	pSectionHeader += (numberOfSections - 1);
	//分配内存拷贝数据
	*dataBuffer = malloc(pSectionHeader->Misc.VirtualSize);
	memset(*dataBuffer, 0, pSectionHeader->Misc.VirtualSize);
	DWORD dstAddr = pSectionHeader->VirtualAddress;
	dstAddr += dwImageBase;
	memcpy(*dataBuffer, (void*)dstAddr, pSectionHeader->Misc.VirtualSize);
	return pSectionHeader->Misc.VirtualSize;
}

//解密
VOID JieMi(LPVOID* dataBuffer)
{

}

// 卸载原外壳占用内存 
BOOL UnloadShell(HANDLE ProcHnd, unsigned long BaseAddr)

{

		typedef unsigned long(__stdcall *pfZwUnmapViewOfSection)(unsigned long, unsigned long);

		pfZwUnmapViewOfSection ZwUnmapViewOfSection = NULL;

		BOOL res = FALSE;

		HMODULE m = LoadLibrary("ntdll.dll");

		if (m) {

				ZwUnmapViewOfSection = (pfZwUnmapViewOfSection)GetProcAddress(m, "ZwUnmapViewOfSection");


				if (ZwUnmapViewOfSection)

					res = (ZwUnmapViewOfSection((unsigned long)ProcHnd, BaseAddr) == 0);

				FreeLibrary(m);

		}

		return res;

}

typedef struct _PEHEADER
{
	//DOS头
	PIMAGE_DOS_HEADER pDosHeader;
	//NT头
	PIMAGE_NT_HEADERS pNTHeader;
	//标准PE头
	PIMAGE_FILE_HEADER pPEHeader;
	//可选PE头
	PIMAGE_OPTIONAL_HEADER32 pOptionHeader;
	//节表
	PIMAGE_SECTION_HEADER pSectionHeader;
} PEHEADER, *PPEHEADER;
VOID GetPEHeader(IN LPVOID pFileBuffer, OUT PPEHEADER peHeader)
{

	if (!pFileBuffer)
	{
		printf("缓冲取指针无效\n");
		return;
	}

	//判断是否是有效的MZ标志	
	if (*((PWORD)pFileBuffer) != IMAGE_DOS_SIGNATURE)
	{
		printf("不是有效的MZ标志\n");
		return;
	}

	peHeader->pDosHeader = (PIMAGE_DOS_HEADER)(pFileBuffer);

	//判断是否是有效的PE标志	
	if (*((PDWORD)((DWORD)pFileBuffer + peHeader->pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE)
	{
		printf("不是有效的PE标志\n");
		return;
	}
	peHeader->pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)(pFileBuffer)+peHeader->pDosHeader->e_lfanew);
	peHeader->pPEHeader = (PIMAGE_FILE_HEADER)(((DWORD)peHeader->pNTHeader) + 4);
	peHeader->pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)peHeader->pPEHeader + IMAGE_SIZEOF_FILE_HEADER);
	peHeader->pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)peHeader->pOptionHeader + peHeader->pPEHeader->SizeOfOptionalHeader);

}
//**************************************************************************						
//CopyFileBufferToImageBuffer:将文件从FileBuffer复制到ImageBuffer						
//参数说明:						
//pFileBuffer  FileBuffer指针						
//pImageBuffer ImageBuffer指针						
//返回值说明:						
//读取失败返回0  否则返回复制的大小						
//**************************************************************************						
DWORD CopyFileBufferToImageBuffer(IN LPVOID pFileBuffer, OUT LPVOID* pImageBuffer)
{
	//DOS头
	PIMAGE_DOS_HEADER pDosHeader = NULL;
	//NT头
	PIMAGE_NT_HEADERS pNTHeader = NULL;
	//标准PE头
	PIMAGE_FILE_HEADER pPEHeader = NULL;
	//可选PE头
	PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;
	//节表
	PIMAGE_SECTION_HEADER pSectionHeader = NULL;


	if (!pFileBuffer)
	{
		printf("缓冲取指针无效\n");
		return 0;
	}

	//判断是否是有效的MZ标志	
	if (*((PWORD)pFileBuffer) != IMAGE_DOS_SIGNATURE)
	{
		printf("不是有效的MZ标志\n");
		return 0;
	}

	pDosHeader = (PIMAGE_DOS_HEADER)(pFileBuffer);

	//判断是否是有效的PE标志	
	if (*((PDWORD)((DWORD)pFileBuffer + pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE)
	{
		printf("不是有效的PE标志\n");
		return 0;
	}
	pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)(pFileBuffer)+pDosHeader->e_lfanew);
	pPEHeader = (PIMAGE_FILE_HEADER)(((DWORD)pNTHeader) + 4);
	pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER);
	pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);
	WORD numberOfSections = pPEHeader->NumberOfSections;

	printf("ImageBufferSize:%X\n", pOptionHeader->SizeOfImage);
	//分配ImageBuffer内存
	*pImageBuffer = (LPVOID)malloc(pOptionHeader->SizeOfImage);
	memset(*pImageBuffer, 0, pOptionHeader->SizeOfImage);
	if (!*pImageBuffer)
	{
		printf("分配ImageBuffer内存空间失败!\n");
		return 0;
	}
	//复制Headers
	memcpy(*pImageBuffer, pFileBuffer, pOptionHeader->SizeOfHeaders);

	//复制节表
	PIMAGE_SECTION_HEADER pTempSectionHeader = pSectionHeader;

	for (WORD i = 0; i < numberOfSections; i++)
	{
		LPVOID pSectionSrc = (LPVOID)((DWORD)(pFileBuffer)+pTempSectionHeader->PointerToRawData);
		LPVOID pSectionDst = (LPVOID)((DWORD)(*pImageBuffer) + pTempSectionHeader->VirtualAddress);
		memcpy(pSectionDst, pSectionSrc, pTempSectionHeader->SizeOfRawData);
		pTempSectionHeader++;

	}
	return pOptionHeader->SizeOfImage;
}
BOOL MemeryTOFile(IN LPVOID pMemBuffer, IN size_t size, OUT LPSTR lpszFile)
{
	FILE* pFile = NULL;

	//打开文件
	fopen_s(&pFile, lpszFile, "wb+");
	if (!pFile)
	{
		printf("无法创建exe\n");
		return FALSE;
	}
	fwrite(pMemBuffer, size, 1, pFile);
	fclose(pFile);
	pFile = NULL;
	return TRUE;
}
//**************************************************************************						
//ReadPEFile:将文件读取到缓冲区						
//参数说明:						
//lpszFile 文件路径						
//pFileBuffer 缓冲区指针						
//返回值说明:						
//读取失败返回0  否则返回实际读取的大小						
//**************************************************************************						
DWORD ReadPEFile(IN LPSTR lpszFile, OUT LPVOID* pFileBuffer)
{
	FILE* pFile = NULL;
	DWORD fileSize = 0;

	errno_t err;
	err = fopen_s(&pFile, lpszFile, "rb");
	//打开文件
	if (pFile == NULL)
	{
		return 0;
	}

	//读取文件大小
	fseek(pFile, 0, SEEK_END);
	fileSize = ftell(pFile);
	fseek(pFile, 0, SEEK_SET);

	//分配缓冲区
	*pFileBuffer = (LPVOID)malloc(fileSize);
	if (!*pFileBuffer)
	{
		fclose(pFile);
		return 0;
	}
	//将文件数据读取到缓冲区
	size_t n = fread(*pFileBuffer, fileSize, 1, pFile);
	if (!n)
	{
		free(*pFileBuffer);
		fclose(pFile);
		return 0;
	}
	//关闭文件
	fclose(pFile);
	return fileSize;

}
DWORD RvaToFileOffset(IN LPVOID pFileBuffer, IN DWORD dwRva)
{
	//DOS头
	PIMAGE_DOS_HEADER pDosHeader = NULL;
	//NT头
	PIMAGE_NT_HEADERS pNTHeader = NULL;
	//标准PE头
	PIMAGE_FILE_HEADER pPEHeader = NULL;
	//可选PE头
	PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;
	//节表
	PIMAGE_SECTION_HEADER pSectionHeader = NULL;


	if (!pFileBuffer)
	{
		printf("缓冲取指针无效\n");
		return 0;
	}

	//判断是否是有效的MZ标志	
	if (*((PWORD)pFileBuffer) != IMAGE_DOS_SIGNATURE)
	{
		printf("不是有效的MZ标志\n");
		return 0;
	}

	pDosHeader = (PIMAGE_DOS_HEADER)(pFileBuffer);

	//判断是否是有效的PE标志	
	if (*((PDWORD)((DWORD)pFileBuffer + pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE)
	{
		printf("不是有效的PE标志\n");
		return 0;
	}
	pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)(pFileBuffer)+pDosHeader->e_lfanew);
	pPEHeader = (PIMAGE_FILE_HEADER)(((DWORD)pNTHeader) + 4);
	pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER);
	pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);
	WORD numberOfSections = pPEHeader->NumberOfSections;
	DWORD dwFOA = 0;
	for (WORD i = 0; i < numberOfSections; i++, pSectionHeader++)
	{
		if (dwRva >= pSectionHeader->VirtualAddress && dwRva < pSectionHeader->VirtualAddress + pSectionHeader->Misc.VirtualSize)
		{
			dwFOA = pSectionHeader->PointerToRawData + dwRva - pSectionHeader->VirtualAddress;
		}
	}
	return dwFOA;
}
BOOL HasRELOCATION(LPVOID pFileBuffer)
{
	//DOS头
	PIMAGE_DOS_HEADER pDosHeader = NULL;
	//NT头
	PIMAGE_NT_HEADERS pNTHeader = NULL;
	//标准PE头
	PIMAGE_FILE_HEADER pPEHeader = NULL;
	//可选PE头
	PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;
	//节表
	PIMAGE_SECTION_HEADER pSectionHeader = NULL;


	if (!pFileBuffer)
	{
		printf("缓冲取指针无效\n");
		return 0;
	}

	//判断是否是有效的MZ标志	
	if (*((PWORD)pFileBuffer) != IMAGE_DOS_SIGNATURE)
	{
		printf("不是有效的MZ标志\n");
		return 0;
	}

	pDosHeader = (PIMAGE_DOS_HEADER)(pFileBuffer);

	//判断是否是有效的PE标志	
	if (*((PDWORD)((DWORD)pFileBuffer + pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE)
	{
		printf("不是有效的PE标志\n");
		return 0;
	}
	pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)(pFileBuffer)+pDosHeader->e_lfanew);
	pPEHeader = (PIMAGE_FILE_HEADER)(((DWORD)pNTHeader) + 4);
	pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER);
	pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);

	PIMAGE_DATA_DIRECTORY pIMAGE_DATA_DIRECTORY = (PIMAGE_DATA_DIRECTORY)&(pOptionHeader->DataDirectory[5]);
	if (pIMAGE_DATA_DIRECTORY->VirtualAddress==0 && pIMAGE_DATA_DIRECTORY->Size == 0)
	{
		return FALSE;
	}
	

	DWORD foa = RvaToFileOffset(pFileBuffer, pIMAGE_DATA_DIRECTORY->VirtualAddress);

	PIMAGE_BASE_RELOCATION pIMAGE_BASE_RELOCATION = (PIMAGE_BASE_RELOCATION)(foa + (DWORD)pFileBuffer);
	if (pIMAGE_BASE_RELOCATION->VirtualAddress && pIMAGE_BASE_RELOCATION->SizeOfBlock)
	{
		return TRUE;
	}
	return FALSE;
}

//修改ImageBase和重定位表
BOOL ModifyImageBaseAndRelocation(LPVOID* pFileBuffer, DWORD delta)
{
	//DOS头
	PIMAGE_DOS_HEADER pDosHeader = NULL;
	//NT头
	PIMAGE_NT_HEADERS pNTHeader = NULL;
	//标准PE头
	PIMAGE_FILE_HEADER pPEHeader = NULL;
	//可选PE头
	PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;
	//节表
	PIMAGE_SECTION_HEADER pSectionHeader = NULL;


	if (!(*pFileBuffer))
	{
		printf("缓冲取指针无效\n");
		return FALSE;
	}

	//判断是否是有效的MZ标志	
	if (*((PWORD)*pFileBuffer) != IMAGE_DOS_SIGNATURE)
	{
		printf("不是有效的MZ标志\n");
		return FALSE;
	}

	pDosHeader = (PIMAGE_DOS_HEADER)(*pFileBuffer);

	//判断是否是有效的PE标志	
	if (*((PDWORD)((DWORD)*pFileBuffer + pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE)
	{
		printf("不是有效的PE标志\n");
		return FALSE;
	}
	pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)(*pFileBuffer) + pDosHeader->e_lfanew);
	pPEHeader = (PIMAGE_FILE_HEADER)(((DWORD)pNTHeader) + 4);
	pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER);
	pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);
	//修改ImageBase
	pOptionHeader->ImageBase += delta;
	//修改重定位表
	PIMAGE_DATA_DIRECTORY pIMAGE_DATA_DIRECTORY = (PIMAGE_DATA_DIRECTORY)&(pOptionHeader->DataDirectory[5]);

	DWORD foa = RvaToFileOffset(*pFileBuffer, pIMAGE_DATA_DIRECTORY->VirtualAddress);

	PIMAGE_BASE_RELOCATION pIMAGE_BASE_RELOCATION = (PIMAGE_BASE_RELOCATION)(foa + (DWORD)*pFileBuffer);
	PIMAGE_BASE_RELOCATION pCurrent = pIMAGE_BASE_RELOCATION;

	DWORD page = 0;
	for (page; pCurrent->VirtualAddress && pCurrent->SizeOfBlock; page++)
	{

		DWORD Items = (pCurrent->SizeOfBlock - 8) / 2;

		WORD* pItem = (WORD*)((DWORD)pCurrent + 8);
		for (DWORD j = 0; j < Items; j++)
		{
			WORD Item = *(pItem + j);
			WORD ItemType = Item >> 12;
			Item = Item & 0x0FFF;
			if (ItemType == 3)
			{
				//计算要修改的RVA
				DWORD dwRVA = pCurrent->VirtualAddress + Item;
				//计算要修改的FOA
				DWORD dwFOA = RvaToFileOffset(*pFileBuffer, dwRVA);
				//修改原来的值为 原值+delta
				*(DWORD*)(dwFOA + (DWORD)*pFileBuffer) = *(DWORD*)(dwFOA + (DWORD)*pFileBuffer) + delta;
			}

		}
		pCurrent = (PIMAGE_BASE_RELOCATION)((BYTE*)pCurrent + pCurrent->SizeOfBlock);
	}



	return TRUE;
}

int main()
{

	LPVOID path = NULL;
	DWORD dwCImageBase = GetProcessImageBase(_getpid(),&path);

	//LPVOID fileBuffer = NULL;
	//DWORD fsize = ReadPEFile(path, &fileBuffer);
	//1、读取主模块数据
	LPVOID dataBuffer = NULL; 

	DWORD msize = ReadLastSection(dwCImageBase, &dataBuffer);
	if (dataBuffer == NULL)
	{
		return 1;
	}
	//2、解密得到原来的PE文件
	JieMi(&dataBuffer);


	//测试OK
	//MemeryTOFile(dataBuffer, msize, "D:\\testc.exe");

	PEHEADER peH;
	GetPEHeader(dataBuffer, &peH);
	DWORD dwSizeOfImage = peH.pOptionHeader->SizeOfImage;
	DWORD dwImageBase = peH.pOptionHeader->ImageBase;
	DWORD dwOEP = peH.pOptionHeader->AddressOfEntryPoint;
	BOOL hasRLOC = HasRELOCATION(dataBuffer);
	//free(dataBuffer);
	//3、以挂起的方式创建进程
	STARTUPINFO ie_si = { 0 };
	PROCESS_INFORMATION ie_pi;
	ie_si.cb = sizeof(ie_si);

	//以挂起的方式创建进程							
	char szBuffer1[256] = { 0 };//"D:\\jialeke.exe";
	wsprintf(szBuffer1, "%s", path);
	 CreateProcess(
		 szBuffer1,                    // name of executable module						
		 NULL,                // command line string						
		NULL, 					 // SD	
		NULL,  		             // SD				
		FALSE,                   // handle inheritance option						
		CREATE_SUSPENDED,     	 // creation flags  					
		NULL,                    // new environment block						
		NULL,                    // current directory name						
		&ie_si,                  // startup information						
		&ie_pi                   // process information						
	);

	//4、获取进程CONTEXT
	CONTEXT contx;
	contx.ContextFlags = CONTEXT_FULL;

	GetThreadContext(ie_pi.hThread, &contx);

	//获取入口点							
	DWORD dwEntryPoint = contx.Eax;
	printf("old entrypoint:%X\n", dwEntryPoint);
	//获取ImageBase							
	char* baseAddress = (CHAR *)contx.Ebx + 8;
	TCHAR szBuffer[4];
	memset(szBuffer, 0, 4);
	ReadProcessMemory(ie_pi.hProcess, baseAddress, szBuffer, 4, NULL);
	int* fileImageBase;
	fileImageBase = (int*)szBuffer;
	DWORD shellImageBase = *fileImageBase;

	//5、卸载外壳程序
	BOOL isUnload = UnloadShell(ie_pi.hProcess, shellImageBase);

	if (!hasRLOC)
	{
	    free(path);
	    path = NULL;
	    dataBuffer = NULL;
	    TerminateProcess(ie_pi.hProcess, 1234);
	    return 1;
	}

	LPVOID res = VirtualAllocEx(ie_pi.hProcess, (LPVOID)shellImageBase, dwSizeOfImage, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);

	if (!res)
	{
		free(path);
		free(dataBuffer);
		path = NULL;
		dataBuffer = NULL;
		TerminateProcess(ie_pi.hProcess, 1234);
		return 1;
	}
	//修复重定位表
	DWORD deta = (DWORD)res - dwImageBase;
	ModifyImageBaseAndRelocation(&dataBuffer, deta);
	LPVOID pImageBuffer = NULL;
	//拉伸
	CopyFileBufferToImageBuffer(dataBuffer, &pImageBuffer);
	if (pImageBuffer==NULL)
	{
		free(dataBuffer);
		dataBuffer = NULL;
		TerminateProcess(ie_pi.hProcess, 1234);
		return 1;
	}


	WriteProcessMemory(ie_pi.hProcess, res, pImageBuffer, dwSizeOfImage, NULL);

	contx.Eax = dwOEP + (DWORD)res;
	SetThreadContext(ie_pi.hThread, &contx);// 更新运行环境

	ResumeThread(ie_pi.hThread);
	CloseHandle(ie_pi.hThread);

	free(dataBuffer);
	free(path);
	free(pImageBuffer);
	return 0;
}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值