PE结构(3)从磁盘到内存的加载过程

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 // !PE.h

文件从磁盘到内存

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);
}
//设置DOS头位置
lpPEFile->h_dos = (lpPEHDOS)start;
//设置PE头位置
int peOffset = lpPEFile->h_dos->e_lfanew;
lpPEFile->h_pe = (lpPEHPE)((DWORD)start + peOffset);
//设置OP头位置
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) {
//PE属性
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;

//拷贝PE头
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);

//PE属性
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;
}

//拷贝PE头
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() {
//将指定文件加载到内存,并解析PE信息到PEFILE结构体
PEFILE peFile{ 0 };
FILE *pFile = fopen("D:\\src.exe", "rb");
int fileLength = LoadFileToMemory(pFile, &peFile);
void *pMemoryBuffer = nullptr;
fclose(pFile);

//根据PE信息创建内存映像
pMemoryBuffer = CreateImageBuffer(&peFile);

//根据内存映像dump到磁盘
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
Author
Sin
Posted on
January 13, 2024
Licensed under