PE格式第七讲,重定位表

作者:IBinary
出处:http://www.cnblogs.com/iBinary/
版权所有,欢迎保留原文链接进行转载:)

一丶何为重定位(注意,不是重定位表格)

首先,我们先看一段代码,比如调用Printf函数,使用OD查看.

那么大家有没有想过这么一个问题,函数的字符串偏移是00407030位置,函数Call的地址是00401020的位置

但是如果模块首地址申请不到了,变为了00100000的位置,那么此时的偏移是不是都是错的了?

首先说下,一般重定位表格都是DLL中的,因为满足不了模块首地址的需求,所以会遇到函数的重定位问题.

那么如果磨坏地址变为了00100000的位置,那么对应的字符串位置是不是也要变为00107030的位置,而Call的地址,是不是也要变为00101020的位置

那么这个就叫做重定位,我们要把偏移,以及各种需要修正的位置,变为正确的.

二丶重定位表格如何设计?

首先我们自己先想一下,重定位的表格要如何设计?

我猜想,你要保存模块的地址  ,修改地址,偏移, 以及大小.

新的模块 ImageBase

旧的模块 iMageBase

修改的地址

偏移

修改的大小

那么如果这样设计会不会出现问题?

会出现很多问题,比如占得字节太多了,如果是Kerner32.dll里面都是这样设计,那么得要多少内存.

那么进一步的优化

可不可以一个分页,保存修改的偏移,以及长度

分页: page  (DWORD) 占4个字节

大小: size (DWORD)     偏移:offset(DWORD)

表格设计为上面的,

感觉这样可以了.但是感觉还可以进一步的优化,大小,以及偏移都占4个字节,是不是浪费了

而且如果记录一个分页中的重定位的数据,那么偏移是不会超过12位的(二进制12位,转为10进制是1024),  那么如果一个DWORD存储文件偏移,那么高4位是没有用的.

而且我们发现,大小也是很占位置的.大小一个字节就可以表示了,比如0 做对齐使用,1修改高16位的偏移,2修改低16位的偏移,3修改4个字节大小

那么是不是可以合并了

page  (DWORD)

sizeofoffset

0x3005    代表的意思就是看高位,3代表我要修改4个字节,005代表修改的当前页的偏移位置.

三丶真正的重定位表格

看下重定位表格的真正的结构体吧.

代码:

typedef struct _IMAGE_BASE_RELOCATION {
DWORD VirtualAddress;            页存储的RVA
DWORD SizeOfBlock;              word类型数组的个数,也就是下面注释的
// WORD TypeOffset[1];
} IMAGE_BASE_RELOCATION;
typedef IMAGE_BASE_RELOCATION UNALIGNED * PIMAGE_BASE_RELOCATION;

那么看看是不是和我们猜想的一样,我们随便找个DLL,在数据目录中定位重定位表格

1.寻找数据目录RVA偏移

我们首先要找到数据目录中重定位表格的RVA偏移然后判断属于哪个节,通过公式转化,得到在文件中的实际偏移位置.

得出RVA = 6000h

2.判断属于哪个节

我们发现,新增加了一个节,这个节就是重定位的节然后虚拟地址是6000位置,而且在文件偏移的位置也是6000h

那么我们就得出 FA = RVA了,那么就不用算了,可以确定,文件偏移位置就是6000就是重定位表的位置

3.定位文件偏移处,查看排列

然后可以看出 前八个字节分别保存页的RVA偏移,以及大小,.我们使用计算器计算一下,看看有多大

计算的出 160h,这个大小,保存的是数组大小+上我们八个字节的总大小,也就是说160 - 8 = 数组的大小了.

可以看出确实是怎么大,然后就到记录下一个分页了.

四丶数组解析查看

那么按照我们的想法看上面重定位表中的数组的第一个,按照小尾方式读取则是

0x3005  那么高位是3那么就是要修改大小是4个字节,005则是代表偏移.

至于高位怎么查看,VC++6.0中的宏已经定义了.

代码:

#define IMAGE_REL_I386_ABSOLUTE         0x0000  // Reference is absolute, no relocation is necessary
#define IMAGE_REL_I386_DIR16 0x0001 // Direct 16-bit reference to the symbols virtual address
#define IMAGE_REL_I386_REL16 0x0002 // PC-relative 16-bit reference to the symbols virtual address
#define IMAGE_REL_I386_DIR32 0x0006 // Direct 32-bit reference to the symbols virtual address
#define IMAGE_REL_I386_DIR32NB 0x0007 // Direct 32-bit reference to the symbols virtual address, base not included
#define IMAGE_REL_I386_SEG12 0x0009 // Direct 16-bit reference to the segment-selector bits of a 32-bit virtual address
#define IMAGE_REL_I386_SECTION 0x000A
#define IMAGE_REL_I386_SECREL 0x000B
#define IMAGE_REL_I386_REL32 0x0014 // PC-relative 32-bit reference to the symbols virtual address

