2005-05-23 00:34:16 +00:00
|
|
|
#!/usr/bin/ruby
|
|
|
|
|
2005-06-08 21:39:12 +00:00
|
|
|
require 'Rex/Encoding/Xor/Exceptions'
|
2005-06-09 16:49:11 +00:00
|
|
|
require 'Rex/StringUtils'
|
2005-06-08 21:39:12 +00:00
|
|
|
|
2005-05-23 00:34:16 +00:00
|
|
|
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
|
|
|
|
|
2005-05-25 17:40:50 +00:00
|
|
|
#
|
|
|
|
# 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)
|
2005-06-09 16:49:11 +00:00
|
|
|
return Rex::StringUtils.badchar_index(key, badchars)
|
2005-05-25 17:40:50 +00:00
|
|
|
end
|
|
|
|
def Generic._check_encode(data, key, badchars)
|
2005-06-09 16:49:11 +00:00
|
|
|
return Rex::StringUtils.badchar_index(encode(data, key), badchars)
|
2005-05-25 17:40:50 +00:00
|
|
|
end
|
|
|
|
|
2005-05-24 06:50:46 +00:00
|
|
|
def Generic.find_key(data, badchars)
|
2005-05-25 06:24:05 +00:00
|
|
|
return _find_good_key(data, _find_bad_keys(data, badchars), badchars)
|
2005-05-24 06:50:46 +00:00
|
|
|
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
|
|
|
|
#
|
2005-05-25 06:24:05 +00:00
|
|
|
def Generic._find_good_key(data, badkeys, badchars)
|
2005-05-24 06:50:46 +00:00
|
|
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2005-06-08 21:39:12 +00:00
|
|
|
raise KeySearchError, "Exhausted byte space for strip #{strip}!", caller
|
2005-05-24 06:50:46 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
key << kbyte
|
|
|
|
strip += 1
|
|
|
|
end
|
|
|
|
|
2005-05-25 17:40:50 +00:00
|
|
|
# ok, we should have a good key now, lets double check...
|
2005-06-09 04:25:40 +00:00
|
|
|
if _check(data, key, badchars)
|
2005-06-08 21:39:12 +00:00
|
|
|
raise KeySearchError, "Key found, but bad character check failed!", caller
|
2005-05-25 17:40:50 +00:00
|
|
|
end
|
|
|
|
|
2005-05-24 06:50:46 +00:00
|
|
|
return key
|
2005-05-24 03:58:47 +00:00
|
|
|
end
|
|
|
|
|
2005-05-23 00:34:16 +00:00
|
|
|
def Generic.encode(buf, key)
|
|
|
|
|
|
|
|
if !key.kind_of?(String)
|
2005-06-08 21:39:12 +00:00
|
|
|
raise ::ArgumentError, "Key must be a string!", caller
|
2005-05-23 00:34:16 +00:00
|
|
|
end
|
|
|
|
|
2005-05-24 03:58:47 +00:00
|
|
|
len = key.length
|
|
|
|
|
|
|
|
if len == 0
|
2005-06-08 21:39:12 +00:00
|
|
|
raise ::ArgumentError, "Zero key length!", caller
|
2005-05-24 03:58:47 +00:00
|
|
|
end
|
2005-05-23 00:34:16 +00:00
|
|
|
|
|
|
|
if keysize != 0 && keysize != len
|
2005-06-08 21:39:12 +00:00
|
|
|
raise ::ArgumentError, "Key length #{len}, expected #{keysize}", caller
|
2005-05-23 00:34:16 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
encoded = ""
|
|
|
|
pos = 0
|
|
|
|
|
|
|
|
while pos < buf.length
|
|
|
|
encoded += (buf[pos] ^ key[pos % len]).chr
|
2005-06-09 20:20:08 +00:00
|
|
|
key = _encode_mutate_key(buf, key, pos, len)
|
2005-05-24 03:58:47 +00:00
|
|
|
pos += 1
|
2005-05-23 00:34:16 +00:00
|
|
|
end
|
|
|
|
|
2005-06-09 18:08:06 +00:00
|
|
|
return [ encoded, key ]
|
2005-05-23 00:34:16 +00:00
|
|
|
|
|
|
|
end
|
|
|
|
|
2005-05-25 05:31:57 +00:00
|
|
|
# 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
|
|
|
|
|
2005-05-24 03:58:47 +00:00
|
|
|
# maybe a bit a smaller of method name?
|
2005-06-09 04:25:40 +00:00
|
|
|
def Generic.find_key_and_encode(data, badchars)
|
2005-06-09 18:08:06 +00:00
|
|
|
key = find_key(data, badchars)
|
|
|
|
enc, fkey = encode(data, key)
|
|
|
|
return [ enc, key, fkey ]
|
2005-05-24 03:58:47 +00:00
|
|
|
end
|
|
|
|
|
2005-05-23 00:34:16 +00:00
|
|
|
|
|
|
|
end end end end # Generic/Xor/Encoding/Rex
|