Home > Back-end >  What is the stack pointer used for in this shellcode?
What is the stack pointer used for in this shellcode?

Time:11-13

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.

  • Related