全局变量有无初始值的区别:
没有初始值:PE文件在文件中的状态的时候不会对该变量的地址进行存储,只有在内存中运行的时候的状态才会进行分配
有初始值:PE文件在文件中的状态的时候会对该变量的地址进行存储
VA:英文全称是Virual Address,简称VA,中文意思是虚拟地址,指的是文件被载入虚拟空间后的地址。
ImageBase:中文意思是基址,指的是程序在虚拟空间中被装载的位置。
RVA:相对虚拟地址,可以理解为文件被装载到虚拟空间(拉伸)后先对于基址的偏移地址。
它的对齐方式一般是以1000h为单位在虚拟空间中对齐的(传说中的4K对齐),具体对齐需要参照IMAGE_OPTIONAL_HEADER32中的SectionAlignment成员。
FOA:文件偏移地址。可以理解为文件在磁盘上存放时相对于文件开头的偏移地址。
它的对齐方式一般是以200h为单位在硬盘中对齐的(512对齐),具体对齐需要参照IMAGE_OPTIONAL_HEADER32中的FileAlignment成员。
计算方式:RVA = VA(虚拟地址) - ImageBase(基址)
RVA(相对虚拟地址)转换FOA(文件偏移地址)过程:
int a = 0x12345678;
int main() {
printf("地址:%.8X\n",&a);
printf("数值:%d\n",a);
return 0;
}
运行结果:
D:\VC6EN\COMMON\MSDEV98\BIN\Debug>5.exe
地址:00424A30
数值:305419896
我们要求RVA,RVA = VA - ImageBase,VA虚拟地址为0x00424A30
,
那么 RVA = 424A30 - ImageBase
查看Imagebase:0x00400000
RVA = 424A30 - 400000 = 24A30
接下来寻址FOA,就要考虑文件对齐跟内存对齐不是一样的问题 所以我们要考虑是否对齐方式是一样的
第一种情况:如果文件对齐跟内存对齐一样,那么这样就可以直接去找
第二种情况:比如文件对齐和内存对齐不一样
我们需要判断RVA属于哪个节/头,这里也要分为两种情况!
1):如果RVA属于文件头部(DOS头 + PE头 + 节表)
那么不需要进行计算了,因为DOS头和PE头和节表在文件中和在内存中展开都是一样的,直接从开始位置寻找到RVA个字节即可,那么这里也就是24A30
2):如果RVA不在头,就要判断在哪个节里面
判断节开始位置到节结束位置 我们的RVA是否在这个范围里面 20890
RVA >= 指定节.VirtualAddress
RVA <= 指定节.VirtualAddress + 当前节内存对齐后的大小
差值 = RVA - 指定节.VirtualAddress + 当前节内存对齐后的大小
FOA = 指定节.PointerToRawData + 差值
FOA(文件偏移地址)转换RVA(相对虚拟地址)过程:
设FOA为节数据的任意一位置
1.计算差值偏移: FOA - 节.PointerToRawData(节数据在文件中开始的位置) == 差值偏移.
2.计算RVA: 差值偏移 + 节.VirtuallAddress(节数据在内存中展开的位置) == RVA
3.计算虚拟地址: RVA+ ImageBase == VA
需要注意的就是我们的 FOA 在哪一个节中. FOA <= 节.PointerToRawData + 节.SizeofRawData