一个简单的加壳解壳程序

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
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Crack破解必学,手动脱壳,案例收集 01、破解工具的介绍 02、壳的介绍已经脱壳常用思路 03、手脱UPX的几种方法 04、手脱ASPack以及变形壳的几种方法 05、手脱FSG1.33变形壳 06、手脱PECompact 07、手脱nspack(北斗)和PEncrypt 08、手脱Yoda's Crypter以及SFX法 09、手脱Telock 10、手脱PETITE和FSG 2.0 11、ESP定律与内存断点详解 12、附加数据的处理方法 13、程序自校验的解除方法 14、手脱EncryptPE壳以及附加数据的处理 15、手脱Armadillo壳(穿山甲壳) 16、进阶Armadillo壳 17、手脱Acprotect壳 18、手脱ASProtect壳 19、带发修行ACProtect v1.21 20、两种方法以自己的名字注册ASProtect加壳程序 21、寻Stolen Code之Acprotect 22、手脱ASProtect 1.31 05.18 23、手脱Armadillo CopyMem-ll +Debug-Blocker 24、菜鸟也脱SVKP 25、PE区段优化减肥 26、简单汇编基础1 27、简单汇编基础2 28、软件破解的思路1 29、软件破解的思路2 30、软件的爆破1 31、软件的爆破2 32、软件的爆破3 33、破解补丁的制作 34、注册码的追踪方法1 35、注册码的追踪方法2 36、注册码的追踪方法3 37、Delphi程序的破解1 38、Delphi程序的破解2 39、VB程序的破解1 40、VB程序的破解2 41、算法分析1 42、算法分析2 43、算法分析3 44、内存注册机的制作 45、内存补丁的制作 46、了解Delphi1 47、了解Delphi2 48、使用Delphi语言编写算法注册机 49、黑鹰破解大师破解经验总结1 50、黑鹰破解大师破解经验总结2
Zprotect是新一代的软件加密保护系统,拥有多项革命性的创新技术,设计用来保护您的软件产品不被破解,减少由于盗版给您带来的经济损失!此外,Zprotect 拥有简单易用的许可控制系统,您无需更改任何代码,即可为您的软件添加注册机制。与传统软件保护系统相比,Zprotect更加注重对代码的处理,并且拥有良好的稳定性和兼容性,是您配置软件保护系统的最佳选择! Zprotect拥有简单易用、高效灵活的注册和授权管理系统: 一键试用技术. Zprotect 为您提供一键试用技术,您不必修改任何源代码,在短短几分钟之内就可以将您的完整版软件转换为“先试用后购买”的试用版软件,甚至还可以支持带硬件锁定的序列号注册。 内建注册和许可管理系统. Zprotect 内建灵活易用的注册和许可管理系统,您可以轻松创建具有时间限制、硬件锁定、水印信息的注册码。 动态算法生成引擎. 外壳所使用算法均动态生成,随机且唯一,让逆向算法变得困难和高成本。 时间限制注册密钥. 如果您需要限制注册版本的有效期,可以通过创建具有时间限制的注册密钥来实现。 硬件锁定(一机一码). 激活硬件锁定功能的注册密钥,只能在某一特定计算机上使用;您可以通过锁定用户计算机的硬件信息来控制注册码的传播,例如 CPU、硬盘序列号、网卡 MAC 地址等。 密钥黑名单. 如果您的用户泄漏了注册密钥,那么您就可以将该密钥添加进密钥黑名单,这样下一版本更新的时候您就可以锁定该密钥。 启动密码保护. 这种附加的保护可以有效防止软件未经授权的使用,必须输入正确的密码才可以运行程序。 试用次数、天数、日期和运行时间限制. 使用 Zprotect ,您可以轻松为您的应用程序添加试用次数、试用天数、试用日期和试运行时间等限制;这样您的客户就可以全功能评估您的软件产品,增大购买意向

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值