rex-encoder 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. checksums.yaml +7 -0
  2. checksums.yaml.gz.sig +1 -0
  3. data.tar.gz.sig +0 -0
  4. data/.gitignore +9 -0
  5. data/.rspec +2 -0
  6. data/.travis.yml +5 -0
  7. data/CODE_OF_CONDUCT.md +49 -0
  8. data/Gemfile +4 -0
  9. data/README.md +32 -0
  10. data/Rakefile +6 -0
  11. data/bin/console +14 -0
  12. data/bin/setup +8 -0
  13. data/lib/rex/encoder.rb +15 -0
  14. data/lib/rex/encoder/alpha2.rb +31 -0
  15. data/lib/rex/encoder/alpha2/alpha_mixed.rb +129 -0
  16. data/lib/rex/encoder/alpha2/alpha_upper.rb +138 -0
  17. data/lib/rex/encoder/alpha2/generic.rb +90 -0
  18. data/lib/rex/encoder/alpha2/unicode_mixed.rb +116 -0
  19. data/lib/rex/encoder/alpha2/unicode_upper.rb +123 -0
  20. data/lib/rex/encoder/bloxor/bloxor.rb +327 -0
  21. data/lib/rex/encoder/ndr.rb +90 -0
  22. data/lib/rex/encoder/nonalpha.rb +61 -0
  23. data/lib/rex/encoder/nonupper.rb +64 -0
  24. data/lib/rex/encoder/version.rb +5 -0
  25. data/lib/rex/encoder/xdr.rb +108 -0
  26. data/lib/rex/encoder/xor.rb +69 -0
  27. data/lib/rex/encoder/xor/dword.rb +13 -0
  28. data/lib/rex/encoder/xor/dword_additive.rb +13 -0
  29. data/lib/rex/encoding/xor.rb +20 -0
  30. data/lib/rex/encoding/xor/byte.rb +15 -0
  31. data/lib/rex/encoding/xor/dword.rb +21 -0
  32. data/lib/rex/encoding/xor/dword_additive.rb +92 -0
  33. data/lib/rex/encoding/xor/exceptions.rb +17 -0
  34. data/lib/rex/encoding/xor/generic.rb +146 -0
  35. data/lib/rex/encoding/xor/qword.rb +15 -0
  36. data/lib/rex/encoding/xor/word.rb +21 -0
  37. data/lib/rex/poly.rb +134 -0
  38. data/lib/rex/poly/block.rb +480 -0
  39. data/lib/rex/poly/machine.rb +13 -0
  40. data/lib/rex/poly/machine/machine.rb +830 -0
  41. data/lib/rex/poly/machine/x86.rb +509 -0
  42. data/lib/rex/poly/register.rb +101 -0
  43. data/lib/rex/poly/register/x86.rb +41 -0
  44. data/rex-encoder.gemspec +31 -0
  45. metadata +248 -0
  46. metadata.gz.sig +0 -0
