前面两篇 PE文件结构详解(四)PE导入表 和 PE文件结构详解(五)延迟导入表 介绍了PE文件中比较常用的两种导入方式,不知道大家有没有注意到,在调用导入函数时系统生成的代码是像下面这样的:

在这里,IE的iexplorer.exe导入了Kernel32.dll的GetCommandLineA函数,可以看到这是个间接call,00401004这个地址的内存里保存了目的地址,
根据图中显示的符号信息可知,00401004这个地址是存在于iexplorer.exe模块中的,实际上也就是一项IAT的地址。这个是IE6的
exe中的例子,当然在dll中如果导入其他dll中的函数,结果也是一样的。这样就有一个问题,代码里call的地址是一个模块内的地址,而且是一个
VA,那么如果模块基地址发生了变化,这个地址岂不是就无效了?这个问题如何解决?

答案是:Windows使用重定位机制保证以上代码无论模块加载到哪个基址都能正确被调用。听起来很神奇,是怎么做到的呢?其实原理并不很复杂,这个过程分三步:

1.编译的时候由编译器识别出哪些项使用了模块内的直接VA,比如push一个全局变量、函数地址,这些指令的操作数在模块加载的时候就需要被重定位。

2.链接器生成PE文件的时候将编译器识别的重定位的项纪录在一张表里,这张表就是重定位表,保存在DataDirectory中,序号是 IMAGE_DIRECTORY_ENTRY_BASERELOC。

3.PE文件加载时,PE 加载器分析重定位表,将其中每一项按照现在的模块基址进行重定位。

以上三步,前两部涉及到了编译和链接的知识,跟本文的关系不大,我们直接看第三步,这一步符合本系列的特征。

在查看重定位表的定义前,我们先了解一下他的存储方式,有助于后面的理解。按照常规思路,每个重定位项应该是一个DWORD,里面保存需要重定位的RVA,这样只需要简单操作便能找到需要重定位的项。然而,Windows并没有这样设计,
原因是这样存放太占用空间了,试想一下,加入一个文件有n个重定位项,那么就需要占用4*n个字节。所以Windows采用了分组的方式,按照重定位项所在的页面分组,每组保存一个页面起始地址的RVA,页内的每项重定位项使用一个WORD保存重定位项在页内的偏移,这样就大大缩小了重定位表的大小。

有了上面的概念,我们现在可以来看一下基址重定位表的定义了:

  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:页起始地址RVA。

SizeOfBlock:表示该分组保存了几项重定位项。

TypeOffset:这个域有两个含义,大家都知道,页内偏移用12位就可以表示,剩下的高4位用来表示重定位的类型。而事实上,Windows只用了一种类型IMAGE_REL_BASED_HIGHLOW,数值是3。

好了,有了以上知识,相信大家可以很容易的写出自己修正重定位表的代码,不如自己做个练习验证一下吧。

本文 by evil.eagle 转载的时候请注明出处。http://blog.csdn.net/evileagle/article/details/12886949

最后,还是总结一下,哪些项目需要被重定位呢?

1.代码中使用全局变量的指令,因为全局变量一定是模块内的地址,而且使用全局变量的语句在编译后会产生一条引用全局变量基地址的指令。

2.将模块函数指针赋值给变量或作为参数传递,因为赋值或传递参数是会产生mov和push指令,这些指令需要直接地址。

3.C++中的构造函数和析构函数赋值虚函数表指针,虚函数表中的每一项本身就是重定位项,为什么呢?大家自己考虑一下吧,不难哦~

