扩大节-合并节-数据目录

扩大节

注意:只能扩大最后一个节。

操作步骤:

  1. 拉伸到内存

    • 将节加载到内存后处理。
  2. 分配新的空间

    • 增加Ex的空间,修改 SizeOfImage

      1
      SizeOfImage = SizeOfImage + Ex
  3. 修改最后一个节的大小

    • 更新最后一个节的 SizeOfRawDataVirtualSize

      1
      2
      N = (max(SizeOfRawData, VirtualSize) 内存对齐后的值) + Ex
      SizeOfRawData = VirtualSize = N
  4. 更新SizeOfImage

    • 修改 PE 头中的 SizeOfImage值,增加新增空间的大小:

      1
      SizeOfImage = SizeOfImage + Ex

合并节

合并节的意义在于节省节表空间。合并操作需要先扩大节后再进行。

操作步骤

  1. 拉伸到内存

    • 将要合并的节加载到内存,便于处理。
  2. 计算合并后的大小

    • 合并后的大小取决于所有节的大小:

      1
      2
      Max = max(VirtualSize, SizeOfRawData) 内存对齐后的大小
      合并节大小 = VirtualAddress + Max - SizeOfHeader 内存对齐后的值
  3. 修改第一个节的大小

    • 更新第一个节的 VirtualSizeSizeOfRawData,两者设为合并后的大小。
  4. 调整节的属性

    • 修改第一个节的属性,使其包含所有节的属性(如读、写、执行权限)。
  5. 修改节表数量

    • 更新 PE 头中的 NumberOfSections 字段,将其设为 1

数据目录

基础概念

  1. 数据目录位置:
    • 数据目录位于可选 PE 头的最后一项,包含 PE 文件运行时需要的重要信息。
  2. 数据目录的作用:
    • 定位程序的资源信息,例如:
      • 程序图标位置。
      • 使用的系统函数。
      • 提供给其他程序的函数。

数据目录结构:

1
2
3
4
5
6
typedef struct _IMAGE_DATA_DIRECTORY {				
DWORD VirtualAddress; // 数据目录的内存偏移(经过内存拉伸)
DWORD Size; // 数据目录的大小
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;

#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16

数据目录的 16 项:

  • 与程序运行相关的主要目录项:
    1. 导出表 (Export Table)
    2. 导入表 (Import Table)
    3. 重定位表 (Relocation Table)
    4. IAT 表 (Import Address Table)
  • 其他目录项:资源表、异常信息表、安全证书表、调试信息表、版权所以表、全局指针表、TLS表、加载配置表、绑定导入表、延迟导入表、COM信息表、最后一个表保留未使用。

实践练习

  1. 扩大最后一个节

    • 按上述步骤,增加最后一个节的大小,保证程序运行正常。
  2. 合并所有节

    • 将所有节合并为一个,更新节的属性和节表数量。
  3. 定义对齐函数

    • 编写一个函数,返回内存对齐后的大小:

      1
      2
      3
      int Align(int x, int alignment) {
      return (x + alignment - 1) & ~(alignment - 1);
      }
  4. 编程输出所有目录项

    • 遍历数据目录的 16 项,并输出每一项VirtualAddressSize

      1
      2
      3
      4
      5
      6
      void 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);
      }
      }