assemblyx86-64nasmmemory-addressshellcode

Getting absolute address of data in shellcode


Here's my shellcode:

    xor rax, rax
    xor rdi, rdi
    xor rsi, rsi
    xor rdx, rdx

    ; getting address of `pathname`
    mov rdi, [something]
    mov al, 59
    mov rdi, rsp
    syscall

    xor rax,rax
    mov al, 60
    xor rdi, rdi
    syscall

_pathname:
    db "/usr/bin/shutdown",0

Simple execve and exit, that's all. The problem is that I can't get the absolute address in order to access pathname. The "solution" to this, that I have found, is rigging the code something like this:

call _end

_start:
    pop rdi ; absolute address of _start
    ; then add bytes to get to address of _end

_end:
    call start
    db "/usr/bin/shutdown", 0

This never made sense to me, and it didn't work. I also tried using FPU instructions, which were supposed to work as well, but they didn't work either.

Anybody have a solution?

OS: Linux
Architecture: amd64


Solution

  • On x86-64 you have RIP-relative addressing modes, so you should be able to simply do lea rdi, [rel _pathname]. The assembler computes the displacement between the address of the current instruction (or actually the next one) and the label _pathname, and encodes it into the instruction. At runtime this displacement is added to rip and the result placed in rdi.

    x86-32 doesn't have relative addressing modes, so in 32-bit mode, your call/pop trick is the standard way to accomplish this, despite being awkward. And it does work in 64-bit mode too. But the address popped by pop rdi isn't the address of _start; rather it's the return address pushed by the call _start instruction, i.e. the address of the byte following the call _start instruction. In this case it is exactly the first byte of your /usr/bin/shutdown string, so in fact you wouldn't have to add anything.

    Note that you are passing a null pointer as the argv and envp arguments to execve. This is legal for the kernel, but the shutdown program is probably not expecting this and it may crash upon startup. So you might have to do some more work to construct a minimal argument vector with argv[0] == "shutdown" at least.