@@ -0,0 +1,90 @@
1
+ # -*- coding: binary -*-
2
+ require "rex/text"
3
+
4
+ module Rex
5
+ module Encoder
6
+ module NDR
7
+
8
+ # Provide padding to align the string to the 32bit boundary
9
+ def NDR.align(string)
10
+ return "\x00" * ((4 - (string.length & 3)) & 3)
11
+ end
12
+
13
+ # Encode a 4 byte long
14
+ # use to encode:
15
+ # long element_1;
16
+ def NDR.long(string)
17
+ return [string].pack('V')
18
+ end
19
+
20
+ # Encode a 2 byte short
21
+ # use to encode:
22
+ # short element_1;
23
+ def NDR.short(string)
24
+ return [string].pack('v')
25
+ end
26
+
27
+ # Encode a single byte
28
+ # use to encode:
29
+ # byte element_1;
30
+ def NDR.byte(string)
31
+ return [string].pack('C')
32
+ end
33
+
34
+ # Encode a byte array
35
+ # use to encode:
36
+ # char element_1
37
+ def NDR.UniConformantArray(string)
38
+ return long(string.length) + string + align(string)
39
+ end
40
+
41
+ # Encode a string
42
+ # use to encode:
43
+ # char *element_1;
44
+ def NDR.string(string)
45
+ string << "\x00" # null pad
46
+ return long(string.length) + long(0) + long(string.length) + string + align(string)
47
+ end
48
+
49
+ # Encode a string
50
+ # use to encode:
51
+ # w_char *element_1;
52
+ def NDR.wstring(string)
53
+ string = string + "\x00" # null pad
54
+ return long(string.length) + long(0) + long(string.length) + Rex::Text.to_unicode(string) + align(Rex::Text.to_unicode(string))
55
+ end
56
+
57
+ # Encode a string and make it unique
58
+ # use to encode:
59
+ # [unique] w_char *element_1;
60
+ def NDR.uwstring(string)
61
+ string = string + "\x00" # null pad
62
+ return long(rand(0xffffffff))+long(string.length) + long(0) + long(string.length) + Rex::Text.to_unicode(string) + align(Rex::Text.to_unicode(string))
63
+ end
64
+
65
+ # Encode a string that is already unicode encoded
66
+ # use to encode:
67
+ # w_char *element_1;
68
+ def NDR.wstring_prebuilt(string)
69
+ # if the string len is odd, thats bad!
70
+ if string.length % 2 > 0
71
+ string = string + "\x00"
72
+ end
73
+ len = string.length / 2;
74
+ return long(len) + long(0) + long(len) + string + align(string)
75
+ end
76
+
77
+ # alias to wstring, going away soon
78
+ def NDR.UnicodeConformantVaryingString(string)
79
+ NDR.wstring(string)
80
+ end
81
+
82
+ # alias to wstring_prebuilt, going away soon
83
+ def NDR.UnicodeConformantVaryingStringPreBuilt(string)
84
+ NDR.wstring_prebuilt(string)
85
+ end
86
+
87
+ end
88
+ end
89
+ end
90
+
@@ -0,0 +1,61 @@
1
+ # -*- coding: binary -*-
2
+
3
+ require 'rex/text'
4
+
5
+ module Rex
6
+ module Encoder
7
+
8
+ class NonAlpha
9
+
10
+ def NonAlpha.gen_decoder
11
+ decoder =
12
+ "\x66\xB9\xFF\xFF" +
13
+ "\xEB\x19" + # Jmp to table
14
+ "\x5E" + # pop esi
15
+ "\x8B\xFE" + # mov edi, esi - Get table addr
16
+ "\x83\xC7" + "A" + # add edi, tablelen - Get shellcode addr
17
+ "\x8B\xD7" + # mov edx, edi - Hold end of table ptr
18
+ "\x3B\xF2" + # cmp esi, edx
19
+ "\x7D\x0B" + # jle to end
20
+ "\xB0\x7B" + # mov eax, 0x7B - Set up eax with magic
21
+ "\xF2\xAE" + # repne scasb - Find magic!
22
+ "\xFF\xCF" + # dec edi - scasb purs us one ahead
23
+ "\xAC" + # lodsb
24
+ "\x28\x07" + # subb [edi], al
25
+ "\xEB\xF1" + # jmp BACK!
26
+ "\xEB" + "B" + # jmp [shellcode]
27
+ "\xE8\xE2\xFF\xFF\xFF"
28
+ end
29
+
30
+ def NonAlpha.encode_byte(block, table, tablelen)
31
+ if tablelen > 255 || block == 0x7B
32
+ raise RuntimeError, "BadChar"
33
+ end
34
+
35
+ if (block >= 0x41 && block <= 0x5A) || (block >= 0x61 && block <= 0x7A)
36
+ # gen offset, return magic
37
+ offset = 0x7b - block
38
+ table += offset.chr
39
+ tablelen = tablelen + 1
40
+ block = 0x7B
41
+ end
42
+
43
+ return [block.chr, table, tablelen]
44
+ end
45
+
46
+ def NonAlpha.encode(buf)
47
+ table = ""
48
+ tablelen = 0
49
+ nonascii = ""
50
+ encoded = gen_decoder()
51
+ buf.each_byte { |block|
52
+ newchar, table, tablelen = encode_byte(block.unpack('C')[0], table, tablelen)
53
+ nonascii += newchar
54
+ }
55
+ encoded.gsub!(/A/, tablelen)
56
+ encoded.gsub!(/B/, tablelen+5)
57
+ encoded += table
58
+ encoded += nonascii
59
+ end
60
+
61
+ end end end
@@ -0,0 +1,64 @@
1
+ # -*- coding: binary -*-
2
+
3
+ require 'rex/text'
4
+
5
+ module Rex
6
+ module Encoder
7
+
8
+ class NonUpper
9
+
10
+
11
+ def NonUpper.gen_decoder()
12
+ decoder =
13
+ "\x66\xB9\xFF\xFF" +
14
+ "\xEB\x19" + # Jmp to table
15
+ "\x5E" + # pop esi
16
+ "\x8B\xFE" + # mov edi, esi - Get table addr
17
+ "\x83\xC7" + "A" + # add edi, tablelen - Get shellcode addr
18
+ "\x8B\xD7" + # mov edx, edi - Hold end of table ptr
19
+ "\x3B\xF2" + # cmp esi, edx
20
+ "\x7D\x0B" + # jle to end
21
+ "\xB0\x7B" + # mov eax, 0x7B - Set up eax with magic
22
+ "\xF2\xAE" + # repne scasb - Find magic!
23
+ "\xFF\xCF" + # dec edi - scasb purs us one ahead
24
+ "\xAC" + # lodsb
25
+ "\x28\x07" + # subb [edi], al
26
+ "\xEB\xF1" + # jmp BACK!
27
+ "\xEB" + "B" + # jmp [shellcode]
28
+ "\xE8\xE2\xFF\xFF\xFF"
29
+ end
30
+
31
+ def NonUpper.encode_byte(badchars, block, table, tablelen)
32
+ if (tablelen > 255) or (block == 0x40)
33
+ raise RuntimeError, "BadChar"
34
+ end
35
+
36
+ if (block >= 0x41 and block <= 0x40) or (badchars =~ block)
37
+ # gen offset, return magic
38
+ offset = 0x40 - block;
39
+ table += offset.chr
40
+ tablelen = tablelen + 1
41
+ block = 0x40
42
+ end
43
+
44
+ return [block.chr, table, tablelen]
45
+ end
46
+
47
+ def NonUpper.encode(buf)
48
+ table = ""
49
+ tablelen = 0
50
+ nonascii = ""
51
+ encoded = gen_decoder()
52
+ buf.each_byte {
53
+ |block|
54
+
55
+ newchar, table, tablelen = encode_byte(block.unpack('C')[0], table, tablelen)
56
+ nonascii += newchar
57
+ }
58
+ encoded.gsub!(/A/, tablelen)
59
+ encoded.gsub!(/B/, tablelen+5)
60
+ encoded += table
61
+ encoded += nonascii
62
+ end
63
+
64
+ end end end
@@ -0,0 +1,5 @@
1
+ module Rex
2
+ module Encoder
3
+ VERSION = "0.1.0"
4
+ end
5
+ end
@@ -0,0 +1,108 @@
1
+ # -*- coding: binary -*-
2
+ module Rex
3
+ module Encoder
4
+
5
+ ###
6
+ #
7
+ # This class implements basic XDR encoding.
8
+ #
9
+ ###
10
+ module XDR
11
+ MAX_ARG = 0xffffffff
12
+
13
+ # Also: unsigned int, bool, enum
14
+ def XDR.encode_int(int)
15
+ return [int].pack('N')
16
+ end
17
+
18
+ def XDR.decode_int!(data)
19
+ raise ArgumentError, 'XDR: No Integer data to decode' unless data
20
+ raise ArgumentError, "XDR: Too little data to decode (#{data.size})" if data.size < 4
21
+ return data.slice!(0..3).unpack('N')[0]
22
+ end
23
+
24
+ def XDR.encode_lchar(char)
25
+ char |= 0xffffff00 if char & 0x80 != 0
26
+ return encode_int(char)
27
+ end
28
+
29
+ def XDR.decode_lchar!(data)
30
+ return (decode_int!(data) & 0xff).chr
31
+ end
32
+
33
+ # Also: Variable length opaque
34
+ def XDR.encode_string(str, max=MAX_ARG)
35
+ raise ArgumentError, 'XDR: String too long' if str.length > max
36
+ len = str.length
37
+ str << "\x00" * ((4 - (len & 3)) & 3)
38
+ return encode_int(len) + str
39
+ end
40
+
41
+ def XDR.decode_string!(data)
42
+ real_len = decode_int!(data)
43
+ return "" if real_len == 0
44
+ align_len = (real_len + 3) & ~3
45
+ return data.slice!(0..align_len-1).slice(0..real_len-1)
46
+ end
47
+
48
+ def XDR.encode_varray(arr, max=MAX_ARG, &block)
49
+ raise ArgumentError, 'XDR: Too many array elements' if arr.length > max
50
+ return encode_int(arr.length) + arr.collect(&block).join(nil)
51
+ end
52
+
53
+ def XDR.decode_varray!(data)
54
+ buf = []
55
+ 1.upto(decode_int!(data)) { buf.push(yield(data)) }
56
+ return buf
57
+ end
58
+
59
+ # encode(0, [0, 1], "foo", ["bar", 4]) does:
60
+ # encode_int(0) +
61
+ # encode_varray([0, 1]) { |i| XDR.encode_int(i) } +
62
+ # encode_string("foo") +
63
+ # encode_string("bar", 4)
64
+ def XDR.encode(*data)
65
+ data.collect do |var|
66
+ if var.kind_of?(String)
67
+ encode_string(var)
68
+ elsif var.kind_of?(Integer)
69
+ encode_int(var)
70
+ elsif var.kind_of?(Array) && var[0].kind_of?(String)
71
+ raise ArgumentError, 'XDR: Incorrect string array arguments' if var.length != 2
72
+ encode_string(var[0], var[1])
73
+ elsif var.kind_of?(Array) && var[0].kind_of?(Integer)
74
+ encode_varray(var) { |i| XDR.encode_int(i) }
75
+ # 0 means an empty array index in the case of Integer and an empty string in
76
+ # the case of String so we get the best of both worlds
77
+ elsif var.kind_of?(Array) && var[0].nil?
78
+ encode_int(0)
79
+ else
80
+ type = var.class
81
+ type = var[0].class if var.kind_of?(Array)
82
+ raise TypeError, "XDR: encode does not support #{type}"
83
+ end
84
+ end.join(nil)
85
+ end
86
+
87
+ # decode(buf, Integer, String, [Integer], [String]) does:
88
+ # [decode_int!(buf), decode_string!(buf),
89
+ # decode_varray!(buf) { |i| XDR.decode_int!(i) },
90
+ # decode_varray!(buf) { |s| XDR.decode_string(s) }]
91
+ def XDR.decode!(buf, *data)
92
+ return *data.collect do |var|
93
+ if data.length == 0
94
+ elsif var.kind_of?(Array) && var[0] == String
95
+ decode_varray!(buf) { |s| XDR.decode_string!(s) }
96
+ elsif var.kind_of?(Array) && var[0] == Integer
97
+ decode_varray!(buf) { |i| XDR.decode_int!(i) }
98
+ elsif var == String
99
+ decode_string!(buf)
100
+ elsif var == Integer
101
+ decode_int!(buf)
102
+ end
103
+ end
104
+ end
105
+ end
106
+
107
+ end
108
+ end
@@ -0,0 +1,69 @@
1
+ # -*- coding: binary -*-
2
+
3
+ module Rex
4
+ module Encoder
5
+
6
+ ###
7
+ #
8
+ # This class performs basic XOR encoding.
9
+ #
10
+ ###
11
+ class Xor
12
+
13
+ attr_accessor :raw, :encoded, :badchars, :opts, :key, :fkey # :nodoc:
14
+
15
+ #
16
+ # wrap that in a wanna be static class
17
+ #
18
+ def self.encode(*args)
19
+ self.new.encode(*args)
20
+ end
21
+
22
+ #
23
+ # Return the class associated with this encoder.
24
+ #
25
+ def encoder()
26
+ self.class::EncoderKlass
27
+ end
28
+
29
+ #
30
+ # This method encodes the supplied data, taking into account the badchar
31
+ # list, and returns the encoded buffer.
32
+ #
33
+ def encode(data, badchars = '', opts = { })
34
+ self.raw = data
35
+ self.badchars = badchars
36
+ self.opts = opts
37
+
38
+ # apply any transforms to the plaintext data
39
+ data = _unencoded_transform(data)
40
+
41
+ self.encoded, self.key, self.fkey = encoder().find_key_and_encode(data, badchars)
42
+
43
+ # apply any transforms to the encoded data
44
+ self.encoded = _encoded_transform(encoded)
45
+
46
+ return _prepend() + encoded + _append()
47
+ end
48
+
49
+ protected
50
+ def _unencoded_transform(data) # :nodoc:
51
+ data
52
+ end
53
+
54
+ def _encoded_transform(data) # :nodoc:
55
+ data
56
+ end
57
+
58
+ def _prepend() # :nodoc:
59
+ ""
60
+ end
61
+
62
+ def _append() # :nodoc:
63
+ ""
64
+ end
65
+
66
+ end
67
+
68
+ end end
69
+
@@ -0,0 +1,13 @@
1
+ # -*- coding: binary -*-
2
+
3
+ require 'rex/encoder/xor'
4
+ require 'rex/encoding/xor/dword'
5
+
6
+ ###
7
+ #
8
+ # This class wraps the Dword XOR encoder.
9
+ #
10
+ ###
11
+ class Rex::Encoder::Xor::Dword < Rex::Encoder::Xor
12
+ EncoderKlass = Rex::Encoding::Xor::Dword
13
+ end
@@ -0,0 +1,13 @@
1
+ # -*- coding: binary -*-
2
+
3
+ require 'rex/encoder/xor'
4
+ require 'rex/encoding/xor/dword_additive'
5
+
6
+ ###
7
+ #
8
+ # This class wraps the Dword XOR Additive feedback encoder.
9
+ #
10
+ ###
11
+ class Rex::Encoder::Xor::DwordAdditive < Rex::Encoder::Xor
12
+ EncoderKlass = Rex::Encoding::Xor::DwordAdditive
13
+ end
@@ -0,0 +1,20 @@
1
+ # -*- coding: binary -*-
2
+
3
+ #
4
+ # make sure the namespace is created
5
+ #
6
+
7
+ module Rex
8
+ module Encoding
9
+ module Xor
10
+ end end end
11
+
12
+ #
13
+ # include the Xor encodings
14
+ #
15
+
16
+ require 'rex/encoding/xor/generic'
17
+ require 'rex/encoding/xor/byte'
18
+ require 'rex/encoding/xor/word'
19
+ require 'rex/encoding/xor/dword'
20
+ require 'rex/encoding/xor/qword'