注册 登录
编程论坛 汇编论坛

看来还是发个帖子求教吧-重定位

zongzhitao 发布于 2010-10-01 09:46, 1623 次点击
重定位
call @F
@@:
pop ebx
sub ebx,offset@B

这段代码问题之前有人问过了,我有几个地方还是有一点困惑
1    call @f    换成push @f或者push offset @f 对不对
2    sub ebx,offset@B    换成    sub ebx,@B    对不对
我在RADASM中试了试第二个好像是一样的。
谢谢大家了,顺便祝大家国庆快乐
22 回复
#2
zongzhitao2010-10-01 09:50
疑惑ing,如果call将正确的返回地址进栈,那么push能不能呢,push @f和push offset @f,我觉得前面一个可以,后面一个不对。
#3
zklhp2010-10-01 10:24
试试行不行啊

可以编译运行那就是行啦
#4
zongzhitao2010-10-01 10:49
刚和丫头去了超市,人真TMD多。用的RADASM不好编译啊
#5
zongzhitao2010-10-01 10:50
版主,我还给你发了短信呢
#6
zongzhitao2010-10-01 12:01
好吧,我试过了cal 改成 push 加了一个offset也一样
XXXXXXXX指令引用的XXXXXXXXXXX内存。该内存不能为writen
#7
zklhp2010-10-01 13:47
这个重定位的原理是什么呢?
#8
zklhp2010-10-01 13:49
别发那个站内信 不好用 呵呵 有事发帖说。。

不明白原理 当然随便试不出来了

1 这个应用不是很多了 了解下就好了 如果不是特别感兴趣 建议您背下来 会用就好了

2 你想知道 容我慢慢道来
#9
zklhp2010-10-01 14:02
1 为嘛需要重定位 简单的来讲 病毒需要将自身插入其他程序 其他进程 于是 需要执行重定位

2 重定位的原理?

这个要用机器码来理解 看编译出来的版本

00401000 >  E8 00000000     CALL GUI.00401005    ;压401005
00401005    5B              POP EBX    ;弹出401005
00401006    81EB 05104000   SUB EBX,GUI.00401005    ;一减 是0

也就说 偏移量为0 为啥啊 因为这里是直接写在程序里的

我要把这段代码挪个地方 比如402000处 则

00402000 >  E8 00000000     CALL GUI.00402005    ;压402005
00402005    5B              POP EBX    ;弹出402005
00402006    81EB 05104000   SUB EBX,GUI.00401005    ;一减 是1000

偏移量是1000 也就做到了重定位。。

大概就这样了


[ 本帖最后由 zklhp 于 2010-10-1 14:33 编辑 ]
#10
zklhp2010-10-01 14:16
这段代码问题之前有人问过了,我有几个地方还是有一点困惑
1    call @f    换成push @f或者push offset @f 对不对
2    sub ebx,offset@B    换成    sub ebx,@B    对不对

按说 这里 加offset 和不加是一样的 因为@F是标号 编译器对标号的默认是取偏移量(我也不确定 貌似是)


 
对于2 等价 对于1 两个写法等效

那对不对呢?

貌似不对诶

为嘛还是看机器码

我把这几种都贴出来

    push offset @F
    @@:
    pop ebx
    sub ebx,offset @B

00401000 >  68 05104000     PUSH GUI.00401005
00401005    5B              POP EBX
00401006    81EB 05104000   SUB EBX,GUI.00401005


    push @F
    @@:
    pop ebx
    sub ebx,offset @B

00401000 >  68 05104000     PUSH GUI.00401005
00401005    5B              POP EBX
00401006    81EB 05104000   SUB EBX,GUI.00401005


    push @F
    @@:
    pop ebx
    sub ebx,@B

00401000 >  68 05104000     PUSH GUI.00401005
00401005    5B              POP EBX
00401006    81EB 05104000   SUB EBX,GUI.00401005

自己看啦

为嘛不行啊 因为机器码中已经包含了地址了 也就是 05104000 你把它复制到其他地方 指令的内容 不会变 于是 这个偏移量不会变~

故而 不行

