PE文件结构(五)
参考
书:《加密与解密》
视频:小甲鱼 解密系列 视频
链接器生成一个PE文件时,它会假设程序被装入时使用的默认ImageBase基地址(VC默认exe基地址00400000h,dll基地址10000000h),并且会把代码中所有指令中用到的地址都使用默认的基地址(例如 程序代码中 push 10001000,就是把10000000h当做了基地址,把push 10001000写入到文件中)。如果一个exe程序中一个dll装载时的地址与其它dll地址发生冲突(因为windows程序是虚拟地址空间,exe一般不会有地址冲突,加载dll时可能会有地址冲突),就需要修改代码中的地址,如push 10001000,call 10002000等。这时就需要用进行基址重定位。而基址重定位表中存放了,如果默认地址被改,需要修改的代码的地址。在PE文件中,基址重定位表一般放在一个单独的 ".reloc" 区,可以通过IMAGE_OPTIONAL_HEADER 中 的DataDirectory[5] 查看 基址重定位表 的RVA。
例如:
用W32Dasm 查看 Demo.dll (下载地址:http://pan.baidu.com/s/1qWDepo4)
图片1
可以发现MyMessageBox 这个函数,看看它的代码中的push 10006040 , push 10006030 中的地址是指向字符串的。如果一个程序在加载Demo.dll时因为Demo.dll 默认的地址被占用了,而使用其它的基地址,例如使用20000000h作为基地址,Demo.dll就从20000000h开始装载。这样字符串“Demo”和“Hello World!” 就不是在10006040h跟10006030h中了,这时就需要把push 10006040 , push 10006030改成push 20006040 , push 20006030 。
基址重定位表是由一个一个IMAGE_BASE_RELOCATION结构 构成的。
图片2
IMAGE_BASE_RELOCATION 结构:
typedef struct _IMAGE_BASE_RELOCATION { DWORD VirtualAddress; DWORD SizeOfBlock; // WORD TypeOffset[]; } IMAGE_BASE_RELOCATION; typedef IMAGE_BASE_RELOCATION UNALIGNED * PIMAGE_BASE_RELOCATION;
其中 VirtualAddress 表示 这一组地址的起始RVA。SizeOfBlock表示当前这个IMAGE_BASE_RELOCATION 结构的大小。TypeOffset是一个数组,它的元素个数就是( SizeOfBlock - 8 ) / 2 ,TypeOffset 每一个元素占用两个字节即16位,其中高4位表示重定位类型(一般都为3),低12位表示重定位地址。
实例分析:
查看Demo.dll的第一个 IMAGE_BASE_RELOCATION 结构
图片3
可以发现:
VirtualAddress 为1000h
SizeOfBlock 为 0164h
TypeOffset[0] 0333h 即 3是重定位类型 33h为重定位地址
TypeOffset[1] 0338hTypeOffset[2] 0340h
........
通过Type低12位+VirtualAddress 可以知道前三个的地址为1033h,1038h,1040h 。
再来看看图片1中Demo.dll的代码,可以发现1033h就是图片1中的push 10006040中的10006040,1038h就是push 10006030中的10006030 。
如果加载dll,发现不是使用默认的基地址,PE加载器就会把基址重定位表中所写的地址的值改掉。改掉方法是把原先的值加上 实际基地址 - 默认基地址 的值。
原文地址:http://blog.csdn.net/billvsme/article/details/39834257