继续PE系列笔记的更新
PE其它笔记索引可前去:
PE文件笔记一 PE介绍
前面在PE文件笔记十五 导入表中学习了导入表,接着要学习重定位表,但在学习重定位表前,要先了解一下代码重定位
代码重定位
在学习重定位表之前,要知道什么是代码重定位
代码重定位定义
代码重定位是把可执行代码从内存的一个地方移动到别的一个地方去,包管该部分代码还能正常执行
重定位的提出
可执行代码从内存的一个地方移动到别的一个地方,全部的字节码(硬编码)均保持不变;如果代码指令中的某些操作数不跟着地点发生改变,势必会导致步伐运行出错。这里的某些操作数是指那些使用了绝对地点定位的步伐指令中的操作数
为更好地学习重定位,联合下面的实例分析:
代码
#include int main(){ int result=0; _asm{_code: xor eax,eax mov al,byte ptr ds:[_data] jmp _end_data: _emit 0x61_end: mov result,eax } printf("%X\n",result); return 0;}代码说明
上面的代码十分简短简单,主要看汇编的代码
汇编代码分为三段:代码段_code、数据段_data、竣事段_end
代码段
代码段就是取出数据段的数据,然后生存到寄存器eax
数据段
数据段只存储了一个数据0x61
竣事段
将先前生存到寄存器eax中的数据赋值给变量result
运行结果
可以看到,代码能够正常地取出数据区的内容并打印出来
反汇编对应的硬编码
5: _asm{6: _code:7: xor eax,eax0040D73F 33 C0 xor eax,eax8: mov al,byte ptr ds:[_data]0040D741 3E A0 49 D7 40 00 mov al,ds:[_data (0040d749)]9: jmp _end0040D747 EB 01 jmp _end (0040d74a)10: _data:11: _emit 0x610040D749 61 db 61h12: _end:13: mov result,eax0040D74A 89 45 FC mov dword ptr [ebp-4],eax14: }这里关注一下出现地点的两个地方的硬编码:
第一处
8: mov al,byte ptr ds:[_data]0040D741 3E A0 49 D7 40 00 mov al,ds:[_data (0040d749)]取出0040d749地点对应的数据,取出的数据宽度为一个字节,然后赋值给al(eax的低8位)
可以看到这里的硬编码直接就是写死的地点0040d749(49 D7 40 00 小端存储),为绝对地点
第二处
9: jmp _end0040D747 EB 01 jmp _end (0040d74a)这里的jmp跳转则是采用偏移的方式,其偏移为01(前面的EB 表示jmp)
要跳转的地点 = 当前地点 + 当前指令长度 + 偏移 = 0040D747 + 2 + 1 = 0040D74A
第二处的代码则是采用了相对地点的方法举行寻址
没重定位带来的题目
前面的代码中存在绝对地点,因此如果将代码移到别的地方一定导致结果错误
于是为了验证这一点,举行以下的演示:
首先复制其对应的硬编码:
33 C0 3E A0 49 D7 40 00 EB 01 61 89 45 FC然后用OD随便打开一个步伐
随便选中一行代码,然后 右键→二进制→编辑(或使用快捷键Ctrl+E)
在弹出来的编辑窗口中,取消勾选保持大小,然后将硬编码粘贴进去
得到结果:
可以看到,此时采用相对地点的jmp指令后面跳转的地点发生了变化,依然能够跳转到我们想要的位置
但是mov指令由于接纳了绝对地点,它去取的地点仍旧是先前的地点,没有对应去取下面的数据:0x61
也因此导致了,代码位置变化以后,其运行的结果就不正确了
修正重定位
通过前面,可以知道,代码出错的缘故原由在于mov指令后面采用了绝对地点
于是将mov 指令后面的地点改为相对地点即可
代码
#include int main(){ int result=0; _asm{_code: call _call xor ebx,ebx mov bl,byte ptr ds:[eax+8] jmp _end_data: _emit 0x61_call: mov eax,dword ptr ss:[esp] ret_end: mov result,ebx } printf("%X\n",result); return 0;}代码说明
代码中多了一个_call段,该段用来调用call,根据堆栈的特性,获得的[esp]里存储的地点为xor ebx,ebx这一行指令的地点
不了解为什么在call里面可以通过这种方法获取到返回地点的可以回顾:逆向基础笔记七 堆栈图(重点)
获取到地点后将地点生存到eax中
之后返回以后通过xor ebx,ebx这一行的地点+偏移8得到_data的地点,此时采用的便是相对地点的方式
修正后对应的硬编码
5: _asm{6: _code:7: call _call0040D73F E8 09 00 00 00 call _call (0040d74d)8: xor ebx,ebx0040D744 33 DB xor ebx,ebx9: mov bl,byte ptr ds:[eax+8]0040D746 3E 8A 58 08 mov bl,byte ptr ds:[eax+8]10: jmp _end0040D74A EB 06 jmp _end (0040d752)11: _data:12: _emit 0x610040D74C 61 popad13: _call:14: mov eax,dword ptr ss:[esp]0040D74D 36 8B 04 24 mov eax,dword ptr ss:[esp]15: ret0040D751 C3 ret16: _end:17: mov result,ebx0040D752 89 5D FC mov dword ptr [ebp-4],ebx18: }这里关注一下出现地点的地方的硬编码
7: call _call0040D73F E8 09 00 00 00 call _call (0040d74d)这里的call调用采用偏移的方式,其偏移为09(前面的E8 表示call)
要跳转的地点 = 当前地点 + 当前指令长度 + 偏移 = 0040D73F + 5 + 9 = 0040D74D
于是此时的代码就全部是采用相对地点了,此时代码就支持重定位了
测试重定位后的硬编码
依旧要先将重定位的硬编码复制出来:
E8 09 00 00 00 33 DB 3E 8A 58 08 EB 06 61 36 8B 04 24 C3 89 5D FC然后用OD随便打开一个步伐
随便选中一行代码,然后 右键→二进制→编辑(或使用快捷键Ctrl+E)
在弹出来的编辑窗口中,取消勾选保持大小,然后将硬编码粘贴进去
得到结果:
可以看到采用了相对地点后,移动完代码的位置其代码依然满意我们的需求
F8单步步过到最后一行代码,检察ebx此时的值
可以看到此时的ebx能够正确地获取到数据区的内容( •̀ ω •́ )✧
采用重定位技术的利益
从上面的例子中,不难的得出采用重定位技术的利益:
如果在代码编写中使用重定位技术,你就可以将代码随意地部署到内存中,而不影响步伐的运行
总结
- 采用重定位技术,可以让代码段在恣意内存中运行
- 重定位技术的核心就在:不使用绝对地点,而使用相对地点
- 使用的是绝对地点还是相对地点,归根结底取决于其对应的硬编码
来源:http://www.12558.net
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |