#!/usr/bin/env ruby # -*- coding: binary -*- require 'rex/text' module Rex module Encoder module Alpha2 class Generic # Note: 'A' is presumed to be accepted, but excluded from the accepted characters, because it serves as the terminator def Generic.default_accepted_chars ; ('a' .. 'z').to_a + ('B' .. 'Z').to_a + ('0' .. '9').to_a ; end def Generic.gen_decoder_prefix(reg, offset) # Should never happen - have to pick a specifc # encoding: # alphamixed, alphaupper, unicodemixed, unicodeupper '' end def Generic.gen_decoder(reg, offset) # same as above return '' end def Generic.gen_second(block, base) # XOR encoder for ascii - unicode uses additive (block^base) end def Generic.encode_byte(block, badchars) accepted_chars = default_accepted_chars.dup badchars.each_char {|c| accepted_chars.delete(c) } if badchars # No, not nipple. nibble_chars = Array.new(0x10) {[]} accepted_chars.each {|c| nibble_chars[c.unpack('C')[0] & 0x0F].push(c) } poss_encodings = [] block_low_nibble = block & 0x0F block_high_nibble = block >> 4 # Get list of chars suitable for expressing lower part of byte first_chars = nibble_chars[block_low_nibble] # Build a list of possible encodings first_chars.each do |first_char| first_high_nibble = first_char.unpack('C')[0] >> 4 # In the decoding process, the low nibble of the second char gets combined # (either ADDed or XORed depending on the encoder) with the high nibble of the first char, # and we want the high nibble of our input byte to result second_low_nibble = gen_second(block_high_nibble, first_high_nibble) & 0x0F # Find valid second chars for this first char and add each combination to our possible encodings second_chars = nibble_chars[second_low_nibble] second_chars.each {|second_char| poss_encodings.push(second_char + first_char) } end if poss_encodings.empty? raise RuntimeError, "No encoding of #{"0x%.2X" % block} possible with limited character set" end # Return a random encoding poss_encodings[rand(poss_encodings.length)] end def Generic.encode(buf, reg, offset, badchars = '') encoded = gen_decoder(reg, offset) buf.each_byte { |block| encoded << encode_byte(block, badchars) } encoded << add_terminator() return encoded end # 'A' signifies the end of the encoded shellcode def Generic.add_terminator() 'AA' end end end end end