147 lines
3.2 KiB
Ruby
147 lines
3.2 KiB
Ruby
# -*- coding: binary -*-
|
|
|
|
require 'rex/encoding/xor/exceptions'
|
|
require 'rex/text'
|
|
|
|
module Rex
|
|
module Encoding
|
|
module Xor
|
|
|
|
class Generic
|
|
|
|
def Generic.keysize
|
|
# special case:
|
|
# 0 means we encode based on the length of the key
|
|
# we don't enforce any perticular key length
|
|
return 0
|
|
end
|
|
|
|
#
|
|
# Now for some internal check methods
|
|
#
|
|
|
|
# hook stylies!
|
|
# return index of offending byte or nil
|
|
def Generic._check(data, key, badchars)
|
|
return _check_key(key, badchars) || _check_encode(data, key, badchars)
|
|
end
|
|
def Generic._check_key(key, badchars)
|
|
return Rex::Text.badchar_index(key, badchars)
|
|
end
|
|
def Generic._check_encode(data, key, badchars)
|
|
return Rex::Text.badchar_index(encode(data, key), badchars)
|
|
end
|
|
|
|
def Generic.find_key(data, badchars)
|
|
return _find_good_key(data, _find_bad_keys(data, badchars), badchars)
|
|
end
|
|
|
|
# !!! xxx MAKE THESE BITCHE PRIVATE
|
|
|
|
#
|
|
# Find a list of bytes that can't be valid xor keys, from the data and badchars.
|
|
# This returns a Array of hashes, length keysize
|
|
#
|
|
def Generic._find_bad_keys(data, badchars)
|
|
|
|
ksize = keysize
|
|
|
|
# array of hashes for the bad characters based
|
|
# on their position in the data
|
|
badkeys = [ ]
|
|
ksize.times { badkeys << { } }
|
|
|
|
badchars.each_byte { |badchar|
|
|
pos = 0
|
|
data.each_byte { |char|
|
|
badkeys[pos % ksize][char ^ badchar] = true
|
|
pos += 1
|
|
}
|
|
}
|
|
|
|
return badkeys
|
|
end
|
|
|
|
#
|
|
# (Hopefully) find a good key, from badkeys and badchars
|
|
#
|
|
def Generic._find_good_key(data, badkeys, badchars)
|
|
|
|
ksize = keysize
|
|
strip = 0
|
|
key = ""
|
|
|
|
while strip < keysize
|
|
|
|
kbyte = rand(256)
|
|
|
|
catch(:found_kbyte) do
|
|
256.times {
|
|
|
|
if !badkeys[strip][kbyte] && !badchars[kbyte.chr]
|
|
throw :found_kbyte
|
|
end
|
|
|
|
kbyte = (kbyte + 1) & 0xff
|
|
}
|
|
|
|
raise KeySearchError, "Exhausted byte space for strip #{strip}!", caller
|
|
end
|
|
|
|
key << kbyte
|
|
strip += 1
|
|
end
|
|
|
|
# ok, we should have a good key now, lets double check...
|
|
if _check(data, key, badchars)
|
|
raise KeySearchError, "Key found, but bad character check failed!", caller
|
|
end
|
|
|
|
return key
|
|
end
|
|
|
|
def Generic.encode(buf, key)
|
|
|
|
if !key.kind_of?(String)
|
|
raise ::ArgumentError, "Key must be a string!", caller
|
|
end
|
|
|
|
len = key.length
|
|
|
|
if len == 0
|
|
raise ::ArgumentError, "Zero key length!", caller
|
|
end
|
|
|
|
if keysize != 0 && keysize != len
|
|
raise ::ArgumentError, "Key length #{len}, expected #{keysize}", caller
|
|
end
|
|
|
|
encoded = ""
|
|
pos = 0
|
|
|
|
while pos < buf.length
|
|
encoded += (buf[pos,1].unpack("C*")[0] ^ key[pos % len, 1].unpack("C*")[0]).chr
|
|
key = _encode_mutate_key(buf, key, pos, len)
|
|
pos += 1
|
|
end
|
|
|
|
return [ encoded, key ]
|
|
|
|
end
|
|
|
|
# kind of ghetto, but very convenient for mutating keys
|
|
# by default, do no key mutations
|
|
def Generic._encode_mutate_key(buf, key, pos, len)
|
|
return key
|
|
end
|
|
|
|
# maybe a bit a smaller of method name?
|
|
def Generic.find_key_and_encode(data, badchars)
|
|
key = find_key(data, badchars)
|
|
enc, fkey = encode(data, key)
|
|
return [ enc, key, fkey ]
|
|
end
|
|
|
|
|
|
end end end end # Generic/Xor/Encoding/Rex
|