Last updated on January 13, 2024 pm
模拟PE加载过程 将文件从磁盘load到内存,再从内存中解析PE信息,然后开辟新内存进行“拉伸”操作。
定义PE结构体 由于PE中的内容全部是按1字节进行结构体对齐,因此在定义结构体时应当注意对齐方式,以及保存编译环境对齐字节。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 #ifndef PE #define PE typedef unsigned char BYTE, * lpBYTE;typedef unsigned short int WORD, * lpWORD;typedef unsigned int DWORD, * lpDWORD;#pragma pack(push) #pragma pack(1) typedef struct _PE_HEADER_DOS { WORD e_magic; WORD e_cblp; WORD e_cp; WORD e_crlc; WORD e_cparhdr; WORD e_minalloc; WORD e_maxalloc; WORD e_ss; WORD e_sp; WORD e_csum; WORD e_ip; WORD e_cs; WORD e_lfarlc; WORD e_ovno; WORD e_res[4 ]; WORD e_oemid; WORD e_oeminfo; WORD e_res2[10 ]; DWORD e_lfanew; }PEHDOS, *lpPEHDOS;typedef struct _PE_HEADERS_PE { DWORD Signature; WORD Machine; WORD NumberOfSections; DWORD TimeDateStamp; DWORD PointerToSymbolTable; DWORD NumberOfSymbols; WORD SizeOfOptionalHeader; WORD Characteristics; }PEHPE, *lpPEHPE;typedef struct _PE_HEADERS_OPTIONAL { WORD Magic; BYTE MajorLinkerVersion; BYTE MinorLinkerVersion; DWORD SizeOfCode; DWORD SizeOfInitializedData; DWORD SizeOfUninitializedData; DWORD AddressOfEntryPoint; DWORD BaseOfCode; DWORD BaseOfData; DWORD ImageBase; DWORD SectionAlignment; DWORD FileAlignment; WORD MajorOperatingSystemVersion; WORD MinorOperatingSystemVersion; WORD MajorImageVersion; WORD MinorImageVersion; WORD MajorSubsystemVersion; WORD MinorSubsystemVersion; DWORD Win32VersionValue; DWORD SizeOfImage; DWORD SizeOfHeader; DWORD CheckSum; WORD Subsystem; WORD DllCharacteristics; DWORD SizeOfStackReserve; DWORD SizeOfStackCommit; DWORD SizeOfHeapReserve; DWORD SizeOfHeapCommit; DWORD LoaderFlags; DWORD NmberOfRvaAndSizes; }PEHOPTIONAL, *lpPEHOPTIONAL;typedef struct _PE_HEADERS_TABLE_ITEM { BYTE name[8 ]; DWORD VirtualSize; DWORD VirtualAddress; DWORD SizeOfRawData; DWORD PointerToRawData; DWORD PointerToRelocations; DWORD PointerToLinenumbers; WORD NumberOfRelocations; WORD NumberOfLinenumbers; DWORD Characteristics; } PETable, *lpPETable;#pragma pack(pop) typedef struct _PE { lpPEHDOS h_dos; lpPEHPE h_pe; lpPEHOPTIONAL h_op; lpPETable pet; }PEFILE, *lpPEFILE;int LoadFileToMemory (FILE* pFile, lpPEFILE lpPEFile) ;void * CreateImageBuffer (lpPEFILE lpPEFile) ;void DumpImageToFile (FILE* pFile, void * imageBase, lpPEFILE lpPEFile) ;#endif
文件从磁盘到内存 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 int LoadFileToMemory (FILE* pFile, lpPEFILE lpPEFile) { int fileLength = 0 ; fseek(pFile, 0 , SEEK_END); fileLength = ftell(pFile); fseek(pFile, 0 , SEEK_SET); BYTE* start = new BYTE[fileLength]{ 0 }; for (int i = 0 ; i < fileLength; i++) { start[i] = fgetc(pFile); } lpPEFile->h_dos = (lpPEHDOS)start; int peOffset = lpPEFile->h_dos->e_lfanew; lpPEFile->h_pe = (lpPEHPE)((DWORD)start + peOffset); DWORD peAddress = (DWORD)lpPEFile->h_pe; lpPEFile->h_op = (lpPEHOPTIONAL)(peAddress + 24 ); WORD sizeOfOptionalHeader = lpPEFile->h_pe->SizeOfOptionalHeader; lpPEFile->pet = (lpPETable)(peAddress + 24 + sizeOfOptionalHeader); return fileLength; }
解析内存PE信息 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 void * CreateImageBuffer (lpPEFILE peFile) { lpPEHDOS lpHdos = peFile->h_dos; if (lpHdos == nullptr) { return nullptr; } DWORD imageBaseSrc = (DWORD)lpHdos; lpPEHPE lpHpe = peFile->h_pe; if (lpHpe == nullptr) { return nullptr; } lpPEHOPTIONAL lpHop = peFile->h_op; if (lpHop == nullptr) { return nullptr; } lpPETable lpTable = peFile->pet; if (lpTable == nullptr) { return nullptr; } DWORD sizeOfImage = lpHop->SizeOfImage; void *pMemoryBuffer = new BYTE[sizeOfImage]; DWORD imageBaseDst = (DWORD)pMemoryBuffer; DWORD sizeOfHeader = lpHop->SizeOfHeader; memcpy (pMemoryBuffer, (void *)imageBaseSrc, sizeOfHeader); WORD numberOfSections = lpHpe->NumberOfSections; for (int i = 0 ; i < numberOfSections; i++) { lpPETable t = (lpTable + i); DWORD pointerToRawData = t->PointerToRawData; DWORD sizeOfRawData = t->SizeOfRawData; DWORD virtualAddress = t->VirtualAddress; memcpy ((void *)(imageBaseDst + virtualAddress), (void *)(imageBaseSrc + pointerToRawData), sizeOfRawData); } return pMemoryBuffer; }
从内存中还原到磁盘 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 void DumpImageToFile (FILE* pFile, void * imageBase, lpPEFILE peFile) { fseek(pFile, 0 , SEEK_SET); lpPEHDOS lpHdos = peFile->h_dos; if (lpHdos == nullptr) { return ; } lpPEHPE lpHpe = peFile->h_pe; if (lpHpe == nullptr) { return ; } lpPEHOPTIONAL lpHop = peFile->h_op; if (lpHop == nullptr) { return ; } lpPETable lpTable = peFile->pet; if (lpTable == nullptr) { return ; } DWORD sizeOfHeader = lpHop->SizeOfHeader; for (int i = 0 ; i < sizeOfHeader; i++) { BYTE byte = *((lpBYTE)imageBase + i); fputc(byte, pFile); } WORD numberOfSections = lpHpe->NumberOfSections; for (int num = 0 ; num < numberOfSections; num++) { lpPETable t = (lpTable + num); DWORD pointerToRawData = t->PointerToRawData; DWORD sizeOfRawData = t->SizeOfRawData; DWORD virtualAddress = t->VirtualAddress; fseek(pFile, pointerToRawData, SEEK_SET); for (int i = 0 ; i < sizeOfRawData; i++) { BYTE byte = *((lpBYTE)imageBase + virtualAddress + i); fputc(byte, pFile); } } }
测试程序 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 #include <stdio.h> #include <memory.h> #include "PE.h" int main () { PEFILE peFile{ 0 }; FILE *pFile = fopen("D:\\src.exe" , "rb" ); int fileLength = LoadFileToMemory(pFile, &peFile); void *pMemoryBuffer = nullptr; fclose(pFile); pMemoryBuffer = CreateImageBuffer(&peFile); pFile = fopen("D:\\dst.exe" , "wb" ); DumpImageToFile(pFile, pMemoryBuffer, &peFile); delete[] pMemoryBuffer; delete peFile.h_dos; }
PE结构(3)从磁盘到内存的加载过程
http://dubhehub.github.io/blogs/2024011317470017231.html