PE文件结构详解(六)重定位的更多相关文章

  1. PE文件结构详解(五)延迟导入表

    PE文件结构详解(四)PE导入表讲 了一般的PE导入表,这次我们来看一下另外一种导入表:延迟导入(Delay Import).看名字就知道,这种导入机制导入其他DLL的时机比较“迟”,为什么要迟呢?因 ...

  2. PE文件结构详解(四)PE导入表

    PE文件结构详解(二)可执行文件头的最后展示了一个数组,PE文件结构详解(三)PE导出表中解释了其中第一项的格式,本篇文章来揭示这个数组中的第二项:IMAGE_DIRECTORY_ENTRY_IMPO ...

  3. PE文件结构详解(三)PE导出表

    上篇文章 PE文件结构详解(二)可执行文件头 的结尾出现了一个大数组,这个数组中的每一项都是一个特定的结构,通过函数获取数组中的项可以用RtlImageDirectoryEntryToData函数,D ...

  4. PE文件结构详解(二)可执行文件头

    在PE文件结构详解(一)基本概念里,解释了一些PE文件的一些基本概念,从这篇开始,将详细讲解PE文件中的重要结构. 了解一个文件的格式,最应该首先了解的就是这个文件的文件头的含义,因为几乎所有的文件格 ...

  5. PE文件结构详解(一)基本概念

    PE(Portable Execute) 文件是Windows下可执行文件的总称,常见的有DLL,EXE,OCX,SYS等,事实上,一个文件是否是PE文件与其扩展名无关,PE文件可以是任 何扩展名.那 ...

  6. PE文件结构详解

    (注:最左边是文件头的偏移量.) IMAGE_DOS_HEADER STRUCT { +0h WORD e_magic // Magic DOS signature MZ(4Dh 5Ah) DOS可执 ...

  7. PE文件结构详解(三)

    0x01 前言 上一篇讲到了数据目录表的结构和怎找到到数据目录表(DataDirectory[16]),这篇我们我来讲讲数据目录表后面的另一个结构——区块表. 0x01 区块 区块就是PE载入器将PE ...

  8. PE文件详解(六)

    这篇文章转载自小甲鱼的PE文件详解系列原文传送门 之前简单提了一下节表和数据目录表,那么他们有什么区别? 其实这些东西都是人为规定的,一个数据在文件中或者在内存中的位置基本是固定的,通过数据目录表进行 ...

  9. PE文件详解(八)

    本文转载自小甲鱼PE文件详解系列教程原文传送门 当应用程序需要调用DLL中的函数时,会由系统将DLL中的函数映射到程序的虚拟内存中,dll中本身没有自己的栈,它是借用的应用程序的栈,这样当dll中出现 ...

随机推荐

  1. OC10_代理反向传值

    // // ProtectedDelegate.h // OC10_代理反向传值 // // Created by zhangxueming on 15/6/24. // Copyright (c) ...

  2. hdu 1284 钱币兑换问题 完全背包

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1284 递推公式:dp[i] = sum(dp[i], dp[i-C]) /* 钱币兑换问题 Time ...

  3. 一致性哈希(consistent hashing)算法

    文章同步发表在博主的网站朗度云,传输门:http://www.wolfbe.com/detail/201608/341.html 1.背景        我们都知道memcached服务器是不提供分布 ...

  4. 用户不在sudoers文件中的解决方法

    1.更改/etc/sudoers权限为777 2.修改文件中 root    ALL=(ALL)       ALL 下方增加 user    ALL=(ALL)       ALL 3.回复文件/e ...

  5. 【转】让iframe在iOS设备手机浏览器上支持滚动

    HTML代码 在使用IFRAME或者其他HTML元素时,你需要使用一个元素(如DIV)来包装他们: <div class="scroll-wrapper"> <i ...

  6. IOS_问题: Xcode8 安装KSImageName插件, 编代码就崩了

    Xcode 8之后, KSImageName插件就不能用了,如果安装了,就会导致一写英文代码Xcode 就崩了. 解决方法: 把这个插件删除,重启了一下xcode就可以了, 如果重启没用, 可以尝试下 ...

  7. mongodb的常用操作

    对于nosql之前工作中有用到bekerlydb,最近开始了解mongodb,先简单写下mongodb的一些常用操作,当是个总结: 1.mongodb使用数据库(database)和集合(collec ...

  8. linux lsof命令的使用

    lsof(list open files)是一个列出当前系统打开文件的工具.在UNIX环境下,任何事物都是以文件的形式存在的,通过文件不仅仅可以访问常规数据,还可以访问网络连接和硬件. 像传输协议(T ...

  9. Fedora9下解决无ifconfig指令

    问题:在VM6.5上装了Fedora9,但是当输入ifconfig指令的时候,提示不存在. 原因:PATH环境变量设置不对,少了几个目录:/sbin:/usr/sbin:/usr/local/sbin ...

  10. Python计算斗牛游戏的概率

    Python计算斗牛游戏的概率 过年回家,都会约上亲朋好友聚聚会,会上经常会打麻将,斗地主,斗牛.在这些游戏中,斗牛是最受欢迎的,因为可以很多人一起玩,而且没有技术含量,都是看运气(专业术语是概率). ...