PE3-20 扩大节-合并节-数据目录
扩大节-合并节-数据目录
扩大节
注意:只能扩大最后一个节。
操作步骤:
拉伸到内存
- 将节加载到内存后处理。
分配新的空间
增加
Ex
的空间,修改SizeOfImage
:1
SizeOfImage = SizeOfImage + Ex
修改最后一个节的大小
更新最后一个节的
SizeOfRawData
和VirtualSize
:1
2N = (max(SizeOfRawData, VirtualSize) 内存对齐后的值) + Ex
SizeOfRawData = VirtualSize = N
更新
SizeOfImage
修改 PE 头中的
SizeOfImage
值,增加新增空间的大小:1
SizeOfImage = SizeOfImage + Ex
合并节
合并节的意义在于节省节表空间。合并操作需要先扩大节后再进行。
操作步骤:
拉伸到内存
- 将要合并的节加载到内存,便于处理。
计算合并后的大小
合并后的大小取决于所有节的大小:
1
2Max = max(VirtualSize, SizeOfRawData) 内存对齐后的大小
合并节大小 = VirtualAddress + Max - SizeOfHeader 内存对齐后的值
修改第一个节的大小
- 更新第一个节的
VirtualSize
和SizeOfRawData
,两者设为合并后的大小。
- 更新第一个节的
调整节的属性
- 修改第一个节的属性,使其包含所有节的属性(如读、写、执行权限)。
修改节表数量
- 更新 PE 头中的
NumberOfSections
字段,将其设为1
。
- 更新 PE 头中的
数据目录
基础概念:
- 数据目录位置:
- 数据目录位于可选 PE 头的最后一项,包含 PE 文件运行时需要的重要信息。
- 数据目录的作用:
- 定位程序的资源信息,例如:
- 程序图标位置。
- 使用的系统函数。
- 提供给其他程序的函数。
- 定位程序的资源信息,例如:
数据目录结构:
1 | typedef struct _IMAGE_DATA_DIRECTORY { |
数据目录的 16 项:
- 与程序运行相关的主要目录项:
- 导出表 (Export Table)
- 导入表 (Import Table)
- 重定位表 (Relocation Table)
- IAT 表 (Import Address Table)
- 其他目录项:资源表、异常信息表、安全证书表、调试信息表、版权所以表、全局指针表、TLS表、加载配置表、绑定导入表、延迟导入表、COM信息表、最后一个表保留未使用。
实践练习
扩大最后一个节
- 按上述步骤,增加最后一个节的大小,保证程序运行正常。
合并所有节
- 将所有节合并为一个,更新节的属性和节表数量。
定义对齐函数
编写一个函数,返回内存对齐后的大小:
1
2
3int Align(int x, int alignment) {
return (x + alignment - 1) & ~(alignment - 1);
}
编程输出所有目录项
遍历数据目录的 16 项,并输出每一项
VirtualAddress
和Size
:1
2
3
4
5
6void PrintDirectories(PIMAGE_DATA_DIRECTORY directories) {
for (int i = 0; i < IMAGE_NUMBEROF_DIRECTORY_ENTRIES; i++) {
printf("Directory %d: VirtualAddress = 0x%X, Size = %d\n",
i, directories[i].VirtualAddress, directories[i].Size);
}
}
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Hexo!