Loading... 前言: 重定位信息是在编译的时候,由编译器生成并被保留在可执行文件中。当程序执行前,操作系统会根据这些重定位信息对代码予以修正,复杂的操作由编译器和操作系统代替程序完成。开发人员在编写程序的时候就可以随意地使用哪些涉及直接寻址的指令了。 ##### 重定位表定位 源程序如下: ``` #include<windows.h> #include<tchar.h> int main(void) { MessageBox(NULL,_T("Hello World"),_T("对话框"),MB_OK); return 0; } ``` 编译为hw.exe,以此程序来学习pe结构中重定位表的相关知识。 重定位表: ![image.png](http://47.117.131.13/usr/uploads/2021/08/3237294884.png) **重定位表项IMAGE_BASE_RELOCATION** 与导入表类似,重定位表指针指向的位置是一个数组,而不像导出表一样只有一个结构。这个数组的每一项都是如下结构: ![image.png](http://47.117.131.13/usr/uploads/2021/08/1165903895.png) 以下是对每一项的解释: **IMAGE_BASE_RELOCATION.VirtualAddress**:双字。重定位块RVA。由于直接寻址指令较多,所以在一些PE文件中,存在大量的需要修正的重定位地址。按照常规计算,每个地址占4个字节,如果有n个重定位项,那么需要总的空间为4\*n字节。重新审视直接寻址中的地址发现,在一页中的所有地址只需要12位(因为win32页面大小为1000h,也就是4096字节,即2的12次方)。而这12位只需要用一个字就能表达出来。如果有n个重定位项,则只需要2*n个地址+4个字节的页面起始RVA+4字节的本页的重定位项个数。将以上两种情况的表达式分别是: Sum0 = 4*n Sum1 = 2*n+4+4 很明显,当有大量的重定位地址时,Sum0远大于Sum1。 **IMAGE_BASE_RELOCATION.SizeOfBlock** :双字。重定位块中重定位表项数量。该字段时表达式Sum1里的第二个4,描述的是该页面中所有的重定位表的项数。 数组和数组之间并不是相邻的。比如页面1的IMAGE_BASE_RELOCATION后,并不是页面2的IMAGE_BASE_RELOCATION,而是页面1的所有重定位表项;每个项大小为一个字,每个字的高四位被用来说明此重定位项的类型,之后才是需要重定位的数据在页面中的地址。 ![image.png](http://47.117.131.13/usr/uploads/2021/08/3670837826.png) **在实际的PE文件中,我们只能看到0和3这两种情况,也就是说这一项要么是对齐用的,要么是需要全部修正的。** ![image.png](http://47.117.131.13/usr/uploads/2021/08/3695504916.png) **实例:** 依旧以hw.exe程序为例。 重定位表: ![image.png](http://47.117.131.13/usr/uploads/2021/08/1362879950.png) 从字节码可以获知: * 重定位表第一项的代码起始页面RVA=0x00001000 * 第一块的长度为00000164h 第一块的第一个重定位项的值为302Dh,其中高四位为3,转换为二进制码为0011,表示该重定位值得高位和低位均需要修正。低十二位为修正地址,该地址加上基地址再加上代码页面得起始地址即为代码再内存得实际位置VA值。公式如下: 实际VA = 基地址 + 代码页面起始地址 + 低十二位虚拟地址 = 00400000 + 001000 + 02D = 40102Dh 算出对应的FOA = 0x102D: ![image.png](http://47.117.131.13/usr/uploads/2021/08/3055162998.png) 在内存中找到0x40102D处的字节码:0041F024h ![image.png](http://47.117.131.13/usr/uploads/2021/08/1826057308.png) 在文件中找到0x102D处的内容:0041F024 ![image.png](http://47.117.131.13/usr/uploads/2021/08/2937146000.png) 可以看到,0x40102D处的地址需要修正。重定位表中后边的项也是一样的道理。 ![image.png](http://47.117.131.13/usr/uploads/2021/08/145674675.png) 我们找到需要修正的地址,如此处的VA = 0x0041F024,ImageBase = 0x400000,RVA = 1F024h。如果ImageBase变成了0x300000 ,那么修正之后就是: VA - ImageBase + ImageBase' = VA' = 0x0041F024 - 0x400000 + 0x300000 = 0x31F024. 参考:《windows.PE权威指南》 最后修改:2021 年 08 月 05 日 05 : 18 PM © 允许规范转载