日期:2014-05-17  浏览次数:20661 次

PE 基础求解
将RVA转换为File Offset,给大家一个非常经典的公式:
设:VK为相对虚拟地址RVA与文件偏移地址File Offset的差值
VA=ImageBase+RVA
File Offset = RVA ---VK
File Offset = VA---ImageBase---VK


这个里面 VK 怎么知道?

------解决方案--------------------
贴一段我当年写的代码
C/C++ code


extern vector<Section_Header*> *sh_table;
extern vector<Import_Table*> *it_table;
extern Pe_Header *ph;

/* RVA即(Relative Virtual Address)相对与可执行文件加载地址的虚拟地址。
* VA即(Virtual Address)虚拟地址,即可执行文件在加载到内存中的地址。
* 偏移量则为可执行文件存在磁盘上的偏移地址。
*
* 由于在磁盘上与内存中有不同的对齐方式,因此在第一个段之后,RVA与文件偏移不同。
* 在第一个段之前,RVA与偏移地址是相同的。
*
* 因此,在分析一个没被Loader加载到内存的可执行文件映像,需要计算RVA。
* RVA计算方法
* 1. 遍历可执行文件中的每一个段,根据各个段的起始RVA(IMAGE_SECTION_HEADER->VirtualSize),
*    以及该段的原始大小(IMAGE_SECTION_HEADER->SizeOfRawData),计算该段结束RVA。
*
* 2. 测试欲计算的RVA,在哪一个段中,找到后,用应计算RVA减去该段起始RVA,得到相对于该段起始RVA
*    的偏移RVA。
*
* 3. 在段表中获取该段的文件所属偏移,加上上一步得到的偏移RVA,即欲计算的目标RVA的偏移地址。
*/

DWORD RvaToVa(DWORD rva)
{
    static DWORD (*sections)[3] = NULL;
    //设置为static变量,目的在于对于一个可执行文件,
    //只计算一次各段的起始地址、段尾地址、以及原始指针数组

    //However,I do not know why I set the type to a pointer to a array of three DWORDs,
    //but just a original array of three DWORDs.

    DWORD numberOfSection = ph->GetSectionNumber ();
    if (sections == NULL){
        sections = new DWORD[numberOfSection][3] ;
        for (DWORD i = 0;i < numberOfSection; i++)
        {
            sections[i][0] = (*sh_table)[i]->VirtualAddress;
            //sections[i][0]:段的起始RVA:VirtualAddress
            sections[i][1] = (*sh_table)[i]->SizeOfRawData + sections[i][0];
            //sections[i][1]:段尾:VirtualAddress + SizeOfRawData
            sections[i][2] = (*sh_table)[i]->PointerToRawData;
            //sections[i][3]:段原始偏移指针: PointerToRawData
        }
    }
    for (DWORD i = 0;i < numberOfSection;i++)
    {
        if ( rva > sections[i][0] && rva < sections[i][1] ){
            DWORD va = rva - sections[i][0];
            va += sections[i][2];
            return va;
        }
    }
    return -1;
}