0x01  重定位表结构

     重定位表是由数据目录表中的第六个成员指出的:

typedef struct _IMAGE_DATA_DIRECTORY {
DWORD VirtualAddress;
DWORD Size;
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;

 

 

    程序编译时每个模块有一个优先加载地址ImageBase,这个值是链接器给出的,因此链接器生成的指令中的地址是在假设模块被加载到ImageBase前提之下生成的,那么一旦程序没有将模块加载到ImageBase时,那么程序中的指令地址就需要重新定位,从而需要重定位表的修正。

    对于EXE应用程序来说,在自己独立的4G进程空间中,它是肯定加载到ImageBase默认基地址上的。但是动态链接库就不一样了,动态链接库都是映射到别的应用程序的空间中的,所以出现要载入的基地址被应用程序占据了也是很正常的,这时它就必须进行重定位了。

    重定位的算法功能可以描述为:将直接寻址指令中的地址加上模块实际装入地址与模块建议(默认)装入地址之差。

    参与运算的是这3个数据:需要修正的机器码地址, 模块的实际装入地址,模块的建议(默认)装入地址ImageBase.而模块的建议(默认)装入地址已经ImageBase中定义了,而模块的实际装入地址是Windows加载器确定的, 因此,PE文件的重定位表中唯一保存的就是一组需要修正的代码的地址。

    (位置)重定位表一般会被单独存放在一个以“.reloc”命名的节中,但这并不是必然的,因为重定位表放在其他节中也是合法的,但是如果重定位表存在的话,它的地址肯定可以在数据目录中找到。

  

    为了节省空间,重定位表对需要重定位的指令的地址的存放方式做了一些优化。

    直观上看,x86下每个32位的指针占用4个字节,如果有n个重定位项,那么重定位表的总大小就是4×n字节大小。

    直接寻址指令在程序中还是比较多的,在相临近的各个重定位表项中,32位指针的高位地址总是相同的,如果将这些相近表项的高位地址只用少数几位来统一表示,那么就可以节省一部分的空间。

    当按照一个内存页来分割时,在一个页面中寻址需要的指针位数是12位(一页4096字节,2的12次方),将这12位按WORD对齐为16位,再用一个附加的DWORD来表示页的起始指针,另一个DWORD来表示本页中的重定项数,那么占用的总空间就是4+4+2×n字节大小,当某个内存页中的重定位项多于4项的时候,后一种方法的占用空间就会比前面的方法要小。0

    PE文件中重定位表的组织方法就是采用类似的按页分割的方法,从PE文件头的数据目录中得到重定位表的地址后,这个地址指向的就是顺序排列在一起的很多重定位块,每一块用来描述一个内存页中的所有重定位项。

    重定位表由一个个的重定位块组成,如果重定位表存在的话,必定是至少有一个重定位块。因为每个块只负责定位0x1000大小范围内的数据,因此如果要定位的数据范围比较大的话,就会有多个重定位块存在。

    每个块的首部IMAGE_BASE_RELOCATION定义如下:

typedef struct _IMAGE_BASE_RELOCATION {
DWORD VirtualAddress; //重定位内存页的起始RVA,本块中所有重定位项中的12位地址加上这个起始地址后就得到了真正的RVA值
DWORD SizeOfBlock; //重定位块的大小,从这个字段的值可以算出块中重定位项的数量
} IMAGE_BASE_RELOCATION

  由于SizeOfBlock=4+4+2×n,也就是sizeof IMAGE_BASE_RELOCATION+2×n,所以重定位项的数量就等于(SizeOfBlock-sizeof IMAGE_BASE_RELOCATION)÷2。

  MAGE_BASE_RELOCATION结构后面跟着的n个WORD就是重定位项,每个重定位项的16位数据位中的低12位就是需要重定位的数据在页面中的地址,剩下的高4位用来描述当前重定位项的种类。

  所有的重定位块最终以一个VirtualAddress字段为0的IMAGE_BASE_RELOCATION结构作为结束,因此可执行文件的代码总是从装入地址的1000h处开始定义的了(比如装入00400000h处的.exe文件的代码总是从00401000h开始,而装入10000000h处的.dll文件的代码总是从10001000h处开始),要是代码从装入地址处开始定义,那么第一页代码的重定位块的VirtualAddress字段就会是0,这就和重定位块的结束方式冲突了。

  

  

  

PE文件 03 重定位表的更多相关文章

  1. PE结构之重定位表

    什么是重定位: 重定位就是你本来这个程序理论上要占据这个地址,但是由于某种原因,这个地址现在不能让你占用,你必须转移到别的地址,这就需要基址重定位.你可能会问,不是说过每个进程都有自己独立的虚拟地址空 ...

  2. 逆向-PE重定位表

    重定位表 ​ 当链接器生成一个PE文件时,会假设这个文件在执行时被装载到默认的基地址处(基地址+RVA就是VA).并把code和data的相关地址写入PE文件.如果像EXE一样首先加载就是它image ...

  3. Windows PE第6章 栈与重定位表

    第六章 栈与重定位表 本章主要介绍栈和代码重定位.站和重定位表两者并没有必然的联系,但都和代码有关.栈描述的是代码运行过程中,操作系统为调度程序之间相互调用关系,或临时存放操作数而设置的一种数据结构. ...

  4. Reverse Core 第二部分 - 16&17章 - 基址重定位表&.reloc节区

    第16-17章 - 基址重定位表&.reloc节区 @date: 2016/11/31 @author: dlive 0x00 前言 这几天忙着挖邮箱漏洞,吃火锅,马上要被关禁闭,看书进度比较 ...

  5. 基址重定位表&.reloc节区

    第16-17章 - 基址重定位表&.reloc节区 @date: 2016/11/31 @author: dlive 0x01 PE重定位 若加载的是DLL.SYS文件,且在ImageBase ...

  6. ELF 动态链接 - so 的 重定位表

    动态链接下,无论时可执行文件还是共享对象,一旦对其他共享对象有依赖,也就是所有导入的符号时,那么代码或数据中就会有对于导入符号的引用.而在编译时期这些导入符号的确切地址时未知的.只有在运行期才能确定真 ...

  7. PE格式第七讲,重定位表

    PE格式第七讲,重定位表 作者:IBinary出处:http://www.cnblogs.com/iBinary/版权所有,欢迎保留原文链接进行转载:) 一丶何为重定位(注意,不是重定位表格) 首先, ...

  8. PE知识复习之PE的重定位表

    PE知识复习之PE的重定位表 一丶何为重定位 重定位的意思就是修正偏移的意思.  如一个地址位 0x401234 ,Imagebase = 0x400000 . 那么RVA就是 1234.  如果Im ...

  9. WindowsPE权威指南-PE文件头中的重定位表

    PE加载的过程 任何一个EXE程序会被分配4GB的内存空间,用户层处理低2G的内存,驱动处理高2G的内存. 1.双击EXE程序,操作系统开辟一个4GB的空间. 2.从ImageBase决定了加载后的基 ...

随机推荐

  1. 响应式布局与bootstrap框架

    原文 网页布局方式 1.固定宽度布局:为网页设置一个固定的宽度,通常以px做为长度单位,常见于PC端网页. 2.流式布局:为网页设置一个相对的宽度,通常以百分比做为长度单位. 3.栅格化布局:将网页宽 ...

  2. ADO.NET梳理

    目录: 简单的介绍下ADO.NET SqlConnection(连接对象) SqlCommand(命令对象) SqlParameter(Sql参数) SqlDataReader(数据流读取器) Sql ...

  3. PHP操作MySQL数据库--PHP的应用

    一.Apache服务器的安装 <1>安装版(计算机相关专业所用软件---百度云链接下载)-直接install<2>非安装版(https://www.apachehaus.com ...

  4. Confluence 6 修改一个空间从归档到当前

    通过空间目录: 进入头部的 空间(Spaces ) > 空间目录(Space directory). 在左侧 选择 归档的空间(Archived Spaces). 找到你的空间,然后单击右侧的  ...

  5. centos7 mysql+MHA高可用安装

    https://dzone.com/articles/consul-proxysql-and-mysql-ha?utm_medium=feed&utm_source=feedpress.me& ...

  6. 安卓——AppTheme

    <?xml version="1.0" encoding="utf-8"?> <resources> <style name=&q ...

  7. python中lambda的用法

    一.lambda函数也叫匿名函数,即,函数没有具体的名称.先来看一个最简单例子: def f(x):return x**2print f(4) Python中使用lambda的话,写成这样 g = l ...

  8. GitHub C 和 C++ 开源库的清单(含示例代码)

    内容包括:标准库.Web应用框架.人工智能.数据库.图片处理.机器学习.日志.代码分析等. 标准库 C++标准库,包括了STL容器,算法和函数等. C++ Standard Library:是一系列类 ...

  9. commonJS,常用js工具方法

    说明:平时项目用到的一些常见过滤方法,有些是vue过滤器,稍微修改下吧,我就不改了. js四舍五入不准确的解决(重写方法): Number.prototype.toFixed = function(l ...

  10. ADG配置(主备库环境)

    @font-face { font-family: "Courier New"; }@font-face { font-family: "宋体"; }@font ...