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

一丶何为重定位  

    重定位的意思就是修正偏移的意思.  如一个地址位 0x401234 ,Imagebase = 0x400000 . 那么RVA就是 1234.  如果Imagebase 变了成了0x300000, 那么修正之后就是 ImageBase + RVA = 0X300000+1234 = 0x301234.

    首先我们知道.一个EXE文件.会调用很多DLL(PE) 有多个PE文件组成.

exe文件启动的基址 (ImageBase) 是0x40000. 假设我们调用三个DLL  A B C.

A DLL 在EXE展开的基址位置是0x10000000

那么恰巧 B DLL 展开的位置也是 0x1000000 两个DLL位置展开地方是一样的.那么就出现问题了.

如下图:

这时候操作系统就会给我们进行修正. 将B DLL 换个内存位置. 进行展开. 这也是为什么很多游戏外挂.等等.都选择DLL注入. 因为系统帮你重定位了各种信息. 代码写在DLL中即可.

如下图: B DLL 从0x20.... 展开了.规避了使用相同地址

虽然这样解决了入口基址不一样.内存展开不一样. 但是我们知道.PE文件中有很多RVA .RVA 是相对于ImageBase的偏移进行存放的. 如果PE文件中都是 RVA 那就好办了.

但是不一定呀.

如一下代码所示:

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <Windows.h>
  4. int g_Value;
  5. int main()
  6. {
  7. g_Value = ;
  8.  
  9. }

查看其反汇编

我们发现,在给全局变量赋值的的时候.地址是一个固定的.他不是 RVA

再次运行截图:

我们发现地址变了. 而且硬编码 是一个固定的. 0x012c813c ,他直接编译到二进制文件中了.

他把  ImageBase + RVA的值. 直接编译到二进制当中. 就是说.这个全局变量的地址. 是一个 RVA + IMAGEBASE 的地址. 但是他是直接编译到二进制中的.

问题所在:

  假设A编译的全局变量的地址是  RVA + iMAGEbase 假设是 0x1012345,那么A展开的位置是 0x10..... 那么全局变量地址是正确的. 但是如果B编译的时候.地址也是1012345. 但是模块基址加载不一样.那么就会出问题了.如下图:

根据上面我们发现了问题所在.所以现在我们需要一张表.记录那个地方需要进行重定位. 我们把这个地方的值改一下即可.

也就是要记录我们修改需要重定位的位置.以上图的代码进行反汇编查看.

也就是记录需要重定位的地方即可.

重定位表就是记录所有需要修正的地址.只要有了重定位表.我们就不用担心我们的ImageBase 没有占住位置.

非常重要的一张表.

二丶重定位表的定位以及结构

  重定位表.的定位在扩展头中的数据目录中. 数据目录的第6项就是重定位表的 RVA偏移.以及重定位表的大小.

定位到重定位表,那么有额外的结构体来描述重定位表.

  1. typedef struct _IMAGE_BASE_RELOCATION {
  2. DWORD VirtualAddress;
  3. DWORD SizeOfBlock; //存储的值以字节为单位.字节多大.表示了一个重定位快有多大.
  4. // WORD TypeOffset[1];
  5. } IMAGE_BASE_RELOCATION;
  6. typedef IMAGE_BASE_RELOCATION UNALIGNED * PIMAGE_BASE_RELOCATION;

看着重定位表就两个成员. 其实非常复杂. 我们设 VirtualAddress 为 x 设 SizeofBlock为Y

如下图所示,一个格子为1个字节.

第一行四个字节为x.也就是 Virtualaddress.. y则是第二个成员

  1. SizeOfBlock 成员你的意思. 以字节为单位.代表重定位的快由多大. 我们知道.一个PE文件需要很多地方进行重定位的.比如这个记录的
    大小为16. 也就是两个重定位块,那么我们的重定位表的大小就是如下图所示:

下面则是新的重定位表.结构就是重定位表的结构,如果SzieofBlock大小为20个字节.那么重定位表大小就是20个自己.

第三个依次类推,重定位表的结束是不停的往下找,知道最后一个重定位表的结构成员你都为0

这样设计的原因:

  算术题解惑.

比如我们有地址 101234 101235 101236 这种修正的地址有10000个.

那么每个地址有4个字节的. 那么 4 * 10000 = 4万个字节. 也就是我们要准备一张4万个字节的表来保存重定位的.

