PE结构(5)新增节

Last updated on May 5, 2024 am

第一步,遍历节表

首先应当遍历节表,找到最后一节。

尝试在该节后找到一段连续的40字节空间,因为节表中每一项的长度是固定的40字节。

找到这块空间,便于我们操作。

寻找连续空间的函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
DWORD FindEmptyAddress(void* start, int maxSize, int codeLen) {
int count = 0;
int i = 0;
while (i <= maxSize - codeLen) {
char *current = (char*)start + i;
for (int j = 0; j < codeLen; j++) {
if (current[j] != 0) {
break;
}
count++;
}
if (count == codeLen) {
return (DWORD)current;
}
i += count + 1;
count = 0;
}
return 0;
}

找到连续的空间,确定插入新节的位置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
bool AddSection(lpPEFILE peFile, char* name, int length) {
lpPEHPE peHeader = peFile->h_pe;
lpPETable table = peFile->pet;

int sections = peHeader->NumberOfSections;

//提前确定了位置,直接来到我们想插入新表的位置
lpPETable newTable = table + sections;

//确定这个位置是40字节的连续空闲空间
DWORD injectEntry = FindEmptyAddress(newTable, 0x28, 0x28);

if (injectEntry == 0) {
return false;
}

第二步,复制节

先将最后一节复制到我们找到的这40字节空间中。

这样我们只需要在原节表的结构上修改即可。

1
2
3
4
//将原节表的40字节内容复制到新空间
memcpy(newTable, table + sections - 1, 0x28);
//给新节表的名字赋个值
memcpy(newTable->name, name, 8);

第三步,修复节表

新节表复制好了,但是其属性内容不太正常,我们需要修复一下(注意,此处要考虑内存对齐问题)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//文件内偏移,即FOA,直接加上老节表的Size即可
newTable->PointerToRawData += newTable->SizeOfRawData;
//内存内偏移,即RVA,直接加上老节表的Size即可
newTable->VirtualAddress += newTable->VirtualSize;
//设置本节在文件中长度,此处给了一个固定值
newTable->SizeOfRawData = length;
//同上,设置该节在内存中长度
newTable->VirtualSize = length;

//节表RVA,按内存对齐字段修复
DWORD sectionAlignment = peFile->h_op->SectionAlignment;
DWORD alignMod = newTable->VirtualAddress % sectionAlignment;
if (alignMod != 0) {
newTable->VirtualAddress += (sectionAlignment - alignMod);
}

//节表FOA,按文件对齐字段修复
DWORD fileAlignment = peFile->h_op->FileAlignment;
alignMod = newTable->PointerToRawData % fileAlignment;
if (alignMod != 0) {
newTable->PointerToRawData += (fileAlignment - alignMod);
}

第四步,修复PE头

1
2
3
4
//镜像的大小加上新增节的长度
peFile->h_op->SizeOfImage += length;
//PE头内增加节表项数量
peHeader->NumberOfSections += 1;

第五步,初始化新节

此处我就全部用0填充了。

1
2
DWORD imageBase = (DWORD)peFile->h_dos;
memset((void*)(imageBase + newTable->PointerToRawData), 0, newTable->SizeOfRawData);

完整函数

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
bool AddSection(lpPEFILE peFile, char* name, int length) {
lpPEHPE peHeader = peFile->h_pe;
lpPETable table = peFile->pet;

int sections = peHeader->NumberOfSections;
//step1 寻找新空间
lpPETable newTable = table + sections;
DWORD injectEntry = FindEmptyAddress(newTable, 0x28, 0x28);

if (injectEntry == 0) {
return false;
}
//step2 拷贝节表
memcpy(newTable, table + sections - 1, 0x28);
memcpy(newTable->name, name, 8);

//step3 修复节表属性
newTable->PointerToRawData += newTable->SizeOfRawData;
newTable->VirtualAddress += newTable->VirtualSize;
newTable->SizeOfRawData = length;
newTable->VirtualSize = length;

//内存对齐
DWORD sectionAlignment = peFile->h_op->SectionAlignment;
DWORD alignMod = newTable->VirtualAddress % sectionAlignment;
if (alignMod != 0) {
newTable->VirtualAddress += (sectionAlignment - alignMod);
}
//文件对齐
DWORD fileAlignment = peFile->h_op->FileAlignment;
alignMod = newTable->PointerToRawData % fileAlignment;
if (alignMod != 0) {
newTable->PointerToRawData += (fileAlignment - alignMod);
}

//step4 修复PE头
peFile->h_op->SizeOfImage += length;
peHeader->NumberOfSections += 1;

//step5 初始化节内空间
DWORD imageBase = (DWORD)peFile->h_dos;
memset((void*)(imageBase + newTable->PointerToRawData), 0, newTable->SizeOfRawData);
return true;
}

PE结构(5)新增节
http://dubhehub.github.io/blogs/2024050415400062615.html
Author
Sin
Posted on
May 4, 2024
Licensed under