/ / Saltos curtos com um deslocamento relativo que não usa o deslocamento que espero - linux, assembly, gdb, nasm, x86-64

Saltos curtos com um deslocamento relativo não usando o deslocamento esperado - linux, assembly, gdb, nasm, x86-64

Estou tentando entender a instrução jmp curta. Eu tenho um programa muito simples, compilado com 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

Desmontado, o código fica assim em gdb (desmontar 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

Estou tentando pular para 0x4000d2. 34-2 = 32 = 0x20. 0x4000d2 - 0x4000b2 = 0x20. Não importa o que eu monte, o nasm sempre parece codificar o endereço de salto como um deslocamento de um byte após o início da instrução de salto. Porque é jmp short 0x20 montagem errado? (sem contar que jmp 0x20 teve um resultado diferente e foi uma instrução de 5 bytes em vez de uma instrução de 2 bytes)

Eu também estou lendo sobre quebrando a pilha por diversão e lucro. Aleph1 quer pular de jmp para ligar e depois de chamar para popl. Este é o código que ele usa:

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

Adicionando os bytes de popl %esi para call -0x2b Recebo 42. Não deveria a primeira instrução ser jmp 0x2a? E subtraindo bytes do final da instrução de chamada até o início de popl %esi Eu recebo -47. A chamada não deve ser call -0x2f? Quando ele realmente cria um arquivo c e coloca sua montagem em um __asm__ bloco, ele usa as compensações que eu calculei, mas não neste código que é anterior a isso. O que mudou?

E enquanto estou aqui, ele não conseguiu acessar o eip e usá-lo para obter o deslocamento relativo da string na memória?

Respostas:

1 para resposta № 1

Com a sintaxe da Intel, deve ser:

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

Observe que um salto em distância usando os mesmos $ + 022hA sintaxe ainda acabaria saltando para 4000d2, pois o montador geraria um campo de deslocamento menor. Esse tipo de uso é raro, com a exceção mais comum: jmp short $ + 2 usado no código legado para gerar atrasos muito curtos entre os acessos ao dispositivo de E / S.