我正在尝试理解简短的 jmp 指令。我有一个非常简单的程序,用 nasm 编译:
SECTION .data
bsh: db "/bin/sh",0
arr: dq bsh,0
SECTION .text
global main
main:
jmp short 0x20
mov edx, 0
mov rsi, arr
mov rdi, bsh
mov rax, 0x3b
syscall
mov ebx, 0
mov eax, 0x3c
syscall
反汇编后,代码在 gdb 中看起来像这样(反汇编 main):
0x00000000004000b0 <+0>: jmp 0x4000d1 <main+33>
0x00000000004000b2 <+2>: mov $0x0,%edx
0x00000000004000b7 <+7>: movabs $0x6000e8,%rsi
0x00000000004000c1 <+17>: movabs $0x6000e0,%rdi
0x00000000004000cb <+27>: mov $0x3b,%eax
0x00000000004000d0 <+32>: syscall
0x00000000004000d2 <+34>: mov $0x0,%ebx
0x00000000004000d7 <+39>: mov $0x3c,%eax
0x00000000004000dc <+44>: syscall
我正在尝试跳转到 0x4000d2
。 34 - 2 = 32 = 0x20。 0x4000d2 - 0x4000b2 = 0x20。无论我汇编什么,nasm 似乎总是将跳转地址编码为跳转指令开始后一个字节的偏移量。为什么jmp short 0x20
汇编错误? (更不用说 jmp 0x20
有不同的结果,它是一条 5 字节指令而不是 2 字节指令)
我也在阅读 smashing the stack for fun and profit . Aleph1 想从 jmp 跳到 call,然后从 call 跳到 popl。这是他使用的代码:
jmp 0x26 # 2 bytes
popl %esi # 1 byte
movl %esi,0x8(%esi) # 3 bytes
movb $0x0,0x7(%esi) # 4 bytes
movl $0x0,0xc(%esi) # 7 bytes
movl $0xb,%eax # 5 bytes
movl %esi,%ebx # 2 bytes
leal 0x8(%esi),%ecx # 3 bytes
leal 0xc(%esi),%edx # 3 bytes
int $0x80 # 2 bytes
movl $0x1, %eax # 5 bytes
movl $0x0, %ebx # 5 bytes
int $0x80 # 2 bytes
call -0x2b # 5 bytes
.string \"/bin/sh\" # 8 bytes
将 popl %esi
中的字节加到 call -0x2b
我得到 42。第一条指令不应该是 jmp 0x2a
?从调用指令的末尾到 popl %esi
的开头减去字节,我得到 -47。调用不应该是 call -0x2f
吗?当他实际创建一个 c 文件并将他的程序集放在 __asm__
block 中时,他使用我计算的偏移量,但不是在此之前的代码中。什么改变了?
当我在这里时,他不能访问 eip 并使用它来获取字符串在内存中的相对偏移量吗?
最佳答案
使用 Intel 语法,这应该是:
jmp short $+022h ;jump from current location ($ == 4000b0) to 4000d2
请注意,使用相同的 $+022h 语法的长跳转最终仍会跳转到 4000d2,因为汇编程序会生成较小的偏移字段。这种用法很少见,最常见的异常(exception)是在遗留代码中使用 jmp short $+2 来在 I/O 设备访问之间生成非常短的延迟。
关于linux - 具有相对偏移的短跳未使用我期望的偏移,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22741483/