PE文件结构随笔(未更新完)-Object Pascal描述

作者英文名:Delort

参考:《Windows PE权威指南》,Delphi的Winapi.Windows

1.DOS_HEADER

IMAGE_DOS_HEADER=record
       e_magic:Word; //exe标志,“MZ”
       e_cblp:Word;  //最后(部分)页中的字节数
       e_cp:Word;    //文件中的全部和部分页数
       e_crlc:Word;  //重定位表的指针数
       e_cparhdr:Word;   //头部尺寸,以段落为单位
       e_minalloc:Word;   //所需的最小附加段
       e_maxalloc:Word;   //所需的最大附加段
       e_ss:Word;         //初始的ss值
       e_sp:Word;         //初始的sp值
       e_csum:Word;       //补码校验值
       e_ip:Word;         //初始的ip值
       e_cs:Word;         //初始的cs值
       e_lfarlc:Word;     //重定位表的字节偏移量
       e_ovno:Word;       //覆盖号
       e_res:array[0..3] of Word; //保留字
       e_oemid:Word;        //OEM标识符
       e_oeminfo:Word;      //OEM信息
       e_res2:array[0..9] of Word;   //保留字
       e_lfanew:LongWord;   //PE文件相对于文件的偏移地址
   end;

2.NT_HEADER

IMAGE_NT_HEADERS=record
        Signature:Cardinal;  //“PE\0\0”
        FileHeader:IMAGE_FILE_HEADER;
        OptionalHeader:IMAGE_OPTIONAL_HEADER;
   end;        

3.FILE_HEADER

IMAGE_FILE_HEADER=record
         Machine:Word;   //运行平台
         NumberSizeOfSections:Word; //PE中节的数量
         TimeDateStamp:Cardinal;   //文件创建日期和时间
         PointerToSymbolTable:Cardinal;   //指向符号表(用于调试)
         NumberOfSymbols:Cardinal;       //符号表中的符号数量(用于调试)
         SizeOfOptionalHeader:Word;      //扩展头结构的长度
         Characteristics:Word;           //文件属性
   end;      

4.OPTIONAL_HEADER

IMAGE_OPTIONAL_HEADER=record
         Magic:Word;  //魔术字 107h是rom image,10bh是exe image
         MajorLinkerVersion:Byte;  //链接器版本号
         MinorLinkerVersion:Byte;
         SizeOfCode:Cardinal;      //所有含代码节的总大小
         SizeOfInitializedData:Cardinal;    //所有含已初始化数据的节的总大小
         SizeofUninitializedData:Cardinal;   //所有含未初始化数据的节的大小
         AddressOfEntryPoint:Cardinal;       //程序执行入口 RVA
         BaseOfCode:Cardinal;                //代码的节的起始RVA
         BaseOfData:Cardinal;                //数据的节的起始 RVA
         ImageBase:Cardinal;                 //程序的建议装载地址
         SectionAlignment:Cardinal;          //内存中节的对齐粒度
         FileAlignment:Cardinal;             //文件中的节的对齐粒度
         MajorOperatingSystemVersion:Word;   //操作系统版本号
         MinorOperatingSystemVersion:Word;
         MajorImageVersion:Word;             //该PE的版本号
         MinorImageVersion:Word;
         MajorSubsystemVersion:Word;         //所需子系统的版本号
         MinorSubsystemVersion:Word;
         Win32VersionValue:Cardinal;         //未用
         SizeOfImage:Cardinal;               //内存中整个PE的映像尺寸
         SzieOfHeaders:Cardinal;             //所有头+节表的总大小
         CheckSum:Cardinal;                  //校验和
         Subsystem:Word;                     //文件的子系统
         DllCharacteristics:Word;            //DLL文件特性
         SizeOfStackReverse:Cardinal;        //初始化的栈大小
         SizeOfStackCommit:Cardinal;         //初始化时实际提交的栈大小
         SizeOfHeapReverse:Cardinal;         //初始化时保留的堆大小
         SizeOfHeapCommit:Cardinal;          //初始化时提交的堆大小
         LoaderFlags:Cardinal;               //与调试有关
         NumberOfRvaAndSizes:Cardinal;       //下面的数据目录结构的项目数量
         DataDirectory:array[0..15] of IMAGE_DATA_DIRECTORY ; //数据目录
   end;                          

5.DATA_DIRECTORY

IMAGE_DATA_DIRECTORY =record
        virtualAddress:Cardinal;
        Size:Cardinal;
   end; 

6.数据目录入口

