如何在x64 asm中跳过相对于RIP跳转的1条指令?

时间:2017-12-12 14:51:42

标签: assembly 64-bit intel

我试图在不使用标签的情况下跳过1条指令,带标签的例子是:

cmp r12, r13
je dest ; skip the jmp
jmp whatever
dest:
nop

但是,我的限制是我不能使用标签,所以我假设我必须创建一个相对于RIP寄存器的跳转。例如(伪):

cmp r12, r13
je rip+0x05 ; this would obviously depend on the length of the next instruction
jmp whatever
nop

然而,我缺乏生产任何工作的知识,据我所知,没有黑客也无法读/写RIP寄存器。

编辑:我只熟悉英特尔语法,我使用Keystone作为汇编程序。我将从程序集中取出字节并将其加载到可执行内存位置。我正在使用我自己的网站从汇编中获取字节,如果你查看it,你可能会有这个想法。

编辑2:我尝试了Jesters和Margaret Blooms的评论,建议使用:

je .+0x05
; or
je $+0x05

但是,我可以确认两者都不适用于Keystone!幸运的是,我注意到Keystone能够处理这段代码:

je +0x05

是否有人能够确认这是否有效?

编辑3:我用NASM试了一下,$前缀与我测试过的代码配合得很好。我用它来测试它:

section .text       
global _WinMain@16       

_WinMain@16:
    jmp $+2+2 ; skip this jmp and the next jmp (each 2 bytes)
    jmp $
    ret 16

它按预期工作。同样defuse产生与Keystone相同的输出。唯一的区别是defuse使用$前缀而Keystone根本不需要! Keystone等价物是:

jmp +4
jmp .
ret 16

1 个答案:

答案 0 :(得分:3)

请注意,在NASM中,MASM $ docker network inspect otp_bridge [ { "Name": "otp_bridge", "Id": "727bfc6cc21fd74f19eb7fe164582637cbad4c2d7e36620c1c0a1c51c0490d31", "Created": "2017-12-13T06:12:40.5070258Z", "Scope": "local", "Driver": "bridge", "EnableIPv6": false, "IPAM": { "Driver": "default", "Options": null, "Config": [ { "Subnet": "172.19.0.0/16", "Gateway": "172.19.0.1" } ] }, "Internal": false, "Attachable": true, "Ingress": false, "ConfigFrom": { "Network": "" }, "ConfigOnly": false, "Containers": { "02fa407062cdd5f6f368f2d17c5e68d2f9155d1d9b30c9edcbb2386a9ded648a": { "Name": "totp_api", "EndpointID": "860c47da1e70d304399b42917b927a8cc6717b86c6d1ee6f065229e33f496c2f", "MacAddress": "02:42:ac:13:00:02", "IPv4Address": "172.19.0.2/16", "IPv6Address": "" } }, "Options": {}, "Labels": { "com.docker.compose.network": "bridge", "com.docker.compose.project": "otp" } } ] 不是前缀。 It's a stand-alone keyword / symbol which refers to the address of the current line

$无法工作:je $+5为5个字节,短JCC为2.因此,您需要jmp rel32跳过5字节指令,或{{ 1}}跳过一个2字节的指令。

rel8位移将为je $+7$+4,因为跳转会从指令末尾对其位移进行编码。但是NASM的0x05标签给出了指令开始的地址,汇编器总是根据目标地址为你计算相对位移。因此,对于0x02,您需要包含当前指令的长度。

如果您想自己编码rel8,可以使用$伪指令发出所需的字节。例如$+x

除非您使用可靠的方式知道下一条指令的时长,否则您不使用任何标签的整个方法/目标都存在根本缺陷。 (例如,使用dbdb 0xEB, 0x02强制执行长编码或短编码)。您所能做的就是编码一个跳转,该跳转前进固定数量的字节,而不是跳过一条指令的跳转,无论宽度如何。

但严重的是只使用标签; x86跳跃总是相对的,所以让你的汇编程序让你的生活更轻松,并计算正确的相对位移。