#!/usr/bin/env ruby # -*- coding: binary -*- require 'rex/encoding/xor/exceptions' require 'rex/encoding/xor/generic' # # Routine for xor encoding a buffer by a 2-byte (intel word) key. The perl # version used to pad this buffer out to a 2-byte boundary, but I can't think # of a good reason to do that anymore, so this doesn't. # module Rex module Encoding module Xor class DwordAdditive < Generic def DwordAdditive.keysize 4 end def DwordAdditive._packspec 'V' end def DwordAdditive.pack_key(key) return [ key ].pack(_packspec) end def DwordAdditive.unpack_key(key) return key.unpack(_packspec)[0] end # hook in the key mutation routine of encode for the additive feedback def DwordAdditive._encode_mutate_key(buf, key, pos, len) if (pos + 1) % len == 0 # add the last len bytes (in this case 4) with the key, # dropping off any overflow key = pack_key( unpack_key(key) + unpack_key(buf[pos - (len - 1), len]) & (1 << (len << 3)) - 1 ) end return key end # # I realize this algorithm is broken. We invalidate some keys # in _find_bad_keys that could actually be perfectly fine. However, # it seems to work ok for now, and this is all just a lame adhoc method. # Maybe someday we can revisit this and make it a bit less ghetto... # def DwordAdditive._find_good_key(data, badkeys, badchars) ksize = keysize kstart = "" ksize.times { kstart << rand(256) } # random key starting place key = kstart.dup # # now for the ghettoness of an algorithm: # try the random key we picked # if the key failed, figure out which key byte corresponds # increment that key byte # if we wrapped a byte all the way around, fail :( # loop do # ok, try to encode it, any bad chars present? pos = _check(data, key, badchars) # yay, no problems, we found a key! break if !pos strip = pos % ksize # increment the offending key byte key[strip] = key[strip] + 1 & 0xff # We wrapped around! if key[strip] == kstart[strip] raise KeySearchError, "Key space exhausted on strip #{strip}!", caller end end return key end end end end end # DwordAdditive/Xor/Encoding/Rex