但是我们发现一个规律.我们要修正的表的偏移都很近, 1234 1235 ....

那么我们可不可以这样那. 我们把 100000取出来. 两个字节存储1234 另外两个地址存储1235,不用准备四个字节了.小的偏移我们两个字节存储.这样的话我们的表的字节就会缩小一半.

VirtuallAddress 就是存储了 100000这个值,也就是需要 ""基址"" 公用的地址.

SizeofBlock 就是下面的偏移由多大, 我们要修正的偏移是 VirtualAddress + sizeofBlock下面的值.

如下图:

我们的重定位表,需要修正的基址是 0x11000,大小是54. 那么需要修正的偏移是 "36b0" "36bc" "36e0"....

我们基址 + 偏移就是要修正的位置.

偏移的概念:

重定位表,是按照一个物理页(4kb)进行存储的. 也就是一个4kb内存,有一个重定位块, 一个重定位表只管自己当前的物理页的重定位.

一个重定位表的记录偏移的大小是2个字节,也就是16位. 而记录偏移的大小. 是由 SizeofBlock决定的.

但是我们记录偏移的位置,12位就够了. 高4位.挪作他用. 并不是记录的才会修正偏移.只有高4位为3的时候.才会进行重定位(基址 + 偏移)

真正修复的位置 virtualaddress +  (高四位为3 ?  低12位偏移 : 无所谓的值.)

也就是高四位为3  Vir + 低12位偏移就等于真正要修复的RVA  例如 36b0 高位为3 低12位就是6b0  要修复的RVA = vir + 6b0  ,如果加上当前DLL的ImagebASE 才是真正要修复的虚拟地址 (VA) 我们计算出的是RVA

如果高位不为3,那么这个值是无所谓了.因为内存对齐的原因.

例如上图重定位表.  0x11000代表了当前要进行修复的块位置. 要修复偏移的地址第一个是36b0 . 高位为3是要进行修复.

所以低位为6B0. 所以修复的位置是 0x116b0的位置. 0x116b0 + 当前PE文件的ImageBase就是要进行重定位的位置

当前PE的Imagebase为0x400000  重定位地方为 0x4116b0位置.

我们第一个修正的位置是4116b0位置,从内存中.反汇编查看. 4116b0的位置的值是0x0041813c. 也就是说.这个位置的值.是我们需要重定位的. 也就是我们上面写的程序.为全局变量赋值的时候.全局变量的地址.需要进行更改.

  1.  而需要重定位的值. 则是 全局变量的RVA + Imagebase 填写到这里面了. 全局变量是在内存中的data节存储着.所以观看前几篇博客.能知道如何定位全局变量在文件的位置.

三丶总结重定位

    重定位表有两个成员. VirtuallAddress sizeofBlock

    1.virtualladdress 记录了当前物理页需要进行重定位的起始地址.

    2.sizeofBlock 记录了重定位表多大.去掉8个字节(重定位表大小) 下面都是记录了重定位表需要重定位的偏移.

    3.偏移是2个字节存储. 12位存储偏移. 高4位存储是否进行重定位. 高4位为3则需要进行重定位. virtuall + 低12位 就是要修正的 RVA偏移.

    