序号 名称 解释 是否讲解
0 IMAGE_DIRECTORY_ENTRY_EXPORT 导出表
1 IMAGE_DIRECTORY_ENTRY_IMPORT 导入表
2 IMAGE_DIRECTORY_ENTRY_RESOURCE 资源目录
3 IMAGE_DIRECTORY_ENTRY_EXCEPTION 异常处理表
4 IMAGE_DIRECTORY_ENTRY_SECURITY 安全表
5 IMAGE_DIRECTORY_ENTRY_BASERELOC 重定位表
6 IMAGE_DIRECTORY_ENTRY_DEBUG 调试表
7 IMAGE_DIRECTORY_ENTRY_ARCHITECTURE 版权表
8 IMAGE_DIRECTORY_ENTRY_GLOBALPTR 全局指针表
9 IMAGE_DIRECTORY_ENTRY_TLS 线程本地存储表
10 IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 加载配置表
11 IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 绑定导入表
12 IMAGE_DIRECTORY_ENTRY_IAT 导入函数地址表
13 IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 延迟导入表
14 IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR COM运行时描述符
7 IMAGE_DIRECTORY_ENTRY_COPYRIGHT 描述字符串

7.节表项

NT头后紧跟着节表,由许多节表项组成,记录了每个PE中与特定节有关的信息。

其数据结构如下:

TISHMisc = record
    case Integer of
      0: (PhysicalAddress: DWORD);
      1: (VirtualSize: DWORD);//节区尺寸
  end;
_IMAGE_SECTION_HEADER = record
    Name: packed array[0..IMAGE_SIZEOF_SHORT_NAME-1] of Byte;//8字节节名
    Misc: TISHMisc;//如上
    VirtualAddress: DWORD;//节区RVA地址
    SizeOfRawData: DWORD;//在文件中对齐后的尺寸
    PointerToRawData: DWORD;//在文件中的偏移
    PointerToRelocations: DWORD;//OBJ用
    PointerToLinenumbers: DWORD;//行号表位置-调试使用
    NumberOfRelocations: Word;//OBJ用
    NumberOfLinenumbers: Word;//行号表中行号数量
    Characteristics: DWORD;//节的属性
  end;
  

8.导入表

8.1导入表描述符

IMAGE_IMPORT_DESCRIPTOR = record
    case Byte of
      0: (Characteristics: DWORD);// 0 for terminating null import descriptor
      1: (OriginalFirstThunk: DWORD;//桥1
          TimeDateStamp: DWORD;//时间戳
          ForwarderChain: DWORD;//链表的前一个结构
          Name: DWORD;//指向链接库名字的指针
          FirstThunk: DWORD);//桥2
  end;

8.1.1OriginalFirstThunk

其中OriginalFirstThunk指向的数组的每个结构为IMAGE_THUNK_DATA,最后一个该结构以全零结束。这个结构定义了一个导入函数信息。

IMAGE_THUNK_DATA32 = record
    case Byte of
      0: (ForwarderString: DWORD); // PBYTE
      1: (_Function: DWORD);       // PDWORD Function -> _Function
      2: (Ordinal: DWORD);
      3: (AddressOfData: DWORD);   // PIMAGE_IMPORT_BY_NAME
  end;

这个结构是个双字。

最高位为0表示,表示导入符号是一个数值,该数值是一个RVA。

最高位为1表示,表示导入符号是一个名称。

8.1.2TimeDateStamp

一般不用,为0.如果该导入表项被绑定,那么绑定后的时间戳就被设置为对应的DLL文件时间戳。操作系统加载时,可以依据此项判断绑定信息是否过时。

8.1.3ForwarderChain

链表的前一个结构.

8.1.4Name

是个RVA,指向DLL文件的名称,以‘\0’结尾。

8.1.5FirstThunk

与OriginalFirstThunk相同,它指向的链表为Name这个动态链接库引入的所有导入函数。

桥1指向INT,桥2指向IAT,俩者内容一样,位置不同,最后指向"编号-名称"Hint/Name描述部分。

在内存中,桥1可以帮你找到调用的函数名称或者函数的索引编号,桥2可以帮你找到该函数指令代码在内存空间的地址。

当PE被加载进虚拟地址空间后,IAT的内容会被操作系统改为函数VA,会导致通向H/N的桥2断裂,发生断裂后,如果没有桥1作为参照,我们就无法重新找到该地址到底调用了哪个函数。

Borland的TLink只保留桥2,为单桥结构。

调用外部函数,IMAGE_THUNK_DATA会是个RVA,指向IMAGE_IMPORT_BY_NAME结构。

其结构如下:

_IMAGE_IMPORT_BY_NAME = record
    Hint: Word;//函数编号
    Name: array[0..0] of Byte;//函数名字的字符串
  end;
  IMAGE_IMPORT_BY_NAME = _IMAGE_IMPORT_BY_NAME;

8.2导入函数地址表-IAT

该地址表是数据目录的第13个数据项目录。是个双字数组。

其结构如下:

链接库1引入的函数1地址
链接库1引入的函数2地址
0x00000000
链接库2引入的函数1地址
链接库2引入的函数2地址
链接库2引入的函数3地址
0x00000000
........

8.3导入表遍历实验(暂时未更新)

实验步骤:

1.获取导入表第一个描述符的起始地址