#11
zklhp2010-10-01 14:33
更深层次 push 是啥指令呢 是堆栈操作的指令 这里 压栈的 是数 也就是立即数(压eip貌似不能用指令 故而 用call代替)

而立即数 是写在指令中的 是指令的一部分 比如 mov eax.12345678h 则 这个12345678就会老实的出现在指令中 不会变

而我们这里需要的就是当前指令位置 故而不能用push的那一套


#12
你们都要疼我哦2010-10-01 14:36
记得前段时间我回答过这个问题,打了两大段字,不知道楼主是不是看的那个帖子?
如果仔细琢磨,理解是非常容易的。

几条代码的目的就是取得差值,要取得差值,就必须知道实际装载地址和默认装载地址,然后进行SUB。offset@B 这个在编译时就固定了,offset的使用也需要多注意。
这个是取得@@标号的默认装载地址,
pop ebx则是取得标号的实际装载地址,因为CALL需要把返回地址入栈,正是标号的
实际装载地址。

既然是重定位,当然是有可能需要重定位 也有可能不需要重定位。关键看offset@B和pop出的ebx是否相等。你非要忽视offset的作用 那也没办法
#13
zklhp2010-10-01 14:39
顺便留个作业

    call $+5
    pop ebx
    sub ebx,$-1

这个 对吗? 自己想想啦

扩展阅读 Intel(R) 64 and IA-32 Architectures Software Developer’s Manual 有兴趣找来看看 看看call的机器码

CALL—Call Procedure



  Opcode            Instruction      64-Bit      Compat/        Description

                                     Mode        Leg Mode



  E8 cw             CALL rel16       N.S.        Valid          Call near, relative, displacement

                                                                relative to next instruction.



  E8 cd             CALL rel32       Valid       Valid          Call near, relative, displacement

                                                                relative to next instruction. 32-bit

                                                                displacement sign extended to 64-bits

                                                                in 64-bit mode.



  FF /2             CALL r/m16       N.E.        Valid          Call near, absolute indirect, address

                                                                given in r/m16.



  FF /2             CALL r/m32       N.E.        Valid          Call near, absolute indirect, address

                                                                given in r/m32.



  FF /2             CALL r/m64       Valid       N.E.           Call near, absolute indirect, address

                                                                given in r/m64.



  9A cd             CALL             Invalid     Valid          Call far, absolute, address given in

                    ptr16:16                                    operand.



  9A cp             CALL             Invalid     Valid          Call far, absolute, address given in

                    ptr16:32                                    operand.



  FF /3             CALL m16:16      Valid       Valid          Call far, absolute indirect address given

                                                                in m16:16.



                                                                In 32-bit mode: if selector points to a

                                                                gate, then RIP = 32-bit zero extended

                                                                displacement taken from gate; else RIP

                                                                = zero extended 16-bit offset from far

                                                                pointer referenced in the instruction.



  FF /3             CALL m16:32      Valid       Valid          In 64-bit mode: If selector points to a

                                                                gate, then RIP = 64-bit displacement

                                                                taken from gate; else RIP = zero

                                                                extended 32-bit offset from far

                                                                pointer referenced in the instruction.



  REX.W + FF /3     CALL m16:64      Valid       N.E.           In 64-bit mode: If selector points to a

                                                                gate, then RIP = 64-bit displacement

                                                                taken from gate; else RIP = 64-bit

                                                                offset from far pointer referenced in

                                                                the instruction.

呵呵 解答完毕


#14
zklhp2010-10-01 14:39
还有个与这个相关的 跳转的问题 搜一下看看 也是我解答的 嘻嘻
#15
zongzhitao2010-10-01 14:47
谢谢大家乐,我会好好想的,特别谢谢版主和你们都要疼我哦
#16
zongzhitao2010-10-01 15:13
顺便留个作业

    call $+5
    pop ebx
    sub ebx,$-1

