【问题标题】:Short jumps with a relative offset not using the offset I expect相对偏移量的短跳不使用我期望的偏移量
【发布时间】:2014-03-30 07:36:45
【问题描述】:

我正在尝试理解简短的 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 %esicall -0x2b 的字节相加得到 42。第一条指令不应该是 jmp 0x2a 吗?并从调用指令的末尾减去popl %esi 的开头的字节我得到-47。电话不应该是call -0x2f吗?当他实际创建一个 c 文件并将他的程序集放在 __asm__ 块中时,他使用我计算的偏移量,但不是在此之前的代码中。发生了什么变化?

当我在这里时,他不能刚刚访问 eip 并使用它来获取内存中字符串的相对偏移量吗?

【问题讨论】:

  • 看起来你得到了答案,但重申一下,在汇编中你只跳转或分支到标签。问题是,除非你直接用十六进制编写,否则真的无法知道一段代码会有多大,这将非常浪费时间。

标签: linux assembly gdb nasm x86-64


【解决方案1】:

使用 Intel 语法,这应该是:

jmp     short $+022h    ;jump from current location ($ == 4000b0) to 4000d2

请注意,使用相同 $+022h 语法的长跳转最终仍会跳转到 4000d2,因为汇编器会生成更小的偏移字段。这种用法很少见,最常见的例外是 jmp short $+2 在遗留代码中用于在 I/O 设备访问之间产生非常短的延迟。

【讨论】:

  • 这编码EB 1E,这是一个跳转到中断。 jmp short 0x20 编码 EB 1F。 (我用 gdb 检查了程序集)。
  • 我不熟悉那个汇编器,但是由于执行跳转时 PC = 4000b2,所以从 PC 的偏移量应该是 0x1E 到 4000d0。 "$" 代表当前位置(与执行指令时 PC 的位置相反),使偏移量更易于计算。
  • 我会投赞成票,虽然这不是我想要的,所以我不能接受。你用什么汇编器?
  • 好吧,我去了 IRC 频道,他们告诉我没有办法像我想要的那样使用汇编程序的偏移量,所以我将接受这个答案并在此处留下评论为他人。也有标签。
  • +2 表示跳转指令?!据我所知,偏移量是从 jmp/call 指令之后开始计算的。
猜你喜欢
  • 2018-12-23
  • 2014-02-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多