这里只需要知道0 1 2 代表的意思即可,因为0x3005的高位是 用位运算 | 上去的,所以3代表的是1 和 2的组合

0  对齐使用

1.修改高16位

2.修改低16位

1和2 使用位运算|起来就是修改4个字节.

1.定位修改位置

那么怎么定位要修改的位置那?

公式:

现在的ImageBase(模块地址) +  当前分页大小的虚拟地址 +5的位置等于要修改的位置:

比如假设我们的现在的模块地址是00400000位置,而DLL以前的位置是10000000  而它以前的字符串的偏移是   10003045

首先定位修改地址:

00400000 + 1000 + 005 = 401005  那么在401005的位置就是你要修改的位置

比如我们在写一个

0x3096 =  400000 + 1000 + 96 = 401096  那么定位的位置就是401096是你要修改的偏移,大小是4个字节,高位为3  为什么是4个字节,一会看下内部存储

2.修改的偏移计算

比如我们调用一个printf

push 10003096    "HelloWorld"

call    10004086

那么我们要修正他的偏移

我们现在得知,以前的DLL偏移是  10000000    以前的字符串偏移是  10003096 ,不过因为DLL的模块地址没有满足,那么现在的模块地址变为了00400000的位置

那么我们要修正偏移

公式:

现在的ImageBase (00400000) - 以前的ImageBase(10000000) + 以前的偏移(10003096)

这样写汇编代码好写,如果便于理解的话,可以写成下面那样,只不过你需要知道的是汇编代码就是上面这种写法就行

以前的偏移(10003096)  - 以前的ImageBase(10000000) + 现在的ImageBase(00400000)

= 3096 + 400000

= 403096  (计算出来的偏移)

那么push的位置就成了 403096了,已经重定位了.

五丶实战演练查看

因为DLL中的重定位表中的项太多,所以这里使用一个EXE(没有导出函数的EXE),然后注入这个DLL,那么这个EXE就有重定位表格了.

首先我们先看DLL, 3005的位置要重定位

按照公式我们得出,要修改的位置是

现在模块地址 + 当前表中记录分页 + 数组中后三位的偏移(上面说过,如果按照分页存储,那么3位就可以表达一个分页需要记录的了)

那么现在  我们的EXE的模块地址是00500000 + 1000(重定位表中第一项成员) + 005  (这是一个数组,第一个成员是0x3005  取出后三位则是005)

得出修改的位置是  00501005的位置,我们OD中CTRL+ G看看这个位置是不是要修正.

代码乱了,那么我们可能断掉指令了,那么此时CTRL + A重新分析一下.

可以看出,我们修正的位置是501005的位置,不过汇编代码在501004才能显示出来,501005后面正好是要修正的地址,那么只需要计算偏移填进去就可以了,大小是按照高4个字节, 现在0x3005 高位是3那么代表了要修正4个字节的偏移.

算出偏移位置:

偏移位置我们要进行反推了

因为OD已经帮我们重定位好了.

503000 = 现在的ImageBase - 以前的ImageBase + 以前的偏移 = 现在的偏移(503000)

那么现在计算以前的偏移

以前的偏移 = 现在的偏移 - 现在的ImageBase + 以前的ImageBase

=  503000 - 50000 + 60000000

= 3000 + 60000000

= 60003000 (以前的偏移)

那么算出了以前的偏移,我们就计算这4个字节要填写的偏移,也就是503000怎么得出来的

公式上面说了:

Cur (缩写,代表当前的意思)  Old(代表旧的意思)  offset(代表偏移的意思)

CurImageBase - OldImageBase + OldOffset = 要填入的偏移

代入公式:

00500000  -  60000000  + 60030000 = 00503000 (要填写的文件偏移)

看下我们当前的模块地址:

Inject是我们当前的EXE的名称,模块地址在00500000的位置

DLL的模块地址是60000000  这个地址是我们通过修改DLL中的选项头中的ImageBase得到的.

六丶总结

上面讲的很细致

今天主要就是结构体会看,偏移会算即可.

总结一下公式

1.定位重定位的地址  (也就是在哪里修改)

