https://www.exploit-db.com/exploits/46907
global _start
section .text
_start:
xor rsi,rsi
push rsi
mov rdi,0x68732f2f6e69622f
push rdi
push rsp
pop rdi
push 59
pop rax
cdq
syscall
One instruction is push %rsp
, which is followed by popping it in rdi
. I am confused. According to the documentation, rdi
in the execve
syscall should contain the path name to the executable. What does it have to do with rsp
here? Other shellcode don't manipulate rsp
.
CodePudding user response:
Constructing data on the stack, and then copying the stack pointer to another reg, is totally normal. Lots of shellcode manipulates RSP.
push rsp
/ pop rdi
is just a 2-byte version of mov rdi, rsp
, and it comes after pushing a 0 and 8 bytes of ASCII data. (Which could have been written much more clearly in NASM syntax as mov rdi, '/bin//sh'
).
Single-step the asm with a debugger and look at memory pointed-to by RDI when syscall
executes, and work backwards to understand how you got there.
It's weird that they golfed their mov rdi,rsp
down to 2 bytes with push/pop but used a REX prefix on their xor-zeroing instruction. xor esi,esi
is equivalent. NASM will optimize that source into xor esi,esi
, but your link shows the disassembly.
Also, push 59
/ pop rax
is the standard 3-byte way to construct a small constant (__NR_execve
) in a register without depending on any other register values. They could have done lea eax, [rsi 59]
which is also 3 bytes and also avoids any 0
bytes. (5-byte mov eax, 59
would include an imm32 with three zero bytes, which is why most shellcode has to avoid it.)
cdq
just sets RDX=0 (envp=NULL
), since EAX is signed positive at that point. Another code-golfy way to save bytes vs. xor edx,edx
. And they apparently knew about taking advantage of implicit zeroing of the full 64-bit reg when writing a 32-bit reg (EDX) in this case, so it's even more strange they used 64-bit xor-zeroing for RSI. Maybe they didn't know much about x86-64 and didn't even realize that cqo
would explicitly use 64-bit operand-size, sign-extending RAX into RDX:RAX, and had intended to use 64-bit everywhere because they thought they needed to.