C shellcode explanation

using ndisasm, the data in the sh array can be disassembled into the following valid 64bit x86-machinecode:

00000000  EB0B              jmp short 0xd
00000002  5F                pop rdi
00000003  4831D2            xor rdx,rdx
00000006  52                push rdx
00000007  5E                pop rsi
00000008  6A3B              push byte +0x3b
0000000A  58                pop rax
0000000B  0F05              syscall
0000000D  E8F0FFFFFF        call qword 0x2
00000012                    '/bin/sh'

It looks line simple position-independent shellcode to do a kernel syscall to execute /bin/sh.

The first instruction jumps ahead to the instruction just before the /bin/sh string, that in turn does a call back to the second instruction again. The return address is then popped from the stack into register rdi. This is a trick to get the memeory address of the /bin/sh string, since the shellcode does not know where in memory it is when it gets executed.

The register rdx is then set to 0 and pushed to the stack and poped back into register rsi. The byte 0x3b is then pused to the stack and popped back into register rax.

We are now set up as follows:

  • rdi = pointer to the string /bin/sh
  • rdx = 0
  • rsi = 0
  • rax = 0x3b

At this point, we hand over control to the kernel with syscall, where the argument 0x3b in rax tells it to execve() the file path that is at pointer rdi

If we translate this back into C, it is basicly doing:

execve('/bin/sh', NULL, NULL);

Tags:

C

Shellcode