首先从数组取出一项,(2个字节大小)

比如0x3005

公式:

定位修改地址  = 现在模块 + 当前结构记录分页的RVA  + 取出数组的2个字节的低3位

例子: 00401000 + 1000 + 005 = 世纪你要修改的地址,修改大小和取出word自己的第一位有关

2.计算出偏移地址,填写到定位地址的位置,使其偏移正确

现在的模块地址  - DLL模块地址 + 以前的偏移 = 实际修改的偏移

便于理解的公式:

以前的偏移 - DLL模块地址 + 现在模块地址

3.计算出以前偏移

要计算出以前的偏移,你首先要得出现在的偏移,好在OD已经写好了,其实文件中也有存储的.(自己找吧)

以前的偏移 = 现在的偏移 - 现在模块地址 + DLL模块地址

作者:IBinary
出处:http://www.cnblogs.com/iBinary/
版权所有,欢迎保留原文链接进行转载:)

PE格式第七讲,重定位表的更多相关文章

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

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

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

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

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

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

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

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

  5. PE格式第四讲,数据目录表之导入表,以及IAT表

    PE格式第四讲,数据目录表之导入表,以及IAT表 一丶IAT(地址表) 首先我们思考一个问题,程序加载的时候会调用API,比如我们以前写的标准PE 那么他到底是怎么去调用的? 他会Call 下边的Jm ...

  6. PE格式第八讲,TLS表(线程局部存储)

    PE格式第八讲,TLS表(线程局部存储) 作者:IBinary出处:http://www.cnblogs.com/iBinary/版权所有,欢迎保留原文链接进行转载:) 一丶复习线程相关知识 首先讲解 ...

  7. PE结构之重定位表

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

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

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

  9. PE文件 03 重定位表

    0x01  重定位表结构   重定位表是由数据目录表中的第六个成员指出的: typedef struct _IMAGE_DATA_DIRECTORY { DWORD VirtualAddress; D ...

随机推荐

  1. 201521123004《Java程序设计》第5周学习总结

    1. 本周学习总结 1.1 尝试使用思维导图总结有关多态与接口的知识点. 1.2 可选:使用常规方法总结其他上课内容. 接口 接口(interface)就是方法声明和常量值的集合 实现接口的类叫接口的 ...

  2. 201521123053《Java程序设计》第四周总结

    1. 本周学习总结 1.1 尝试使用思维导图总结有关继承的知识点. 1.2 使用常规方法总结其他上课内容. 现在上课跟着老师的思路走,一般都能理解了.就是课上知识点有些难以记住. 特别讲讲这个思维导图 ...

  3. 201521123025 《Java程序设计》第2周学习总结

    1. 本章学习总结 一些注意: (1)在JAVA中,不加后缀的浮点数被默认为double型,如果要用float型就要在数据后加上f或F后缀,如float a=32.6f(正确);float a=32. ...

  4. 静态include与动态include的区别

    jsp中的include有两种形式,分别是:<%@ include file=""%><jsp:include page="" flush=& ...

  5. 201521123088《Java程序设计》第13周学习总结

    1.本周学习总结 2.书面作业 1. 网络基础1.1 比较ping www.baidu.com与ping cec.jmu.edu.cn,分析返回结果有何不同?为什么会有这样的不同? ping cec. ...

  6. 201521123055 《Java程序设计》第13周学习总结

    1. 本章学习总结 2. 书面作业 1. 网络基础 1.1 比较ping www.baidu.com与ping cec.jmu.edu.cn,分析返回结果有何不同?为什么会有这样的不同? 1.2 te ...

  7. 201521123090《Java程序设计》第10周学习总结

    本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结异常与多线程相关内容. 书面作业 本次PTA作业题集异常.多线程 finally 题目4-2 1.1 截图你的提交结果(出现学号) 1.2 ...

  8. 201521123102 《Java程序设计》第12周学习总结

    1.本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结多流与文件相关内容. 2.书面作业 将Student对象(属性:int id, String name,int age,double ...

  9. lintcode.44 最小子数组

    最小子数组   描述 笔记 数据 评测 给定一个整数数组,找到一个具有最小和的子数组.返回其最小和. 注意事项 子数组最少包含一个数字 您在真实的面试中是否遇到过这个题? Yes 哪家公司问你的这个题 ...

  10. [07] ServletContext上下文对象

    1.上下文的概念 我们在说到Servlet的继承关系时,提到自定义Servlet实际上间接实现了Servlet和ServletConfig两个接口,其中ServletConfig接口中定义了一个方法叫 ...