PE结构(2)节表/区块表

结构图总览

节表

偏移计算

DOS头大小固定64字节,标准PE头固定大小24字节,根据标准PE头中的SizeOfOptionalHeader属性可计算 可选PE头长度。

从标准PE头偏移处开始,计算 24 + SizeOfOptionalHeader 即可得到节表偏移量。

节表项

节表中一共有NumberOfSections个项目,每个项目总计40字节,每项有固定格式如下:

字节数 名称 示例值 备注
BYTE[8] NAME “.text” 节名称
DWORD PhysicalAddress/VirtualSize union联合体,存储节内数据在内存中未内存对齐时长度
DWORD VirtualAddress 该节在内存中的实际偏移量RVA
DWORD SizeOfRawData 该节在磁盘中实际所占大小,文件对齐
DWORD PointerToRawData 该节在磁盘中的实际偏移RVA
DWORD PointerToRelocations 无意义
DWORD PointerToLinenumbers 无意义
WORD NumberOfRelocations 无意义
WORD NumberOfLinenumbers 无意义
DWORD Characteristics 节属性,描述该节可读/可写/可执行等信息

编程检验

C语言实现如下:

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
107
108
109
110
111
112
113
114
115
#include <stdio.h>
#include <memory.h>

#define FILE_READ_PATH "D:\\test.exe"
#define SIZE_DOS 64
#define SIZE_PE 24
#define SIZE_TABLE_INDEX 40

typedef unsigned short WORD, *PWORD;
typedef unsigned int DWORD, *PDWORD;

bool OpenFile(FILE** ppFile) {
FILE *pFile = fopen(FILE_READ_PATH, "rb");
if (pFile == nullptr) {
return false;
}
*ppFile = pFile;
return true;
}

void Read(FILE* pFile, void* dst, int length) {
char* pDst = (char*)dst;
for (int i = 0; i < length; i++) {
pDst[i] = fgetc(pFile);
}
}

void ReadWord(FILE* pFile, PWORD dst) {
Read(pFile, dst, 2);
}

void ReadDWord(FILE* pFile, PDWORD dst) {
Read(pFile, dst, 4);
}

//获取PE头偏移
bool GetPEHeaderRva(FILE* pFile, PDWORD pNumber) {
if (pNumber == nullptr) {
return false;
}
fseek(pFile, 0, SEEK_SET);
fseek(pFile, SIZE_DOS - 4, SEEK_CUR);
ReadDWord(pFile, pNumber);
fseek(pFile, 0, SEEK_SET);

return true;
}

//获取节数量
bool GetNumOfSections(FILE* pFile, DWORD rva, PWORD pNumber) {
if (pNumber == nullptr) {
return false;
}
fseek(pFile, 0, SEEK_SET);
fseek(pFile, rva + 6, SEEK_CUR);
ReadWord(pFile, pNumber);
fseek(pFile, 0, SEEK_SET);

return true;
}

//获取可选PE头大小
bool GetNumOfOptional(FILE* pFile, DWORD rva, PWORD pNum) {
if (pNum == nullptr) {
return false;
}
fseek(pFile, 0, SEEK_SET);
fseek(pFile, rva + 20, SEEK_CUR);
ReadWord(pFile, pNum);
fseek(pFile, 0, SEEK_SET);
return true;
}

//打印节表
void PrintfSectionHeader(FILE* pFile, int rva, int numOfSections) {
fseek(pFile, 0, SEEK_SET);
fseek(pFile, rva, SEEK_CUR);

char name[9]{ 0 };
for (int i = 0; i < numOfSections; i++) {
Read(pFile, name, 8);
printf("第%d个节Name:%s \r\n", i+1, name);
fseek(pFile, SIZE_TABLE_INDEX - 8, SEEK_CUR);
memset(name, 0, 9);
}
}

int main() {
FILE* file = nullptr;
if (!OpenFile(&file)) {
printf("打开文件 %s 失败! \r\n", FILE_READ_PATH);
return 0;
}

DWORD nPEHeaderRVA = 0;
if (!GetPEHeaderRva(file, &nPEHeaderRVA)) {
printf("无法获取PE头偏移! \r\n");
return 0;
}

WORD numOfSections = 0;
if (!GetNumOfSections(file, nPEHeaderRVA, &numOfSections)) {
printf("无法获取节数量!\r\n");
return 0;
}

WORD sizeOfOptional = 0;
if (!GetNumOfOptional(file, nPEHeaderRVA, &sizeOfOptional)) {
printf("无法获取OP头长度!\r\n");
return 0;
}

int nSectionsHeaderRVA = nPEHeaderRVA + SIZE_PE + sizeOfOptional;
PrintfSectionHeader(file, nSectionsHeaderRVA, numOfSections);
}

程序输出:


PE结构(2)节表/区块表
http://dubhehub.github.io/blogs/202401112059001543.html
Author
Sin
Posted on
January 11, 2024
Licensed under