这个 对吗? 自己想想啦
;--------------------------------------------
交作业了,我觉得应该是对的,call &+5正好是pop ebx的地址(这样形容可以吗),sub ebx,$-1也正好是pop ebx
;--------------------------------------------
终于找到我问题的关键了,zklhp 版主说的 刚才call @f的机器码是 E8 00000000,而push @f 的机器码68 05104000     因为带了05104000,所以移动的话会出错。。。。
不知道我的理解是不是
#17
你们都要疼我哦2010-10-02 00:18

站内短消息不好用 以后别发了。

暂时不理解就不必强行理解了。偏离初衷就不好了。以后该明白时自然就明白。
举一才能反三,连举一都不行,就忙着反三是不可能的任务。
先理解透彻那几句吧。
call @F
@@:pop ebx
sub ebx,offset@B

CALL是伪指令,实际运行时会先把下条指令地址入栈,然后才会执行CALL。
而执行CALL既是执行了pop ebx,就把刚才入栈的下条指令地址弹出送入ebx,这个地址
就是pop ebx指令本身的地址 也即标号@@的实际地址。
相信你理解应该没问题。

重定位有2个方面 一是什么地方需要重定位 二是需要修正的差值是多少。
这几句代码的作用就是求得重定位需要的差值。

取得标号@@的实际地址以后,还要取得在默认装载情况下的地址。
这就是offset@B的作用。记得回答类似问题的时候,我反复讲,一定要
注意offset,甚至可以说这个是理解的关键。上午回贴时看到zklhp版主
在上页有个手误的地方,就是这个offset@B编译后的值。他自己发现了。

offset@B在编译时就固定了,以常量的形式存在,如果代码按照默认装载
地址装入,那么就不需要重定位,存在于ebx中的@@标号的实际地址和以常
量的形式存在的offset@B的值相等。
如果没有按照默认地址装载,那么他们的值是不等的,SUB以后就得到了两者
的差值,这个差值最后放在ebx中, 然后用这个差值去修正代码中需要进行
重新定位的数据。

实际装载地址可以每次都不同,即存在于ebx中的@@标号的实际地址可以每次
都不同, 但是offset@B在编译时就固定了,以常量的形式存在,不管实际地址
如何改变,这个值是固定不变的,它表示的就是不需重定位时@@标号的地址。

至于反汇编后的机器码什么的,暂时不必去多看,牵扯到opcode的知识,真要感兴趣可以去看看罗聪的OPCODE系列文章,很不错。

读书百遍,其义自见,多看看书 耐住性子。 象这些很简单的问题,多读读 多想想 多
动动手,不成任何问题的。

在透彻理解的前提下,再去扩展思路去想别的-----至少 如果你能理解sub ebx,offset@B的作用是取得差值的话,你也不会在主贴里想要把offset去
掉而变成实际地址减实际地址永远都是0了 那还有必要搞这几句代码吗?

这也是偶一直以来强调的,汇编语言单条指令查查手册谁都懂,但是重点要放在代码段
上 要放在代码段实现的功能上,
为什么要这几句代码?需要取得重定位需要的差值。
如何取得差值? 通过取得@@标号的实际装载地址,再去和@@标号的默认装载地址相减。
代码段完成后有什么结果? ebx中存放着所需的数据。

偶都成唐僧了, 偶看楼主骨骼清奇 眉清目秀 所以罗嗦半天
#18
zklhp2010-10-02 08:53
以下是引用你们都要疼我哦在2010-10-2 00:18:33的发言:


站内短消息不好用 以后别发了。

暂时不理解就不必强行理解了。偏离初衷就不好了。以后该明白时自然就明白。
举一才能反三,连举一都不行,就忙着反三是不可能的任务。
先理解透彻那几句吧。
call @F
@@:pop ebx
sub ebx,offset@B

CALL是伪指令,实际运行时会先把下条指令地址入栈,然后才会执行CALL。
而执行CALL既是执行了pop ebx,就把刚才入栈的下条指令地址弹出送入ebx,这个地址
就是pop ebx指令本身的地址 也即标号@@的实际地址。
相信你理解应该没问题。

重定位有2个方面 一是什么地方需要重定位 二是需要修正的差值是多少。
这几句代码的作用就是求得重定位需要的差值。

