PE格式第七讲,重定位表
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格式第七讲,重定位表的更多相关文章
- WindowsPE权威指南-PE文件头中的重定位表
PE加载的过程 任何一个EXE程序会被分配4GB的内存空间,用户层处理低2G的内存,驱动处理高2G的内存. 1.双击EXE程序,操作系统开辟一个4GB的空间. 2.从ImageBase决定了加载后的基 ...
- Windows PE第6章 栈与重定位表
第六章 栈与重定位表 本章主要介绍栈和代码重定位.站和重定位表两者并没有必然的联系,但都和代码有关.栈描述的是代码运行过程中,操作系统为调度程序之间相互调用关系,或临时存放操作数而设置的一种数据结构. ...
- Reverse Core 第二部分 - 16&17章 - 基址重定位表&.reloc节区
第16-17章 - 基址重定位表&.reloc节区 @date: 2016/11/31 @author: dlive 0x00 前言 这几天忙着挖邮箱漏洞,吃火锅,马上要被关禁闭,看书进度比较 ...
- 基址重定位表&.reloc节区
第16-17章 - 基址重定位表&.reloc节区 @date: 2016/11/31 @author: dlive 0x01 PE重定位 若加载的是DLL.SYS文件,且在ImageBase ...
- PE格式第四讲,数据目录表之导入表,以及IAT表
PE格式第四讲,数据目录表之导入表,以及IAT表 一丶IAT(地址表) 首先我们思考一个问题,程序加载的时候会调用API,比如我们以前写的标准PE 那么他到底是怎么去调用的? 他会Call 下边的Jm ...
- PE格式第八讲,TLS表(线程局部存储)
PE格式第八讲,TLS表(线程局部存储) 作者:IBinary出处:http://www.cnblogs.com/iBinary/版权所有,欢迎保留原文链接进行转载:) 一丶复习线程相关知识 首先讲解 ...
- PE结构之重定位表
什么是重定位: 重定位就是你本来这个程序理论上要占据这个地址,但是由于某种原因,这个地址现在不能让你占用,你必须转移到别的地址,这就需要基址重定位.你可能会问,不是说过每个进程都有自己独立的虚拟地址空 ...
- PE知识复习之PE的重定位表
PE知识复习之PE的重定位表 一丶何为重定位 重定位的意思就是修正偏移的意思. 如一个地址位 0x401234 ,Imagebase = 0x400000 . 那么RVA就是 1234. 如果Im ...
- PE文件 03 重定位表
0x01 重定位表结构 重定位表是由数据目录表中的第六个成员指出的: typedef struct _IMAGE_DATA_DIRECTORY { DWORD VirtualAddress; D ...
随机推荐
- Git和Github使用
什么是Git? Git 是一个快速.可扩展的分布式版本控制系统,它具有极为丰富的命令集,对内部系统提供了高级操作和完全访问. 版本控制 简单地说,就是将在本地开发的代码,定时推送到服务器.每一次修改, ...
- 201521123082 《Java程序设计》第12周学习总结
201521123082 <Java程序设计>第12周学习总结 标签(空格分隔): java 1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结多流与文件相关内容. An ...
- 201521123042 《Java程序设计》第3周学习总结
1. 本周学习总结 初学面向对象,会学习到很多碎片化的概念与知识.尝试学会使用思维导图将这些碎片化的概念.知识组织起来.请使用纸笔或者下面的工具画出本周学习到的知识点.截图或者拍照上传. 2. 书面作 ...
- Rabbitmq集群安装配置
Rabbitmq集群安装与配置 一.rabbitmq安装环境准备 1.安装环境准备 这里,我们以两个节点为例进行安装,一个节点为内存节点,另一个节点为硬盘节点,具体可根据自己需要分配节点. 安装系统 ...
- 懒人小工具:自动生成Model,Insert,Select,Delete以及导出Excel的方法
在开发的过程中,我们为了节约时间,往往会将大量重复机械的代码封装,考虑代码的复用性,这样我们可以节约很多时间来做别的事情.最近跳槽到一节webform开发的公司,主要是开发自己公司用的ERP.开始因为 ...
- POJ-2299 Ultra-QuickSort (树状数组,离散化,C++)
Problem Description In this problem, you have to analyze a particular sorting algorithm. The algorit ...
- Hibernate的DetachedCriteria使用(含Criteria)
1.背景了解:Hibernate的三种查询方式 Hibernate总的来说共有三种查询方式:HQL.QBC和SQL三种,这里做简单的概念介绍,不详细进行展开. 1.1 HQL(Hibernate Qu ...
- JS中如何巧妙的用事件委托
常见场景:页面有多个相同的按钮需要绑定同样的事件逻辑. 如下HTML,实现:点击每个按钮,当它的 data-id不为null的时候输出它的data-id(实际业务中会有更复杂的逻辑) <ul i ...
- web自动化1-selenium简介及环境搭建
selenium 开源软件 支持多浏览器Firefox.Chrome.IE 跨平台Windows.Mac.Linux 多语言 java python Ruby php js 对web支持好,多种API ...
- Java 使用Axis实现WebService实例
在上一篇WebService实例中,基于jdk1.6以上的javax.jws 发布webservice接口.这篇博文则主要用eclipse/myeclipse 使用axis插件进行发布和调用WebSe ...