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;}//复制Headersmemcpy(*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);//修改ImageBasepOptionHeader->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){//计算要修改的RVADWORD dwRVA = pCurrent->VirtualAddress + Item;//计算要修改的FOADWORD 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、获取进程CONTEXTCONTEXT 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. java 模拟电梯_请使用的Java的多线程知识来编写一个程序,实现一个简单的摩天大楼的电梯模型程序是以一座摩天大楼的多个电梯为背景,用线程、流程控制、随机函数等知识来模拟它。2、电梯的描述:...

    请使用的Java的多线程知识来编写一个程序,实现一个简单的摩天大楼的电梯模型 程序是以一座摩天大楼的多个电梯为背景,用线程.流程控制.随机函数等知识来模拟它. 2. 电梯的描述: 电梯是日常生活中经常 ...

  2. 一个简单的银行存取款小程序

    一个简单的银行存取款小程序 来由 银行存取款程序 程序功能 程序主体 后期改进内容 来由 2019年3月17晚,心血来潮想学习编程,向着一个伟大的程序员的方向出发.在我贫穷的知识库中,所了解到的编程语 ...

  3. 通过java程序写一个简单的创造游戏角色的程序

    一.题目分析: 题目要求,编写一个简化的创造游戏角色的程序,游戏角色应有:姓名,性别,种族,职业,力量,敏捷,体力,智力,智慧,生命值,魔法值等属性. 题目思路:根据题目可知,无论创建什么种族角色,都 ...

  4. Java网络编程(一)- 一个简单的服务端/客户端应用程序

    在Java中,我们使用java.net.Socket及其相关类来完成有关网络的相关功能.Socket类非常简单易用,因为Java技术隐藏了建立网络连接和通过连接发送数据的复杂过程.下面所说的内容只适用 ...

  5. 人脸识别手机端APK分享 | 极速体验人脸识别功能 创建一个简单的人脸识别手机APP程序

    1.前言 虹软公司提供免费离线人脸识别,对于开发者提供了比较友好.完整的可配置demo.但是如需直接体验功能,还是要花一点时间去完成项目编译.配置等一系列工作,对于初学者.不怎么熟悉整个项目的人来说可 ...

  6. 一个简单的电商网站秒杀程序的实现

    年关将至,各大电商网站火拼.沉迷于XXX网站前XX名免单,却百试不得其套路. 恰好刚好接触了selenium2.0,于是决定写一个自动抢购小程序. 1,首先是搭建selenium2.0环境. < ...

  7. C#队列Queue实现一个简单的电商网站秒杀程序

    电商的秒杀和抢购,对程序员来说,都不是一个陌生的东西.然而,从技术的角度来说,这对于Web系统是一个巨大的考验.当一个Web系统,在一秒钟内收到数以万计甚至更多请求时,系统的优化和稳定至关重要. 我们 ...

  8. 一道面试题:用shell写一个从1加到100的程序

    [试题描述] 请用shell写一个简短的程序,实现1+2+...+100的功能. [程序] 方法一: #!/bin/bash sum=0 for i in {1..100} dolet sum+=$i ...

  9. [导入]ASP.NET MVC框架开发系列课程(2):一个简单的ASP.NET MVC应用程序.zip(13.70 MB)...

    讲座内容: 使用ASP.NET MVC框架进行开发与ASP.NET WebForms截然不同.本次课程将通过官方的示例程序简单了解一下ASP.NET MVC应用程序的结构与特点. 课程讲师: 赵劼 M ...

最新文章

  1. Windows下安装配置SBT
  2. LeetCode 47全排列Ⅱ48旋转图像
  3. mysql 无论输入什么都是现实 not found_Java高频面试题及答案
  4. am335x 打开内部 RTC
  5. Linux awk命令详解??????????(研究)
  6. python pip在哪里_Python 2.7.9(Linux)中的pip在哪里
  7. Java中数据类型的取值范围
  8. 【转】C#中没有id 没有name C#怎么点击按钮
  9. 基于springboot的民办职业学校缴费系统
  10. 2010版gmp 计算机系统,2010版GMP附录:计算机化系统 整体及条款解读
  11. SD卡格式化造成数据丢失的恢复方法
  12. 使用 AndroidSocketClient 库建立 SSL 安全链接
  13. Contrastive Learning Based on Transformer for Hyperspectral Image Classification
  14. EndNote X9插入参考文献的格式
  15. 经典Web容器解析漏洞
  16. Bootstrap实战 - 单页面网站
  17. 从零开发Vscode上传图片插件
  18. 【微信小程序云开发】使用云函数(node.js)实现多张图片转成pdf的功能,且pdf带水印
  19. 什么是隐私混币协议Tornado Cash?| Tokenview
  20. 天津富斯特-供应压力容器-管壳式换热器

热门文章

  1. 【中秋征文】“海上生明月”中秋节网页特效
  2. FinTech创业的两大势力,以及他们各有千秋的数据应用模式 | TCFA纽约年会直击
  3. PXE-MOF:EXITING INTEL PXE ROM是什么意思
  4. 小程序中消息订阅与发布
  5. 奥利地公司利用Windows 和 Adobe 0day 攻击欧洲和中美洲实体
  6. 计算机word图标不显示,word图标不显示怎么办 设置图标显示的具体方法
  7. HashSet里的元素是不能重复的,那用什么方法来区分重复与否呢?
  8. 使用 Java 8 语言功能
  9. AMOS从模型到分析
  10. Unity 单例基类(运用单例模式)