RVA是相对虚拟地址,FOA是文件偏移
PE文件头与PE内存映像的文件头大小都是一样的,它们受对齐粒度不同的影响; 节的数据在内存和磁盘文件的大小是不一样的,节表项记录了内存映像中节的起始RVA,也同样记录了本节在文件中的起始偏移,节表项IMAGE_SECTION_HEADER是我们可以找到这两个字段之间存在关联的唯一的方:

由于节在内存中是线性排列的,因此如果找到下一个节的内存起始RVA就能知道 上一个节的大小。所有的节组合起来就是PE中除去文件头以外的所有内容,而文件头在磁盘文件和内存中是没有变化的。
这些特点使用在文件头部数据结构中的所有RVA字段都可以通过比较方法将该RVA定位到某个具体的节。有了这个节的内存起始RVA0,就可以求出指定RVA距离节头的偏移off,而这个偏移在磁盘文件和内存中都是一样的(因为对齐时是在节的数据后面补0,而不是前面)。
当我们获取到某个RVA在某个节中距离节头的偏移off后,就可以通过该节在文件中的偏移求出这个RVA在文件中的偏移了。大致的步骤如下:
步骤1: 判断指定的RVA落在哪个节内。
步骤2:求出该节的起始RVA0=IMAGE_SECTION_HEADER.VirtualAddress
步骤3:求出偏移量 offset1 = RVA0 - RVA
步骤4:求出该RVA相对于磁盘文件头的偏移FOA=IMAGE_SECTION_HEADER.PointerToRawData + off

步骤1:很明显,通过对比 RVA20<RVA<RVA30, 指定RVA落在节2内。
步骤2:该节起始为: RVA0 = RVA20
步骤3:距离本节的偏移量为: off = RVA-RVA20
步骤4:该RVA相对于磁盘文件头的偏移为:
FOA = IMAGE_SECTION_HEADER.PointerToRawData + off
= FOA20 + off
= FOA20 + RVA - RVA20
网友评论