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
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.