手动添加重定位
00 什么是重定位
- 什么是重定位?
- 在32步伐中内存有4G空间,此中高2G是系统空间,低2G是用户空间,当一个步伐被加载,会被安排到这个空间中的某个地方,默认情况下EXE会被加载到0x00400000,dll会被加载到0x10000000位置。
- 一般情况下dll都必须开启重定位,应为一个步伐中会存在多个dll,假如所有的dll都加载到0x10000000位置,dll相互直接会被覆盖。而exe可以选择不开启重定位,一个步伐中只有一个主模块。
- 而在步伐中,假如有引用到绝对地点的代码,例如下

- 那么步伐假如开启随机基址,那么这个指令将执行失败,应为它并不是指向当前加载的地点,而是以0x00400000为基址的数据,此时这个地点是无法访问的。

- 加载器怎样修复重定位的?
- 当一个可执行步伐,被加载到内存中,首先会判断是否开启随机基址,可以通过两个字段
IMAGE_FILE_HEADER FileHeader; //文件头FileHeader.Characteristics; // 属性字段IMAGE_OPTIONAL_HEADER OptionalHeader;// 扩展头OptionalHeader.DllCharacteristics;// 属性字段
- 当这个两个属性中都开启了随机基址后,那么加载器就会找数据目次表【5】项,(重定位表)
- 这个重定位指向一个布局体,该布局是一个不定长度的表
typedef struct _IMAGE_BASE_RELOCATION { DWORD VirtualAddress; //RVA,指向一个分页的基址,都是0x1000的倍数 DWORD SizeOfBlock; //这个重定位数据总大小// WORD TypeOffset[1]; //必要修复的数据块项,个数= (SizeOfBlock-8)/2} IMAGE_BASE_RELOCATION;typedef IMAGE_BASE_RELOCATION UNALIGNED * PIMAGE_BASE_RELOCATION;// 数据块布局typedef struct _TYPEDATA { WORD offset : 12; // 一个分页的偏移 WORD type : 4; // 重定位块的属性,通常假如为3,表示32位地点必要修复}TYPEDATA, * PTYPEDATA;
- 加载器中这个重定位表获取 VirtualAddress + TYPEDATA.offset 找到要修复的数据,按照修复公式进行修复
修复后的地点 = 待修复的数据(0x00402000) - 默认基址(0x00400000) + 当前加载基址(0x00A80000)

01 编写测试代码
.386.model flat,stdcallinclude user32.incincludelib user32.lib.data szText db "hello",0.codemain: push 0 push 0 push offset szText ;待修复的地点 0x00403000 push 0 call MessageBox retend mainend
- 该步伐没有重定位表,没有开启随机基址

02 开启重定位
- 将FileHeader.Characteristics第0位置0

- 将OptionalHeader.DllCharacteristics的第4位置为1

03 构建重定位表
- 为了给步伐添加一个重定位表,我们可以找到一个空白的地域,或者添加一个区段,作为重定位表,然后让数据目次表【5】,重定位表指向它。
- 在这个步伐中我选择0x880这个文件偏移(FOA)位置,作为重定位表

- 但是由于PE文件中绝大部分地点保存的都是RVA,所以我们必要将FOA转换为RVA。转换公式
RVA = FOA(0x880) - FOA区段偏移(0x800) + RVA区段内存偏移(0x3000)RVA = 0x3080

、

- 根据重定位表布局,构建数据
VirtualAddress = 0x1000; SizeOfBlock= 2*2 + 8 = 0x0C; TYPE1 = 3005TYPE2 = 3014


04 验证步伐

来源:http://www.12558.net
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |