原文发表于百度空间,2008-11-02
==========================================================================

先定义一下用到的几个变量:
char *hModule=NULL;//映射后的基址
PIMAGE_OPTIONAL_HEADER pOptHeader;//扩展头
PIMAGE_DATA_DIRECTORY pRelocTable=NULL;//指向重定位表
PIMAGE_BASE_RELOCATION pRelocBlock;//指向重定位块
WORD *pRelocData;//16位的重定位数据指针
PE头的定位和分析比较简单,不再多说。
首先,先判断重定位表是否存在:
pRelocTable=&(pOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC]);
判断pRelocTable->VirtualAddress和pRelocTable->Size是否为0即可。
若不为0,则重定位表存在。

ModulBase+pRelocTable->VirualAddress即可定位到重定位表。
重定位表的结构如下图所示:

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

每个块的首部是如下定义:
typedef struct _IMAGE_BASE_RELOCATION {
    DWORD   VirtualAddress;
    DWORD   SizeOfBlock;
} IMAGE_BASE_RELOCATION;

把内存中需要重定位的数据按页的大小0x1000分为若干个块,而这个VirtualAddress就是每个块的起始RVA.只知道块的RVA当然还不行,我们要知道每一个需要重定位数据的具体地址。
每个需重定位的数据其地址及定位方式用两个字节来表示,记为RelocData,紧跟在IMAGE_BASE_RELOCATION结构之后,如图所示。
每个块中重定位信息的个数如何确定?
这个可由每个块结构中的Size来确定。Size的值是以DWORD表示的当前整个块的大小,先减去IMAGE_BASE_RELOCATION的大小,因为重定位数据是16位WORD的,再除以2,就得到个重定位数据的个数。由Size可以直接到达下一个重定位块,如图所示:0x5E850000+0x000000EC=0x5E8500EC即为第二个重定位块的地址,直至某个块首结构的VirtualAddress为0,表明重定位表结束。

每个块中重定位数据的个数确定了,如何得知具体每个需进行重定位的数据的地址呢?

每个16位重定位信息包括低12位的重定位位置和高4位的重定位类型。要得到重定位的RVA,IMAGE_BASE_RELOCATION'的'VirtualAddress'需要加上12位位置偏移量. 类型是下列之一:

    IMAGE_REL_BASED_ABSOLUTE () 使块按照32位对齐,位置为0。
IMAGE_REL_BASED_HIGH () 高16位必须应用于偏移量所指高字16位。
IMAGE_REL_BASED_LOW () 低16位必须应用于偏移量所指低字16位。
IMAGE_REL_BASED_HIGHLOW () 全部32位应用于所有32位。.
IMAGE_REL_BASED_HIGHADJ () 需要32位,高16位位于偏移量,低16位位于下一个偏移量数组元素,组合为一个带符号数,加上32位的一个数,然后加上8000然后把高16位保存在偏移量的16位域内。
IMAGE_REL_BASED_MIPS_JMPADDR () Unknown
IMAGE_REL_BASED_SECTION () Unknown
IMAGE_REL_BASED_REL32 () Unknown

以第一个重定位数据0x34AC为例,其高四位表明了重定位类型为3,即IMAGE_REL_BASED_HIGHLOW,Win32环境下的重定位基本都是这个类型的。

其低12位则表明了相对于VirtualAddress的RVA偏移量。VirtualAddress即需重定位的数据块的起始RVA,再加上这低12位的值就得到了具体的需要进行重定位处理的数据的RVA。感觉说得有点乱,总之就是VirtualAddress与每一个16位重定位数据一起可以得到一个具体要进行重定位处理的数据的RVA。

也就是说:
要进行重定位处理的数据的RVA=VirtualAddress+RelocData&0x0FFF 
=0x00001000+(0x34AC)&0x0FFF
=0x000014AC

再加上模块基址,就得到了在内存中的真实地址了
由ModuleBase=0x5E830000,可得这个重定位数据的地址为:0x5E830000+0x000014AC=0x5E8314AC
转到OD的反汇编窗口,Ctrl+G跳到这个地址,可以看到:

OD自动标上了下划线,表明这是一个重定位数据,接下来的几个数据也可以一一进行对应.
至此,重定位算是搞明白了。

那如何进行修正呢?
把需要修正的数据减去IMAGE_OPTINAL_HEADER中的ImageBase,再加上当前加载的实际基址,就可以了。至此重定位完成!当然,也可以根据别的基址进行重定位。比如加载ntoskrnl.exe时,按照ntoskrnl.exe在内存中加载的实际基址0x804E0000(我系统上的数据)进行重定位之后,然后就可以干很多事情了~~比如查找原始SSDT,或者进行 InlineHook检测,搜索未导出函数等等,总之比较有用。
下面是我程序中的一段代码:

