也谈PE重定位表

最近研究脱壳,遇到了dll,因此不可避免的须要修复重定位表。之前研究过也脱过很多壳,但都是exe历来没有手工修太重定位表,因而搜索之,恩有这么一篇:《PE重定位表学习手记》,有刚巧手上有看雪段钢等编著的《加密与解密》,一并阅读。html

《PE重定位表学习手记》中说到:算法

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

……服务器

这个可由每一个块结构中的Size来肯定。Size的值是以DWORD表示的当前整个块的大小,先减去IMAGE_BASE_RELOCATION的大小, 由于重定位数据是16位WORD的,再除以2,就获得个重定位数据的个数。由Size能够直接到达下一个重定位块,如图所 示:0x5E850000+0x000000EC=0x5E8500EC即为第二个重定位块的地址,直至某个块首结构的VirtualAddress为 0,代表重定位表结束。数据结构

……ide

do
{//处理一个接一个的重定位块,最后一个重定位块以RAV=0结束
函数

……学习

}while (pRelocBlock->VirtualAddress);加密

《加密与解密》中说到:3d

若是还有更多段,将重复上面数据结构,直到VirtualAddress为NULL,表示结束。如图13.48所示是重定位表结构的一个示意图。

OK,照此,就是说若是咱们本身手工建立编辑了重定位表,那么须要填充8个字节的0(也就是空的IMAGE_BASE_RELOCATION)做为重定位表的结束标记。而且pe文件头目录表中的重定位表尺寸也修改成整个重定位表数据的大小(固然包括这8个空字节)。

运行……嚯,0xC0000005……(若是8个空字节后刚好还有杂乱的随机数据,你还会看到各类有意思的Win32 ErrorCode)。

为啥呢?是修改的时候手抖了吗?眼花?神经衰弱?非也,是这些文章错了!咱们先来看看微软官方权威的《Microsoft PE and COFF Specification

如下文字来自Microsoft PE and COFF Specification(Updated: September 21, 2010 File name: pecoff_v8.docx)
5.6 The .reloc Section (Image Only)

The base relocation table contains entries for all base relocations in the image. The Base Relocation Table field in the optional header data directories gives the number of bytes in the base relocation table. For more information, see section 3.4.3, “Optional Header Data Directories (Image Only).” The base relocation table is divided into blocks. Each block represents the base relocations for a 4K page. Each block must start on a 32-bit boundary.

能够看到,微软的文档中并无说重定位表须要padding zero来做为end标志。

下面咱们看看到底windows中是怎么处理这个重定位表的,下面是反汇编windows xp sp2的 ntdll.dll,实际的LoadLibraryA/W最后会调用到  LdrLoadDll(x, x, x, x)

而后沿下列调用链(用IDA和微软的符号服务器便可方便的分析):

LdrLoadDll(x, x, x, x)->LdrpLoadDll(x,x,x,x,x,x)-> LdrpMapDll(x,x,x,x,x,x)->LdrRelocateImage(x, x, x, x, x)->LdrRelocateImageWithBias(x,x,x,x,x,x,x)

LdrRelocateImageWithBias就是实际执行重定位算法的函数,咱们来看看这个函数是怎么作的:

image

首先RtlImageDirectoryEntryToData从目录表中获取重定位表的偏移和尺寸(TotalCountBytes)

而后指针移动到重定位表开始,而后循环开始每一项IMAGE_BASE_RELOCATION调用一次LdrProcessRelocationBlockLongLong,LdrProcessRelocationBlockLongLong返回值是下一项的指针,除非访问到了无效内存,不然这个指针咱们能够认为永远是有效的,7C93D8A7这里的跳转不会执行到。TotalCountBytes为零的时候,说明重定位表处理完成,成功返回。

LdrProcessRelocationBlockLongLong是一个很是单纯的函数,里面彻底根据读取到的数据来对PE进行重定位,也就是说,它永远认为输入数据是正确的!没有任何错误处理!

好了,如今咱们回到一开始的问题:windows遇到了重定位表的最后一项,咱们手工写的8个零,因而LdrProcessRelocationBlockLongLong一丝不苟的开始在VirtualAddress = 0的地方,开始处理(SizeOfBlock-8)/2项,别忘了SizeOfBlock=0,(SizeOfBlock-8)/2是什么请读者本身算吧……

总结:重定位表实际有多少项就是多少项!

相关文章
相关标签/搜索