吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 5880|回复: 12
收起左侧

[调试逆向] PE文件笔记十六 代码重定位

  [复制链接]
lyl610abc 发表于 2021-4-9 15:19
本帖最后由 lyl610abc 于 2021-4-9 15:22 编辑

继续PE系列笔记的更新

PE其它笔记索引可前往:
PE文件笔记一 PE介绍


前面在PE文件笔记十五 导入表中学习了导入表,接着要学习重定位表,但在学习重定位表前,要先了解一下代码重定位

代码重定位

在学习重定位表之前,要知道什么是代码重定位

代码重定位定义

代码重定位是把可执行代码从内存的一个地方移动到另外一个地方去,保证该部分代码还能正常执行

重定位的提出

可执行代码从内存的一个地方移动到另外一个地方,所有的字节码(硬编码)均保持不变;如果代码指令中的某些操作数不跟着地址发生改变,势必会导致程序运行出错。这里的某些操作数是指那些使用了绝对地址定位的程序指令中的操作数

为更好地学习重定位,结合下面的实例分析:

代码

#include <stdio.h>

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


运行结果

image-20210409135527504

可以看到,代码能够正常地取出数据区的内容并打印出来


反汇编对应的硬编码

5:        _asm{
6:    _code:
7:            xor eax,eax
0040D73F 33 C0                xor         eax,eax
8:            mov al,byte ptr ds:[_data]
0040D741 3E A0 49 D7 40 00    mov         al,ds:[_data (0040d749)]
9:            jmp _end
0040D747 EB 01                jmp         _end (0040d74a)
10:   _data:
11:           _emit 0x61
0040D749 61                   db 61h
12:   _end:
13:           mov result,eax
0040D74A 89 45 FC             mov         dword ptr [ebp-4],eax
14:       }

这里关注一下出现地址的两个地方的硬编码:

第一处
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 _end
0040D747 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)

image-20210409141350198


在弹出来的编辑窗口中,取消勾选保持大小,然后将硬编码粘贴进去

image-20210409141728724


得到结果:

image-20210409141956125


可以看到,此时采用相对地址的jmp指令后面跳转的地址发生了变化,依然能够跳转到我们想要的位置

但是mov指令由于采取了绝对地址,它去取的地址仍然是先前的地址,没有对应去取下面的数据:0x61

也因此导致了,代码位置变化以后,其运行的结果就不正确了


修正重定位

通过前面,可以知道,代码出错的原因在于mov指令后面采用了绝对地址

于是将mov 指令后面的地址改为相对地址即可

代码

#include <stdio.h>

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 _call
0040D73F E8 09 00 00 00       call        _call (0040d74d)
8:            xor ebx,ebx
0040D744 33 DB                xor         ebx,ebx
9:            mov bl,byte ptr ds:[eax+8]
0040D746 3E 8A 58 08          mov         bl,byte ptr ds:[eax+8]
10:           jmp _end
0040D74A EB 06                jmp         _end (0040d752)
11:   _data:
12:           _emit 0x61
0040D74C 61                   popad
13:   _call:
14:           mov eax,dword ptr ss:[esp]
0040D74D 36 8B 04 24          mov         eax,dword ptr ss:[esp]
15:           ret
0040D751 C3                   ret
16:   _end:
17:           mov result,ebx
0040D752 89 5D FC             mov         dword ptr [ebp-4],ebx
18:       }

这里关注一下出现地址的地方的硬编码

7:            call _call
0040D73F 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)

image-20210409141350198


在弹出来的编辑窗口中,取消勾选保持大小,然后将硬编码粘贴进去

image-20210409145959047


得到结果:

image-20210409150032097

可以看到采用了相对地址后,移动完代码的位置其代码依然满足我们的需求


F8单步步过到最后一行代码,查看ebx此时的值

image-20210409150346087

可以看到此时的ebx能够正确地获取到数据区的内容( •̀ ω •́ )✧


采用重定位技术的好处

从上面的例子中,不难的得出采用重定位技术的好处:

如果在代码编写中使用重定位技术,你就可以将代码随意地部署到内存中,而不影响程序的运行


总结

  • 采用重定位技术,可以让代码段在任意内存中运行
  • 重定位技术的核心就在:不使用绝对地址,而使用相对地址
  • 使用的是绝对地址还是相对地址,归根结底取决于其对应的硬编码

免费评分

参与人数 7吾爱币 +6 热心值 +7 收起 理由
jiaokai + 1 + 1 很想学会,但还是没学会,难.........
yanghui0705 + 1 作为一个java程序员,虽然看不太懂吧,但觉得是那么回事 555
大寨主 + 1 + 1 用心讨论,共获提升!
bailemenmlbj + 1 + 1 谢谢@Thanks!
adime2018 + 1 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
debug_cat + 1 + 1 大佬66666666666666666
blywq + 1 + 1 谢谢@Thanks!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

feiteng666 发表于 2021-4-9 16:17
大牛66666赞一个
fan329218 发表于 2021-4-9 16:52
swhyy 发表于 2021-4-9 17:55
123坎弯弯 发表于 2021-4-9 21:12
支持楼主,赞一个
大寨主 发表于 2021-4-10 13:19
前来学习
linwen421 发表于 2021-4-10 13:27
绝对的大牛啊!学习当中!
潇翰明枫 发表于 2021-4-12 14:18
萌萌懂懂,不过感谢楼主分享,学习中
Leoi_Chan 发表于 2023-10-27 17:29
感谢分享,学到很多
luchao521 发表于 2023-10-31 18:16
绝对的大牛啊!学习当中!
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-5 20:32

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表