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
mov al, 60
xor rdi, rdi
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:
pop rdi ; absolute address of _start
; then add bytes to get to address of _end
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?
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
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
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 == "shutdown" at least.