pRelocBlock=(PIMAGE_BASE_RELOCATION)(m_hModule + m_pRelocTable->VirtualAddress);
//printf("After Loaded,Reloc Table=0x%08X\n",pRelocBlock);
do
{ //处理一个接一个的重定位块,最后一个重定位块以RAV=0结束
//需要重定位的个数,是本块的大小减去块头的大小,结果是以DWORD表示的大小
//而重定位数据是16位的,那就得除以2
int numofReloc=(pRelocBlock->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION))/;
//printf("Reloc Data num=%d\n",numofReloc);
//重定位数据是16位的
WORD offset=;
WORD *pRelocData = (WORD*)((char*)pRelocBlock + sizeof(IMAGE_BASE_RELOCATION));
for (i=;i<numofReloc;i++)//循环,或直接判断*pData是否为0也可以作为结束标记
{
DWORD *RelocAddress=;//需要重定位的地址 //重定位的高4位是重定位类型,
if (((*pRelocData)>>) == IMAGE_REL_BASED_HIGHLOW)//判断重定位类型是否为IMAGE_REL_BASED_HIGHLOW
{ //计算需要进行重定位的地址 //重定位数据的低12位再加上本重定位块头的RAV即真正需要重定位的数据的RAV
minioffset=(*pRelocData)&0xFFF;//小偏移 //模块基址+重定位基址+每个数据表示的小偏移量
RelocAddress=(DWORD*)(hModule + pRelocBlock->VirtualAddress+offset); //对需要重定位的数据进行修正
//修正方法:减去IMAGE_OPTINAL_HEADER中的基址,再加上实际基址即可
*RelocAddress=*RelocAddress - pOptHeader->ImageBase + hModule;
}
//指向下一个重定位数据
pRelocData++;
}
//指向下一个重定位块
pRelocBlock=(PIMAGE_BASE_RELOCATION)((char*)pRelocBlock + pRelocBlock->SizeOfBlock);
}while (pRelocBlock->VirtualAddress);

这些工作只是自己加载PE过程的一部分,自己加载PE有很多用处,主要是因为加载的是原始的文件,只要不是固化挂钩,都可以自己加载然后与内存中的进行对比,用处还是不少的~

参考:
1.sudami的《SDT Restore v0.2 学习手记》。不过那个源码中用了太多自定义的结构,使得读起来稍有些困难,其实这些结构都是有现成定义的。
2.看雪论坛的《PE文件格式》

【旧文章搬运】PE重定位表学习手记的更多相关文章

  1. 逆向-PE重定位表

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

  2. Windows PE 重定位表编程(枚举重定位地址)

    原理之前单独总结过,在这里: http://blog.csdn.net/u013761036/article/details/54051347 下面是枚举重定位信息的代码: // ReLocation ...

  3. 【旧文章搬运】Windows句柄表分配算法分析(一)

    原文发表于百度空间,2009-03-30========================================================================== 阅读提示: ...

  4. 【旧文章搬运】Windows句柄表格式

    原文发表于百度空间,2009-02-28========================================================================== 句柄是Wi ...

  5. 【旧文章搬运】Windows句柄表分配算法分析(实验部分)

    原文发表于百度空间,2009-03-31========================================================================== 理论结合实 ...

  6. 【旧文章搬运】Windows句柄表分配算法分析(三)

    原文发表于百度空间,2009-03-30========================================================================== 三.当需要 ...

  7. 【旧文章搬运】Windows句柄表分配算法分析(二)

    原文发表于百度空间,2009-03-30========================================================================== 四.句柄表 ...

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

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

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

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

随机推荐

  1. 发布ios应用程序

    详见文档 AppDistributionGuide Submit and Release Your App 首先,需要登入itunes connect并且输入必要的信息更改app状态为 waiting ...

  2. 【Todo】ES6学习

    今天部分分享,有一篇PPT,放在这里了 /Users/baidu/Documents/Data/Work/分享资料/ES6大法好.pptx 内容挺丰富的,可以学习.

  3. HDU 4791 Alice&#39;s Print Service 水二分

    点击打开链接 Alice's Print Service Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K ( ...

  4. spring MVC使用Interceptor做用户登录判断

    在任何一个项目中,我们必须要用到的就是用户登录,那么就少不了用户是否登录的判断,如果我们每一个请求都要去做一次判断,那么就会变得很麻烦,但我们复制粘贴的时候我们就要考虑我们的代码写的是不是有问题,是不 ...

  5. 【转载】VS工具使用——代码图

    代码图:     心想,反正也调不出来,就试试这个东西吧,一打开,就认识到自己发现了一个新大陆:这个代码图可以让我们对一个工程文件有大体的了解,即函数的调用关系等.它是一个VS2013自带工具生成函数 ...

  6. 用NHibernate处理带属性的多对多关系

    1.引言 老谭在面试开发者的时候,为了考察他们的数据库开发能力,经常祭出我的法宝,就是大学数据库教程中讲到的一个模式:学生选课.这个模式是这种: 在这个模式中,学生(Student)和课程(Cours ...

  7. 项目Alpha冲刺(团队9/10)

    项目Alpha冲刺(团队9/10) 团队名称: 云打印 作业要求: 项目Alpha冲刺(团队) 作业目标: 完成项目Alpha版本 团队队员 队员学号 队员姓名 个人博客地址 备注 221600412 ...

  8. (转)OutOfMemory时抓取heap 快照

    转自:https://testerhome.com/topics/579 首先说一下,在程序没有崩溃的时候如何抓取heap快照.这个大家应该都知道,在ddms中自带此功能.   见上图首先我们选中一个 ...

  9. python day- 5 字典(dic)的 增删改查 及 操作方法

    字典(dic) 1.定义及格式 用{ }大括号括起来的,由key:value 来保存数据的就是 字典(dic) eg:dic = {"及时雨" : "宋江" , ...

  10. 正则_action

    http://wiki.ubuntu.org.cn/index.php?title=Python%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F%E6%93% ...