zoukankan      html  css  js  c++  java
  • PE结构学习笔记(六)

    Chinese:

    1、通常,区块中得数据在逻辑上是关联的。PE文件一般至少都会有两个区块:一个代码块、一个数据块。

    2、区块在映像中是按起始地址(RVA)排列的,而不是按字母表顺序。

    3、通常区块名称及其意义

    .text  默认的区块代码。它的内容全是指令代码。连接器把所有目标文件的.text块链接成一个大的.text块。

    .data  默认的读/写数据区块。全局变量、静态变量一般放在这。

    .rdata  默认的只读数据区块。至少有两种情况下要用到.rdata。一是Microsoft的连接器产生的exe文件中,用于存放调试目录;二是用于存放说明字符串。

    .idata  包含其他外来dll的函数及数据信息,即我们说的输入表。将.idata区块合并到另外一个区块现在已成惯例,典型的是.rdata区块。

    .edata  输出表。当创建一个输出api或者数据的可执行文件时,连接器会创建一个.exp文件,这个.exp文件就包含了一个.edata区块,它会被加入到最后的可执行文件中。与.idata区块一样,.edata区块也经常被发现合并到了.text或.data区块中。

    .rsrc  资源,包含模块的全部资源,如图标、菜单、位图等。这个区块是只读的,无论如何它不应该命名为.rsrc以外的其他任何名字,也不能被合并到其他区块里。

    .bss  未初始化数据。很少在用,取而代之的是执行文件的.data区块的Virtual Size被扩展到足够大的空间来装下未初始化数据。

    .tls  tls的意思是线程局部存储器,用于支持通过__declspec(thread)声明的线程局部存储变量的数据,这包括数据的初始化值,也包括运行时所需要的额外变量。

    .reloc  可执行文件的基址重定位。基址重定位一般仅是dll文件才需要的。在Release模式,连接器并不给exe文件加上基址重定位,重定位可以在连接时通过/fixed开关去掉。

    .sdata  可通过全局指针相对寻址的"短"可读/写数据。用于IA-64和其他使用全局指针寄存器的体系上。IA-64上的正常大小的全局变量位于这个节中。

    .srdata  可通过全局指针相对寻址的"短"只读数据。用于IA-64和其他使用全局指针寄存器的体系上。

    .pdata  异常表。包含一个IMAGE_RUNTIME_FUNCTION_ENTRY类型的结构数组,这个结构是特定于CPU的。数据目录中的IMAGE_DIRECTORY_ENTRY_EXCEPTION指向它。用于使用基于表的异常处理的体系,比如IA-64。唯一一个不使用基于表的异常处理的体系是x86。

    .debug$S  obj文件中CodeView格式的符号。这是一个可变长的CodeView格式符号记录流。

    .debug$T  obj文件中CodeView格式的类型记录。这是一个可变长的CodeView格式类型记录流。

    .debug$P  当使用预编译头时会出现在obj文件中。

    .drectve  只用于obj文件,包含一些链接器指令。这些指令是一些能被传递到链接器命令行的ASCII字符串。例如:-defaultlib:LIBC 多个指令之间用空格隔开。

    .didat  延迟加载的导入数据。可在用非Release模式创建的可执行文件中找到它。而在Release模式,延迟加载数据被合并到其他节中。

    4、在VC++中可以命名我们的区块,用#pragma来声明,告诉编译器插入数据到一个区块内,格式如下:

      #pragma data_msg("FC_data")

    以上语句告诉编译器将数据都放进一个名为"FC_data"的区块内。

    5、区块一般是从obj文件开始,被编译器放置的。链接器的工作就是合并左右obj和库中需要的块,使其成为一个最终合适的区块。链接器会遵循一套相当完整的规则,它会判断哪些区块将被合并以及如何被合并到其他区块里。

    6、RVA(Relative Virtual Address) 相对虚拟地址。RVA是当PE文件被装载到内存中后,某个数据位置相对于文件头的偏移量。

    比如Windows装载器将一个PE文件装入到00400000h(虚拟地址)处的内存中,而某个区块中得某个数据被装入到0040xxxx处,那么这个数据的RVA就是0040xxxxh-00400000h=xxxxh,反过来说,将RVA的值加上文件被装载的基地址,就可以找到数据在内存中的实际地址。

    7、RVA使得文件装入内存后的数据定位变得方便,然而却给我们要定位位于磁盘上的静态PE文件带来了麻烦。

    8、换算RVA和文件偏移

    步骤一:循环扫描区块表得出每个区块在内存中的起始RVA(根据IMAGE_SECTION_HEADER中得VirtualAddress字段),并根据区块的大小(根据IMAGE_SECTION_HEADER中得SizeOfRawData字段)算出区块的结束RVA(两者相加),最后判断目标RVA时否落在该区块内。

    步骤二:通过步骤一定位了目标RVA处于具体的某个区块后,那么用目标RVA减去该区块的起始RVA,这样就能得到目标RVA相对于起始地址的偏移量RVA2。

    步骤三:在区块表中获取该区块在文件中所处的偏移地址(根据IMAGE_SECTION_HEADER中得PointerToRawData字段),将这个偏移值加上步骤二得到的RVA2值,就得到了真正的文件偏移地址。

  • 相关阅读:
    runtime-给系统已有类添加属性
    解决自定义leftBarButtonItem返回手势失效的方法
    类和对象
    内存拷贝
    响应者链
    属性
    懒加载
    封装思想
    屏幕旋转
    block
  • 原文地址:https://www.cnblogs.com/maplewan/p/3233754.html
Copyright © 2011-2022 走看看