PE知识复习之PE的重定位表的更多相关文章

  1. PE知识复习之PE的绑定导入表

    PE知识复习之PE的绑定导入表 一丶简介 根据前几讲,我们已经熟悉了导入表结构.但是如果大家尝试过打印导入表的结构. INT IAT的时候. 会出现问题. PE在加载前 INT IAT表都指向一个名称 ...

  2. PE知识复习之PE文件空白区添加代码

    PE知识复习之PE文件空白区添加代码 一丶简介 根据上面所讲PE知识.我们已经可以实现我们的一点手段了.比如PE的入口点位置.改为我们的入口位置.并且填写我们的代码.这个就是空白区添加代码. 我们也可 ...

  3. PE知识复习之PE的导入表

    PE知识复习之PE的导入表 一丶简介 上一讲讲解了导出表. 也就是一个PE文件给别人使用的时候.导出的函数  函数的地址 函数名称 序号 等等. 一个进程是一组PE文件构成的.  PE文件需要依赖那些 ...

  4. PE知识复习之PE的导出表

    PE知识复习之PE的导出表 一丶简介 在说明PE导出表之前.我们要理解.一个PE可执行程序.是由一个文件组成的吗. 答案: 不是.是由很多PE文件组成.DLL也是PE文件.如果我们PE文件运行.那么就 ...

  5. PE知识复习之PE新增节

    PE知识复习之PE新增节 一丶为什么新增节.以及新增节的步骤 例如前几讲.我们的PE文件在空白区可以添加代码.但是这样是由一个弊端的.因为你的空白区节属性可能是只读的不能执行.如果你修改了属性.那么程 ...

  6. PE知识复习之PE的RVA与FOA的转换

    PE知识复习之PE的RVA与FOA的转换 一丶简介PE的两种状态 首先我们知道PE有两种状态.一种是内存展开.一种是在文件中的状态.那么此时我们有一个需求. 我们想改变一个全局变量的初始值.此时应该怎 ...

  7. PE知识复习之PE合并节

    PE知识复习之PE合并节 一丶简介 根据上一讲.我们为PE新增了一个节. 并且属性了各个成员中的相互配合. 例如文件头记录节个数.我们新增节就要修改这个个数. 那么现在我们要合并一个节.以上一讲我们例 ...

  8. PE知识复习之PE扩大节

    PE知识复习之PE扩大节 一丶为什么扩大节 上面我们讲了,空白区添加我们的代码.但是有的时候.我们的空白区不够了怎么办.所以需要进行扩大节. 扩大节其实很简单.修改节数据对齐后的大小即可. 并且在PE ...

  9. PE知识复习之PE的节表

    PE知识复习之PE的节表 一丶节表信息,PE两种状态.以及重要两个成员解析. 确定节表位置: DOS + NT头下面就是节表. 确定节表数量: 节表数量在文件头中存放着.可以准确知道节表有多少个. 节 ...

随机推荐

  1. CentOS下SVN服务的启动与关闭

    CentOS下SVN服务的启动与关闭 操作系统:CentOS 6.5  SVN版本:1.8.11 启动SVN服务:  svnserve -d -r /home/svn /home/svn 为版本库的根 ...

  2. javascript 数据类型 -- 分类

    一.概念 Javascript 中有6中基本类型(也称 原始类型/原始值): number . sring . boolean . symbol . undefined 和 null ,和1种引用类型 ...

  3. MQTT之Mosquitto

    https://mosquitto.org/ Eclipse Mosquitto是一个开源(EPL / EDL许可)消息代理,它实现了MQTT协议版本3.1和3.1.1.Mosquitto重量轻,适用 ...

  4. http 缓存学习.

    mark 一下 HTTP 缓存机制一二三 http://web.jobbole.com/92773/ 彻底弄懂HTTP缓存机制及原理 https://www.cnblogs.com/chenqf/p/ ...

  5. IaaS,PaaS和SaaS

    云计算的三种服务模式:IaaS,PaaS和SaaS IaaS: Infrastructure-as-a-Service(基础设施即服务)是第一层. PaaS: Platform-as-a-Servic ...

  6. Java面经

    转载:[Java面经]干货整理, Java面试题(覆盖Java基础,Java高级,JavaEE,数据库,设计模式等)   原文:http://www.cnblogs.com/wang-meng/p/5 ...

  7. java课程之团队开发冲刺阶段1.5

    一.总结昨天进度 1.昨天由于时间较少,没有太多的时间来进行学习Sqlite 二.遇到的困难 1.由于最终的程序需要调用本地的数据库,所以我们需要在安装程序的时候就需要直接附带安装一个本地的数据库到手 ...

  8. web测试实践——day01

    一.任务进展情况 主要是找寻网站的bug,分析bug的严重程度.同时找了本专业的同学进行博客园系统的使用. 二.存在的问题 由于上线的网站做的比较完善,导致找寻bug比较困难. 三.解决方法 对此我们 ...

  9. Ubuntu VIM下实现python自动缩进

    1.打开vimrc文件 sudo vi /usr/share/vim/vimrc 2.添加 set filetype=python au BufNewFile,BufRead *.py,*.pyw s ...

  10. Three.js学习笔记02

    1.改变相机的位置,让物体移动 通过下面的代码改变相机的位置: camera.position.x =camera.position.x +1; 将相机不断的沿着x轴移动1个单位,也就是相机向右移动. ...