• PE文件基础


    参考项目:https://code.google.com/p/portable-executable-library/

    1. RVA与VA,File Offset

    参考:http://www.pediy.com/kssd/pediy10/61737.html

    VA是内存中的真实的虚拟地址值;

    RVA是VA相对于ImageBase的相对偏移;

    而File Offset就是在PE映像文件中相对于文件开始处的偏移。

    PE文件的布局与最终加载到内存中的布局是不完全相同的,主要是因为有一些对齐的要求。

    在加载到内存时,粒度是section,也就是说一个section里面的内容会被加载到内存中连续的一片区域。

    因此,在一个section内部,所有内容的RVA/VA/File Offset是遵循相同的函数关系的。

    这个函数关系的信息,是保存在PE文件的section header结构中的。

    PE内部的地址都是以RVA形式保存的,从RVA转换到VA很简单,只需要获取到PE加载到内存中的ImageBase。

    虽然PE头部也会指定其“钟意”的基地址,但是很有可能最终没有被加载到这里。

    从RVA到File Offset的转换就是与具体的section相关的了。

    PE Bliss对于RVA到File Offset的转换代码如下:

    //RVA to RAW file offset convertion (4gb max)
    uint32_t pe_base::rva_to_file_offset(uint32_t rva) const
    {
        //Maybe, RVA is inside PE headers
        if(rva < get_size_of_headers())
            return rva;
     
        const section& s = section_from_rva(rva);
        return s.get_pointer_to_raw_data() + rva - s.get_virtual_address();
    }

    因为一个section里的内容的file offset与rva之间的偏移关系是相同的,即

    A.rva - A.offset = B.rva - B.offset

    A.offset = B.rva + A.rva - B.offset

    将B选取为这个section的头部,而A是该section中的任意一点,那么A.offset就可以通过上面的公式求出。

    2. 导入表

    导入表揭示了PE文件对于其他PE文件的依赖关系。

    当一个PE文件需要使用其他PE文件定义的函数或者变量时,需要知道这些内容在内存中的具体加载地址。

    这个信息是在链接过程中写入到PE文件中,要保证这个信息的正确,必须对依赖的那些PE文件的布局有了解,这也是为什么一个PE文件在链接时,需要指明它所依赖的其他PE文件的lib文件,因为lib文件就提供了这些相对位置的信息。

    这些相对位置,其实就是函数或者变量在其他PE文件中的RVA。

    3. 为什么PE文件中使用的地址都用RVA形式表示

    因为PE真正关心的是当它自己被拉起来运行时,它需要的内容要到内存中的哪个位置去找,而不是要到文件中的哪个位置去找。因此它关心其实是VA,而一旦相关映像被加载到内存中了,那么它们的ImageBase也就确定了,所以知道了RVA,就知道了VA。

  • 相关阅读:
    使用频率比较高的PHP函数方法
    penetration test:渗透测试
    penetration test:渗透测试
    按照数组的形式排序+条件切换切换查询
    PHP 性能优化技巧
    再谈PHP单引号和双引号区别
    表单验证的3个函数ISSET()、empty()、is_numeric()的使用方法
    向中级程序员转变必备的10个秘诀
    彻底杜绝PHP的session cookie错误
    Analysis by Its History_theorem 1.2
  • 原文地址:https://www.cnblogs.com/long123king/p/3645176.html
Copyright © 2020-2023  润新知