PE文件的两种状态

如下图,当PE文件于硬盘中存放时按照FileAlignment对齐,在内存中时按照SectionAlignment对齐,整个头可视为一体,在节表的最后和每个节区的最后按照格式对齐。

PE文件的拉伸与压缩

拉伸时将每个节区的PointerToRawData写入到VirtualAddress,反之亦然,头部直接按照SizeOfHeaders写入就行了

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
LPVOID file2Image(LPVOID lpFileBuffer, DWORD *pdwBufferSize) {
PIMAGE_DOS_HEADER pDos =
(PIMAGE_DOS_HEADER)lpFileBuffer;
PIMAGE_NT_HEADERS pNT =
(PIMAGE_NT_HEADERS)((DWORD)lpFileBuffer + pDos->e_lfanew);
PIMAGE_FILE_HEADER pFile =
(PIMAGE_FILE_HEADER)((DWORD)pNT + 4);
PIMAGE_OPTIONAL_HEADER pOption =
(PIMAGE_OPTIONAL_HEADER)((DWORD)pFile + IMAGE_SIZEOF_FILE_HEADER);
PIMAGE_SECTION_HEADER pFirstSection =
PIMAGE_SECTION_HEADER((DWORD)pOption + pFile->SizeOfOptionalHeader);

/*按照拉伸后的大小申请内存*/
LPVOID lpImageBuffer = malloc(pOption->SizeOfImage);

memset(lpImageBuffer, 0, pOption->SizeOfImage);

/*写入头部,不需要对齐,下面从VA开始写入*/
memcpy(lpImageBuffer, lpFileBuffer, pOption->SizeOfHeaders);

/*遍历写入节区,按照内存对齐写入*/
PIMAGE_SECTION_HEADER pSectionHeader = pFirstSection;
for (int i = 0; i < pFile->NumberOfSections; i++) {
memcpy(
(LPVOID)((DWORD)lpImageBuffer + pSectionHeader->VirtualAddress),
(LPVOID)((DWORD)lpFileBuffer + pSectionHeader->PointerToRawData),
pSectionHeader->Misc.VirtualSize
);
/*指向下一个节表*/
pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pSectionHeader + IMAGE_SIZEOF_SECTION_HEADER);
}

*pdwBufferSize = pOption->SizeOfImage;


return lpImageBuffer;
}

LPVOID image2File(LPVOID lpImageBuffer, DWORD *pdwBufferSize) {
PIMAGE_DOS_HEADER pDos =
(PIMAGE_DOS_HEADER)lpImageBuffer;
PIMAGE_NT_HEADERS pNT =
(PIMAGE_NT_HEADERS)((DWORD)lpImageBuffer + pDos->e_lfanew);
PIMAGE_FILE_HEADER pFile =
(PIMAGE_FILE_HEADER)((DWORD)pNT + 4);
PIMAGE_OPTIONAL_HEADER pOption =
(PIMAGE_OPTIONAL_HEADER)((DWORD)pFile + IMAGE_SIZEOF_FILE_HEADER);
PIMAGE_SECTION_HEADER pFirstSection =
PIMAGE_SECTION_HEADER((DWORD)pOption + pFile->SizeOfOptionalHeader);

/*获取最后一个节表的地址*/
PIMAGE_SECTION_HEADER pLastSection =
PIMAGE_SECTION_HEADER((DWORD)pFirstSection + ((pFile->NumberOfSections - 1) * IMAGE_SIZEOF_SECTION_HEADER));

/*获取FileBuffer的大小,用最后一个节的文件偏移加上文件对齐大小得出*/
*pdwBufferSize = pLastSection->PointerToRawData + pLastSection->SizeOfRawData;

/*按照文件对齐大小分配内存*/
LPVOID lpFileBuffer = malloc(*pdwBufferSize);

memset(lpFileBuffer, 0, *pdwBufferSize);

/*写入头,按照文件对齐*/
memcpy(lpFileBuffer, lpImageBuffer, pOption->SizeOfHeaders);

PIMAGE_SECTION_HEADER pSectionHeader = pFirstSection;
for (int i = 0; i < pFile->NumberOfSections; i++) {
/*按照文件对齐遍历写入*/
memcpy(
(LPVOID)((DWORD)lpFileBuffer + pSectionHeader->PointerToRawData),
(LPVOID)((DWORD)lpImageBuffer + pSectionHeader->VirtualAddress),
pSectionHeader->SizeOfRawData
);

/*指向下一个节表*/
pSectionHeader=(PIMAGE_SECTION_HEADER)((DWORD)pSectionHeader + IMAGE_SIZEOF_SECTION_HEADER);
}

return lpFileBuffer;
}

遍历目录项

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
#include<Windows.h>
#include<stdio.h>
#include<stdlib.h>
#include<PETool.h>
#pragma comment(lib,"PETool.lib")
#define FILEPATH TEXT("D:\\absolution\\temporary\\test.exe")
#define OUTFILEPATH TEXT("D:\\absolution\\temporary\\output.exe")

int main() {
/*读取PE文件*/
LPVOID lpFileBuffer = createFileBuffer(FILEPATH);

if (!lpFileBuffer) {
return 0;
}

DWORD dwSize;
LPVOID lpImageBuffer = file2Image(lpFileBuffer, &dwSize);


PIMAGE_DOS_HEADER pDos =
(PIMAGE_DOS_HEADER)lpImageBuffer;
PIMAGE_NT_HEADERS pNT =
(PIMAGE_NT_HEADERS)((DWORD)lpImageBuffer + pDos->e_lfanew);
PIMAGE_FILE_HEADER pFile =
(PIMAGE_FILE_HEADER)((DWORD)pNT + 4);
PIMAGE_OPTIONAL_HEADER pOption =
(PIMAGE_OPTIONAL_HEADER)((DWORD)pFile + IMAGE_SIZEOF_FILE_HEADER);
PIMAGE_SECTION_HEADER pFirstSection =
(PIMAGE_SECTION_HEADER)((DWORD)pOption + pFile->SizeOfOptionalHeader);

for (int i = 0; i < pOption->NumberOfRvaAndSizes; i++) {
IMAGE_DATA_DIRECTORY IDD = pOption->DataDirectory[i];
printf("表项%d \n%X\n%X\n---------\n", i, IDD.VirtualAddress, IDD.Size);
}

free(lpImageBuffer);

free(lpFileBuffer);

getchar();
}