2.获取导入表所处节的位置,同时显示

3.循环,直到到达末尾

4.显示链接库名称和该链接库所有函数和编号。

实验代码:


实验结果样图:

8.4绑定导入

目的:提前进行IAT修正的工作。

8.4.1绑定导入的数据结构

_IMAGE_BOUND_IMPORT_DESCRIPTOR = record
    TimeDateStamp: DWORD;//时间戳
    OffsetModuleName: Word;//指向DLL的名字
    NumberOfModuleForwarderRefs: Word;//ModuleForwarderRef的数目
    // Array of zero or more IMAGE_BOUND_FORWARDER_REF follows
  end;

8.4.2TimeDateStamp

该字段必须与引用的DLL文件头IMAGE_FILE_HEADER.TimeDateStamp字段值吻合。否则加载器重新计算IAT。发生在DLL版本不同或者DLL映像被重定位时。

8.4.3OffsetModuleName

存储了以IMAGE_BOUND_IMPORT_DESCRIPTOR作为基址,DLL名字的字符串的偏移。

8.4.4NumberOfModuleForwarderRefs

描述了在IMAGE_BOUND_IMPORT_DESCRIPTOR结构后的IMAGE_BOUND_FORWARDER_REF的数组元素个数。

其结构为:

_IMAGE_BOUND_FORWARDER_REF = record
    TimeDateStamp: DWORD;//时间戳
    OffsetModuleName: Word;//指向DLL名字
    Reserved: Word;//预留
  end;

8.4.5总体结构

IMAGE_BOUND_IMPORT_DESCRIPTOR(2个REF)
IMAGE_BOUND_FORWARDER_REF
IMAGE_BOUND_FORWARDER_REF
IMAGE_BOUND_IMPORT_DESCRIPTOR(1个REF)
IMAGE_BOUND_FORWARDER_REF
IMAGE_BOUND_IMPORT_DESCRIPTOR(3个REF)
IMAGE_BOUND_FORWARDER_REF
IMAGE_BOUND_FORWARDER_REF
IMAGE_BOUND_FORWARDER_REF
....

9.导出表

作用:

1.可以通过导出表分析不认识的动态链接库文件所提供的功能。

2.向调用者提供输出函数指令在模块中的起始地址。

9.1导出表数据结构

 _IMAGE_EXPORT_DIRECTORY = record
      Characteristics: DWord;//标志,未用
      TimeDateStamp: DWord;//时间戳
      MajorVersion: Word;//未用
      MinorVersion: Word;//未用
      Name: DWord;//指向该导出表的文件名字符串
      Base: DWord;//导出函数的起始序号
      NumberOfFunctions: DWord;//所有导出函数的个数
      NumberOfNames: DWord;//以函数名导出的函数的个数
      AddressOfFunctions: DWORD;//导出函数地址表RVA
      AddressOfNames: DWORD;//函数名称地址表RVA
      AddressOfNameOrdinals: DWORD;//函数序号地址表
  end;

9.1.1Name

一个字符串地址,记录了导出表所在文件的最初文件名。

9.1.2NumberOfFunctions

记录了文件中导出函数的总个数。

9.1.3NumberOfNames

记录了所有定义了名字的导出函数,有的没有名字。

9.1.4AddressOfFunctions

该指针指向了全部导出函数的入口地址的起始。从入口地址开始为双字数组,数组的个数由NumberOfFunctions决定。

导出函数每一个地址按函数编号依次往后排开。

9.1.5Base

导出函数编号的起始值。函数地址=Base+AddressOfFunctions。

9.1.6AddressOfNames

指向一连串的双字值,这些双字值均指向了对应的定义了函数名的函数的字符串地址。个数为NumberOfNames。

9.1.7AddressOfNameOrdinals

与AddressOfNames一一对应,不同的是AddressOfNames指向字符串指针数组,而AddressOfNameOrdinals则指向了该函数在AddressOfFunctions中索引值。索引值=编号-Base。是一个字大小。

10.重定位表

重定位表指针指向的是重定位项数组

10.1重定位表数据结构

IMAGE_BASE_RELOCATION=record
     VirtualAddress:DWord;
     SizeofBlock:DWord;
end;     

10.1.1VirtualAddress

重定位块RVA,是页面起始RVA

因为地址用=2*n+4+4个字节来表达。此处n为n个重定位项,第一个4为页面起始RVA,第二个4为本页重定位项个数。

为何有2呢?因为一页1000h大小,4096字节,及2**12,12位可以用2个字节表达

10.1.2SizeofBlock

重定位表项数目,第二个4.

10.1.3重定位项

每个重定位项大小为2字节,高四位说明类型,其余12位为地址。

常用的俩种类型:

0:无意义,对齐作用。

3:双32位都需要修正。

10.1.4重定位表结构

image-20200628100034808

你可能感兴趣的:(PE文件结构随笔(未更新完)-Object Pascal描述)