取得标号@@的实际地址以后,还要取得在默认装载情况下的地址。
这就是offset@B的作用。记得回答类似问题的时候,我反复讲,一定要
注意offset,甚至可以说这个是理解的关键。上午回贴时看到zklhp版主
在上页有个手误的地方,就是这个offset@B编译后的值。他自己发现了。

offset@B在编译时就固定了,以常量的形式存在,如果代码按照默认装载
地址装入,那么就不需要重定位,存在于ebx中的@@标号的实际地址和以常
量的形式存在的offset@B的值相等。
如果没有按照默认地址装载,那么他们的值是不等的,SUB以后就得到了两者
的差值,这个差值最后放在ebx中, 然后用这个差值去修正代码中需要进行
重新定位的数据。

实际装载地址可以每次都不同,即存在于ebx中的@@标号的实际地址可以每次
都不同, 但是offset@B在编译时就固定了,以常量的形式存在,不管实际地址
如何改变,这个值是固定不变的,它表示的就是不需重定位时@@标号的地址。

至于反汇编后的机器码什么的,暂时不必去多看,牵扯到opcode的知识,真要感兴趣可以去看看罗聪的OPCODE系列文章,很不错。

读书百遍,其义自见,多看看书 耐住性子。 象这些很简单的问题,多读读 多想想 多
动动手,不成任何问题的。

在透彻理解的前提下,再去扩展思路去想别的-----至少 如果你能理解sub ebx,offset@B的作用是取得差值的话,你也不会在主贴里想要把offset去
掉而变成实际地址减实际地址永远都是0了 那还有必要搞这几句代码吗?

这也是偶一直以来强调的,汇编语言单条指令查查手册谁都懂,但是重点要放在代码段
上 要放在代码段实现的功能上,
为什么要这几句代码?需要取得重定位需要的差值。
如何取得差值? 通过取得@@标号的实际装载地址,再去和@@标号的默认装载地址相减。
代码段完成后有什么结果? ebx中存放着所需的数据。

偶都成唐僧了, 偶看楼主骨骼清奇 眉清目秀 所以罗嗦半天

我也是唐僧、、、

很好奇 为嘛您的发言里面加了回车 难道是手机发的 呵呵
#19
zongzhitao2010-10-02 09:06
你们真早啊,我刚送丫头去上学。。
#20
zongzhitao2010-10-02 09:11
offset@B在编译时就固定了,以常量的形式存在,如果代码按照默认装载
地址装入,那么就不需要重定位,存在于ebx中的@@标号的实际地址和以常
量的形式存在的offset@B的值相等。
如果没有按照默认地址装载,那么他们的值是不等的,SUB以后就得到了两者
的差值,这个差值最后放在ebx中, 然后用这个差值去修正代码中需要进行
重新定位的数据。
实际装载地址可以每次都不同,即存在于ebx中的@@标号的实际地址可以每次
都不同, 但是offset@B在编译时就固定了,以常量的形式存在,不管实际地址
如何改变,这个值是固定不变的,它表示的就是不需重定位时@@标号的地址。
--------------------------------------------------------------------
感谢你们不厌其烦的为我解答,谢谢你们啦
#21
你们都要疼我哦2010-10-02 13:15
我用800*600的分辨率,看东西经常要左右拉滚动条,我自己打字的时候,
就不自觉的按回车键换行,省得自己看自己打的字都要滚动条。
现在别人都最少最少都是1024 768了,我习惯看大字,改不了了
#22
zklhp2010-10-02 13:29
以下是引用你们都要疼我哦在2010-10-2 13:15:37的发言:

我用800*600的分辨率,看东西经常要左右拉滚动条,我自己打字的时候,
就不自觉的按回车键换行,省得自己看自己打的字都要滚动条。
现在别人都最少最少都是1024 768了,我习惯看大字,改不了了

改这个不行么

只有本站会员才能查看附件,请 登录

#23
你们都要疼我哦2010-10-02 13:48
试着改过 不过还是有很多地方照旧,再说改过以后也不协调。
还是将就用800 600了。
现在养成习惯了,如果用别人的电脑,坐下来第一件事就是改
分辨率成800*600
1