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);