新增节-添加代码

新增节需要满足的条件:

确保新增节后,节表区域仍有剩余空间以容纳一个节表。计算公式如下:

1
SizeOfHeader - DOS文件头 - 可选PE头 - 节表数量 * 0x28 > 80

**解释:**新增节后需留出一个节表的空间(遵循Windows规则)。若不遵守规则,可能导致程序异常。

修改的内容与步骤:

  1. 添加新的节表
    • 在现有节表末尾新增一个节,可以直接复制已有节表数据进行初始化。
  2. 填充新增节后的空间
    • 在新增节后,填充一个节大小的 0x00,确保数据完整。
  3. 修改PE头中的节表数量
    • 找到PE头中的NumberOfSections字段,增加1,更新节表数量。
  4. 更新SizeOfImage字段
    • 修改PE头中的SizeOfImage字段,增加内存对齐后的新增节大小。
  5. 在文件末尾新增节数据
    • 在原有数据末尾,添加一个内存对齐后的新增节数据区域。
  6. 修正新增节的属性
    • 确保新增节的属性字段设置正确(如只读、可执行等)。根据需要调整其Characteristics字段。
  7. 填充新增节数据
    • 在新增节区域内写入有效数据,避免数据为空导致程序运行失败。

当节表区空间不足时的处理方法:

  • 方法:前移NT头
    • 将NT头整体前移 0x20 个字节,覆盖DOS头后面的字符串部分,为节表区腾出额外空间。
  • 注意事项:
    • 确保调整后,PE结构完整且头部的偏移量正确。
    • 修改后及时校验文件是否能够正常运行。

Exercise

添加新的节表

找到节表所在位置和一共有几个表,由图中可知有四个表

image-20241124203214419

由图可得红色区域到第一个节表开始都是空白区

image-20241124203447256

复制40个字节即第一个节表到空白区,创建新的节表

image-20241124203536646

把节的数量改成5

image-20241124204738196

假设新增大小为1000字节的节表,找到sizeofimage加上1000

image-20241124205733817

image-20241124210000730

在文件结尾插入1000h大小的字节

image-20241124210419570

大小增大为20D000h

image-20241124210605023

可以根据前一个节表的值来填新节表的信息

image-20241124212957046

Name即节表的名字。可以随便改但不要超过限制大小;Virtual Size即内存中的大小(对齐前的长度),这里直接填1000即可;Virtual Offset即内存中的偏移(Virtual Address),根据前一个节表的信息可知这里应填0003E000+001CE000=0020C000;Raw Size即文件中大小(对齐后的长度),这里和Virtual Size填一样即可(1000),因为这个文件对齐前后没有拉伸;同理Raw Offset即文件中偏移,和Virtual Offset填一样即可(0020C000);Characteristics即块属性(标志),看需要填写,这里保持和第一个节表相同即可(可读)

image-20241124221802653

保存后重新打开可以正常运行,说明修改成功

用PE Tools打开可以看到已经成功添加节表

image-20241124223307419

若剩余空间不够,前移NT头增加剩余空间

通过查看e_lfanew的值可以找到NT头的起始地址,而e_lfanew和NT头之间即为垃圾数据,将NT头前移覆盖这些垃圾数据即可增加剩余空间(注意要复制整个NT头)

image-20241124224616404

复制后修改e_lfanew的值为新的NT头的起始地址,即下一行

image-20241124225127365

将NT头后面的数据都清0,之后可以在这些多出来的空间新增节表

image-20241124230238810

image-20241124225352284

保存后重新打开可以正常运行,说明修改成功

用PE Tools打开可以看到PE Address即e_lfanew的值已成功修改

image-20241124225606978

Work

示例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include "PE.h"

int main()
{
PIMAGE_DOS_HEADER dos = nullptr;
PIMAGE_FILE_HEADER file = nullptr;
PIMAGE_OPTIONAL_HEADER32 optional = nullptr;
PIMAGE_SECTION_HEADER* section = nullptr;

LPVOID fileBuffer = ReadPE("C:\\Users\\20870\\Desktop\\WaterDroplet.exe");
fileBuffer = SectionExpand(fileBuffer, 0x1000);
WriteMyFilePeData(fileBuffer, "C:\\Users\\20870\\Desktop\\New_WaterDroplet.exe");

if (fileBuffer)
{
free(fileBuffer);
}
}