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;
}