【逆向】PE文件的基本结构(3)--节表和RVA换算

来源:互联网 发布:淘宝客服可以在家做吗 编辑:程序博客网 时间:2024/06/10 05:57

PE文件中所有节的属性都被定义在节表中,节表由一系列的IMAGE_SECTION_HEADER结构排列而成,每个结构用来描述一个节,结构的排列顺序和它们描述的节在文件中的排列顺序是一致的。全部有效结构的最后以一个的IMAGE_SECTION_HEADER结构作为结束,所以节表中总的IMAGE_SECTION_HEADER结构数量等于节的数量加一。节表总是被存放在紧接在PE文件头的地方。

IMAGE_SECTION_HEADER结构的定义如下:

TISHMisc = packed record
    case Integer of
      0: (PhysicalAddress: DWORD);
      1: (VirtualSize: DWORD);
end;

IMAGE_SIZEOF_SHORT_NAME= 8;

_IMAGE_SECTION_HEADER = packed record
    Name: packed array[0..IMAGE_SIZEOF_SHORT_NAME-1] of Byte;
    Misc: TISHMisc;
    VirtualAddress: DWORD;                 //节区的RVA地址
    SizeOfRawData: DWORD;
    PointerToRawData: DWORD;         //从文件头开始算起的偏移量
    PointerToRelocations: DWORD;
    PointerToLinenumbers: DWORD;
    NumberOfRelocations: Word;
    NumberOfLinenumbers: Word;
    Characteristics: DWORD;
end;
TImageSectionHeader = _IMAGE_SECTION_HEADER;
IMAGE_SECTION_HEADER = _IMAGE_SECTION_HEADER;

●   Name字段

Name字段定义了节的名称,字段的长度为8个字节。

PE文件中的节的名称是一个由ANSI字符组成的字符串,但并没有规定以0结束,如果节的名称字符串长度小于8个字节的话,后面以0补齐,但是字符串长度达到8个字节的话,后面就没有0字符了,所以在处理的时候要注意字符串的结束方式。

每个节的名称是惟一的,不能有同名的两个节,但是节的名称不代表任何含义,它仅仅是为了查看方便而设置的一个标记而已,可以选择任何名称甚至将它空着也可以,将包含代码的节命名为“DATA”或者将包含数据的节命名为“CODE”都是合法的。

各种编译器都以自己的方式对节进行命名,所以,在PE文件中可以看到各式各样的节名称,比如,在MASM32产生的可执行文件中,代码节被命名为“.text”;可读写的数据节被命名为“.data”;包含只读数据、导入表以及导出表的节被命名为“.rdata”;而资源节被命名为“.rsrc”等。但是在其他一些编译器中,导入表被单独放在“.idata”中;而代码节可能被命名为“.code”。

RVA和文件偏移的转换

PE文件中出现RVA的概念是因为PE的内存映像和磁盘文件映像是不同的,为了提高效率,PE文件头中使用的都是内存映像中的偏移量,也就是RVA。RVA仅仅是对于处于节中的数据而言的,对于文件头和节表来说无所谓RVA和文件偏移,因为它们在被映射到内存中后不管是大小还是偏移都不会有任何改变。

当处理PE文件时,任何的RVA必须经过到文件偏移的换算:

(1)循环扫描节表并得到每个节在内存中的起始RVA(根据VirtualAddress字段),并根据节的大小(SizeOfRawData字段)算出节的结束RVA,最后比较判断目标RVA是否落在某个节之内。

(2)如果目标RVA处于某个节之内,那么用目标RVA减去节的起始RVA,这样就得到了目标RVA相对于节起始地址的偏移量RVA'。

(3)在节表中获取节在文件中所处的偏移(PointerToRawData字段),将这个偏移值加上上一步得到的RVA'值,这才是数据在文件中的真正偏移位置。

即:1 节的起始RVA - 节在文件中所处的偏移 = k

        2 目标RVA - k = 文件偏移

原创粉丝点击