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.
- checksums.yaml +7 -0
- checksums.yaml.gz.sig +1 -0
- data.tar.gz.sig +0 -0
- data/.gitignore +9 -0
- data/.rspec +2 -0
- data/.travis.yml +5 -0
- data/CODE_OF_CONDUCT.md +49 -0
- data/Gemfile +4 -0
- data/README.md +32 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/rex/encoder.rb +15 -0
- data/lib/rex/encoder/alpha2.rb +31 -0
- data/lib/rex/encoder/alpha2/alpha_mixed.rb +129 -0
- data/lib/rex/encoder/alpha2/alpha_upper.rb +138 -0
- data/lib/rex/encoder/alpha2/generic.rb +90 -0
- data/lib/rex/encoder/alpha2/unicode_mixed.rb +116 -0
- data/lib/rex/encoder/alpha2/unicode_upper.rb +123 -0
- data/lib/rex/encoder/bloxor/bloxor.rb +327 -0
- data/lib/rex/encoder/ndr.rb +90 -0
- data/lib/rex/encoder/nonalpha.rb +61 -0
- data/lib/rex/encoder/nonupper.rb +64 -0
- data/lib/rex/encoder/version.rb +5 -0
- data/lib/rex/encoder/xdr.rb +108 -0
- data/lib/rex/encoder/xor.rb +69 -0
- data/lib/rex/encoder/xor/dword.rb +13 -0
- data/lib/rex/encoder/xor/dword_additive.rb +13 -0
- data/lib/rex/encoding/xor.rb +20 -0
- data/lib/rex/encoding/xor/byte.rb +15 -0
- data/lib/rex/encoding/xor/dword.rb +21 -0
- data/lib/rex/encoding/xor/dword_additive.rb +92 -0
- data/lib/rex/encoding/xor/exceptions.rb +17 -0
- data/lib/rex/encoding/xor/generic.rb +146 -0
- data/lib/rex/encoding/xor/qword.rb +15 -0
- data/lib/rex/encoding/xor/word.rb +21 -0
- data/lib/rex/poly.rb +134 -0
- data/lib/rex/poly/block.rb +480 -0
- data/lib/rex/poly/machine.rb +13 -0
- data/lib/rex/poly/machine/machine.rb +830 -0
- data/lib/rex/poly/machine/x86.rb +509 -0
- data/lib/rex/poly/register.rb +101 -0
- data/lib/rex/poly/register/x86.rb +41 -0
- data/rex-encoder.gemspec +31 -0
- metadata +248 -0
- metadata.gz.sig +0 -0
@@ -0,0 +1,90 @@
|
|
1
|
+
# -*- coding: binary -*-
|
2
|
+
|
3
|
+
require 'rex/text'
|
4
|
+
|
5
|
+
module Rex
|
6
|
+
module Encoder
|
7
|
+
module Alpha2
|
8
|
+
|
9
|
+
class Generic
|
10
|
+
|
11
|
+
# Note: 'A' is presumed to be accepted, but excluded from the accepted characters, because it serves as the terminator
|
12
|
+
def Generic.default_accepted_chars ; ('a' .. 'z').to_a + ('B' .. 'Z').to_a + ('0' .. '9').to_a ; end
|
13
|
+
|
14
|
+
def Generic.gen_decoder_prefix(reg, offset)
|
15
|
+
# Should never happen - have to pick a specifc
|
16
|
+
# encoding:
|
17
|
+
# alphamixed, alphaupper, unicodemixed, unicodeupper
|
18
|
+
''
|
19
|
+
end
|
20
|
+
|
21
|
+
def Generic.gen_decoder(reg, offset)
|
22
|
+
# same as above
|
23
|
+
return ''
|
24
|
+
end
|
25
|
+
|
26
|
+
def Generic.gen_second(block, base)
|
27
|
+
# XOR encoder for ascii - unicode uses additive
|
28
|
+
(block^base)
|
29
|
+
end
|
30
|
+
|
31
|
+
def Generic.encode_byte(block, badchars)
|
32
|
+
accepted_chars = default_accepted_chars.dup
|
33
|
+
|
34
|
+
badchars.each_char {|c| accepted_chars.delete(c) } if badchars
|
35
|
+
|
36
|
+
# No, not nipple.
|
37
|
+
nibble_chars = Array.new(0x10) {[]}
|
38
|
+
accepted_chars.each {|c| nibble_chars[c.unpack('C')[0] & 0x0F].push(c) }
|
39
|
+
|
40
|
+
poss_encodings = []
|
41
|
+
|
42
|
+
block_low_nibble = block & 0x0F
|
43
|
+
block_high_nibble = block >> 4
|
44
|
+
|
45
|
+
# Get list of chars suitable for expressing lower part of byte
|
46
|
+
first_chars = nibble_chars[block_low_nibble]
|
47
|
+
|
48
|
+
# Build a list of possible encodings
|
49
|
+
first_chars.each do |first_char|
|
50
|
+
first_high_nibble = first_char.unpack('C')[0] >> 4
|
51
|
+
|
52
|
+
# In the decoding process, the low nibble of the second char gets combined
|
53
|
+
# (either ADDed or XORed depending on the encoder) with the high nibble of the first char,
|
54
|
+
# and we want the high nibble of our input byte to result
|
55
|
+
second_low_nibble = gen_second(block_high_nibble, first_high_nibble) & 0x0F
|
56
|
+
|
57
|
+
# Find valid second chars for this first char and add each combination to our possible encodings
|
58
|
+
second_chars = nibble_chars[second_low_nibble]
|
59
|
+
second_chars.each {|second_char| poss_encodings.push(second_char + first_char) }
|
60
|
+
end
|
61
|
+
|
62
|
+
if poss_encodings.empty?
|
63
|
+
raise RuntimeError, "No encoding of #{"0x%.2X" % block} possible with limited character set"
|
64
|
+
end
|
65
|
+
|
66
|
+
# Return a random encoding
|
67
|
+
poss_encodings[rand(poss_encodings.length)]
|
68
|
+
end
|
69
|
+
|
70
|
+
def Generic.encode(buf, reg, offset, badchars = '')
|
71
|
+
encoded = gen_decoder(reg, offset)
|
72
|
+
|
73
|
+
buf.each_byte {
|
74
|
+
|block|
|
75
|
+
|
76
|
+
encoded << encode_byte(block, badchars)
|
77
|
+
}
|
78
|
+
|
79
|
+
encoded << add_terminator()
|
80
|
+
|
81
|
+
return encoded
|
82
|
+
end
|
83
|
+
|
84
|
+
# 'A' signifies the end of the encoded shellcode
|
85
|
+
def Generic.add_terminator()
|
86
|
+
'AA'
|
87
|
+
end
|
88
|
+
|
89
|
+
end end end end
|
90
|
+
|
@@ -0,0 +1,116 @@
|
|
1
|
+
# -*- coding: binary -*-
|
2
|
+
|
3
|
+
require 'rex/encoder/alpha2/generic'
|
4
|
+
|
5
|
+
module Rex
|
6
|
+
module Encoder
|
7
|
+
module Alpha2
|
8
|
+
|
9
|
+
class UnicodeMixed < Generic
|
10
|
+
|
11
|
+
def self.gen_second(block, base)
|
12
|
+
# unicode uses additive encoding
|
13
|
+
(block - base)
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.gen_decoder_prefix(reg, offset)
|
17
|
+
if (offset > 21)
|
18
|
+
raise "Critical: Offset is greater than 21"
|
19
|
+
end
|
20
|
+
|
21
|
+
# offset untested for unicode :(
|
22
|
+
if (offset <= 14)
|
23
|
+
nop = 'CP' * offset
|
24
|
+
mod = 'IA' * (14 - offset) + nop # dec ecx,,, push ecx, pop edx
|
25
|
+
else
|
26
|
+
mod = 'AA' * (offset - 14) # inc ecx
|
27
|
+
nop = 'CP' * (14 - mod.length)
|
28
|
+
mod += nop
|
29
|
+
end
|
30
|
+
regprefix = { # nops ignored below
|
31
|
+
'EAX' => 'PPYA' + mod, # push eax, pop ecx
|
32
|
+
'ECX' => mod + "4444", # dec ecx
|
33
|
+
'EDX' => 'RRYA' + mod, # push edx, pop ecx
|
34
|
+
'EBX' => 'SSYA' + mod, # push ebx, pop ecx
|
35
|
+
'ESP' => 'TUYA' + mod, # push esp, pop ecx
|
36
|
+
'EBP' => 'UUYA' + mod, # push ebp, pop ecx
|
37
|
+
'ESI' => 'VVYA' + mod, # push esi, pop ecx
|
38
|
+
'EDI' => 'WWYA' + mod, # push edi, pop edi
|
39
|
+
}
|
40
|
+
|
41
|
+
prefix = regprefix[reg.upcase]
|
42
|
+
if prefix.nil?
|
43
|
+
raise "Critical: Invalid register"
|
44
|
+
end
|
45
|
+
|
46
|
+
return prefix
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.gen_decoder(reg, offset)
|
50
|
+
decoder =
|
51
|
+
gen_decoder_prefix(reg, offset) +
|
52
|
+
"j" + # push 0
|
53
|
+
"XA" + # pop eax, NOP
|
54
|
+
"QA" + # push ecx, NOP
|
55
|
+
"DA" + # inc esp, NOP
|
56
|
+
"ZA" + # pop edx, NOP
|
57
|
+
"BA" + # inc edx, NOP
|
58
|
+
"RA" + # push edx, NOP
|
59
|
+
"LA" + # dec esp, NOP
|
60
|
+
"YA" + # pop ecx, NOP
|
61
|
+
"IA" + # dec ecx, NOP
|
62
|
+
"QA" + # push ecx, NOP
|
63
|
+
"IA" + # dec ecx, NOP
|
64
|
+
"QA" + # push ecx, NOP
|
65
|
+
"IA" + # dec ecx, NOP
|
66
|
+
"hAAA" + # push 00410041, NOP
|
67
|
+
"Z" + # pop edx
|
68
|
+
"1A" + # add [ecx], dh NOP
|
69
|
+
"IA" + # dec ecx, NOP
|
70
|
+
"IA" + # dec ecx, NOP
|
71
|
+
"J" + # dec edx
|
72
|
+
"1" + # add [ecx], dh
|
73
|
+
"1A" + # add [ecx], dh NOP
|
74
|
+
"IA" + # dec ecx, NOP
|
75
|
+
"IA" + # dec ecx, NOP
|
76
|
+
"BA" + # inc edx, NOP
|
77
|
+
"BA" + # inc edx, NOP
|
78
|
+
"B" + # inc edx
|
79
|
+
"Q" + # add [ecx], dl
|
80
|
+
"I" + # dec ecx
|
81
|
+
"1A" + # add [ecx], dh NOP
|
82
|
+
"I" + # dec ecx
|
83
|
+
"Q" + # add [ecx], dl
|
84
|
+
"IA" + # dec ecx, NOP
|
85
|
+
"I" + # dec ecx
|
86
|
+
"Q" + # add [ecx], dh
|
87
|
+
"I" + # dec ecx
|
88
|
+
"1" + # add [ecx], dh
|
89
|
+
"1" + # add [ecx], dh
|
90
|
+
"1A" + # add [ecx], dh NOP
|
91
|
+
"IA" + # dec ecx, NOP
|
92
|
+
"J" + # dec edx
|
93
|
+
"Q" + # add [ecx], dl
|
94
|
+
"YA" + # pop ecx, NOP
|
95
|
+
"Z" + # pop edx
|
96
|
+
"B" + # add [edx], al
|
97
|
+
"A" + # inc ecx <-------
|
98
|
+
"B" + # add [edx], al |
|
99
|
+
"A" + # inc ecx |
|
100
|
+
"B" + # add [edx], al |
|
101
|
+
"A" + # inc ecx |
|
102
|
+
"B" + # add [edx], al |
|
103
|
+
"A" + # inc ecx |
|
104
|
+
"B" + # add [edx], al |
|
105
|
+
"kM" + # imul eax, [eax], 10 * |
|
106
|
+
"A" + # add [edx], al |
|
107
|
+
"G" + # inc edi |
|
108
|
+
"B" + # add [edx], al |
|
109
|
+
"9" + # cmp [eax], eax |
|
110
|
+
"u" + # jnz ------------------
|
111
|
+
"4JB"
|
112
|
+
|
113
|
+
return decoder
|
114
|
+
end
|
115
|
+
|
116
|
+
end end end end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
# -*- coding: binary -*-
|
2
|
+
|
3
|
+
require 'rex/encoder/alpha2/generic'
|
4
|
+
|
5
|
+
module Rex
|
6
|
+
module Encoder
|
7
|
+
module Alpha2
|
8
|
+
|
9
|
+
class UnicodeUpper < Generic
|
10
|
+
def self.default_accepted_chars ; ('B' .. 'Z').to_a + ('0' .. '9').to_a ; end
|
11
|
+
|
12
|
+
def self.gen_second(block, base)
|
13
|
+
# unicode uses additive encoding
|
14
|
+
(block - base)
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.gen_decoder_prefix(reg, offset)
|
18
|
+
if (offset > 6)
|
19
|
+
raise "Critical: Offset is greater than 6"
|
20
|
+
end
|
21
|
+
|
22
|
+
# offset untested for unicode :(
|
23
|
+
if (offset <= 4)
|
24
|
+
nop = 'CP' * offset
|
25
|
+
mod = 'IA' * (4 - offset) + nop # dec ecx,,, push ecx, pop edx
|
26
|
+
else
|
27
|
+
mod = 'AA' * (offset - 4) # inc ecx
|
28
|
+
nop = 'CP' * (4 - mod.length)
|
29
|
+
mod += nop
|
30
|
+
end
|
31
|
+
|
32
|
+
regprefix = { # nops ignored below
|
33
|
+
'EAX' => 'PPYA' + mod, # push eax, pop ecx
|
34
|
+
'ECX' => mod + '4444', # dec ecx
|
35
|
+
'EDX' => 'RRYA' + mod, # push edx, pop ecx
|
36
|
+
'EBX' => 'SSYA' + mod, # push ebx, pop ecx
|
37
|
+
'ESP' => 'TUYA' + mod, # push esp, pop ecx
|
38
|
+
'EBP' => 'UUYA' + mod, # push ebp, pop ecx
|
39
|
+
'ESI' => 'VVYA' + mod, # push esi, pop ecx
|
40
|
+
'EDI' => 'WWYA' + mod, # push edi, pop edi
|
41
|
+
'[ESP]' => 'YA' + mod + '44', #
|
42
|
+
'[ESP+4]' => 'YUYA' + mod, #
|
43
|
+
}
|
44
|
+
|
45
|
+
return regprefix[reg]
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.gen_decoder(reg, offset)
|
49
|
+
decoder =
|
50
|
+
gen_decoder_prefix(reg, offset) +
|
51
|
+
"QA" + # push ecx, NOP
|
52
|
+
"TA" + # push esp, NOP
|
53
|
+
"XA" + # pop eax, NOP
|
54
|
+
"ZA" + # pop edx, NOP
|
55
|
+
"PU" + # push eax, NOP
|
56
|
+
"3" + # xor eax, [eax]
|
57
|
+
"QA" + # push ecx, NOP
|
58
|
+
"DA" + # inc esp, NOP
|
59
|
+
"ZA" + # pop edx, NOP
|
60
|
+
"BA" + # inc edx, NOP
|
61
|
+
"RA" + # push edx, NOP
|
62
|
+
"LA" + # dec esp, NOP
|
63
|
+
"YA" + # pop ecx, NOP
|
64
|
+
"IA" + # dec ecx, NOP
|
65
|
+
"QA" + # push ecx, NOP
|
66
|
+
"IA" + # dec ecx, NOP
|
67
|
+
"QA" + # push ecx, NOP
|
68
|
+
"PA" + # push eax, NOP
|
69
|
+
"5AAA" + # xor eax, 41004100 - NOP
|
70
|
+
"PA" + # push eax, NOP
|
71
|
+
"Z" + # pop edx
|
72
|
+
"1A" + # add [ecx], dh - NOP
|
73
|
+
"I" + # dec ecx
|
74
|
+
"1A" + # add [ecx], dh - NOP
|
75
|
+
"IA" + # dec ecx, NOP
|
76
|
+
"IA" + # dec ecx, NOP
|
77
|
+
"J" + # dec edx
|
78
|
+
"1" + # add [ecx], dh
|
79
|
+
"1A" + # add [ecx], dh - NOP
|
80
|
+
"IA" + # dec ecx, NOP
|
81
|
+
"IA" + # dec ecx, NOP
|
82
|
+
"XA" + # pop eax, NOP
|
83
|
+
"58AA" + # xor eax, 41003800 - NOP
|
84
|
+
"PA" + # push eax, NOP
|
85
|
+
"ZA" + # pop edx, NOP
|
86
|
+
"BA" + # inc edx, NOP
|
87
|
+
"B" + # inc edx
|
88
|
+
"Q" + # add [ecx], dl
|
89
|
+
"I" + # dec ecx
|
90
|
+
"1A" + # add [ecx], dh - NOP
|
91
|
+
"I" + # dec ecx
|
92
|
+
"Q" + # add [ecx], dl
|
93
|
+
"IA" + # dec ecx, NOP
|
94
|
+
"I" + # dec ecx
|
95
|
+
"Q" + # add [ecx], dl
|
96
|
+
"I" + # dec ecx
|
97
|
+
"1" + # add [ecx], dh
|
98
|
+
"1" + # add [ecx], dh
|
99
|
+
"1" + # add [ecx], dh
|
100
|
+
"1A" + # add [ecx], dh - NOP
|
101
|
+
"IA" + # dec ecx, NOP
|
102
|
+
"J" + # dec edx
|
103
|
+
"Q" + # add [ecx], dl
|
104
|
+
"I" + # dec edx
|
105
|
+
"1A" + # add [ecx], dh - NOP
|
106
|
+
"YA" + # pop ecx, NOP
|
107
|
+
"ZB" + # pop edx, NOP
|
108
|
+
"AB" + # inc ecx, NOP <-------
|
109
|
+
"AB" + # inc ecx, NOP |
|
110
|
+
"AB" + # inc ecx, NOP |
|
111
|
+
"AB" + # inc ecx, NOP |
|
112
|
+
"30" + # imul eax, [ecx], 10 * |
|
113
|
+
"A" + # add al, [ecx+2] * |
|
114
|
+
"P" + # mov [edx], al * |
|
115
|
+
"B" + # inc edx |
|
116
|
+
"9" + # cmp [ecx], 41 * |
|
117
|
+
"4" + # jnz --------------------
|
118
|
+
"4JB"
|
119
|
+
|
120
|
+
return decoder
|
121
|
+
end
|
122
|
+
|
123
|
+
end end end end
|
@@ -0,0 +1,327 @@
|
|
1
|
+
# -*- coding: binary -*-
|
2
|
+
|
3
|
+
require 'rex/poly/machine'
|
4
|
+
|
5
|
+
module Rex
|
6
|
+
|
7
|
+
module Encoder
|
8
|
+
|
9
|
+
class BloXor < Msf::Encoder
|
10
|
+
|
11
|
+
def initialize( *args )
|
12
|
+
super
|
13
|
+
@machine = nil
|
14
|
+
@blocks_out = []
|
15
|
+
@block_size = 0
|
16
|
+
end
|
17
|
+
|
18
|
+
#
|
19
|
+
#
|
20
|
+
#
|
21
|
+
def decoder_stub( state )
|
22
|
+
|
23
|
+
if( not state.decoder_stub )
|
24
|
+
@blocks_out = []
|
25
|
+
@block_size = 0
|
26
|
+
|
27
|
+
# XXX: It would be ideal to use a random block size but unless we know the maximum size our final encoded
|
28
|
+
# blob can be we should instead start with the smallest block size and go up to avoid generating
|
29
|
+
# anything too big (if we knew the max size we could try something smaller if we generated a blob too big)
|
30
|
+
#block_sizes = (1..state.buf.length).to_a.shuffle
|
31
|
+
#block_sizes.each do | len |
|
32
|
+
|
33
|
+
1.upto( state.buf.length ) do | len |
|
34
|
+
|
35
|
+
# For now we ignore all odd sizes to help with performance (The rex poly machine
|
36
|
+
# doesnt have many load/store primitives that can handle byte sizes efficiently)
|
37
|
+
if( len % 2 != 0 )
|
38
|
+
next
|
39
|
+
end
|
40
|
+
|
41
|
+
blocks, size = compute_encoded( state, len )
|
42
|
+
if( blocks and size )
|
43
|
+
|
44
|
+
# We sanity check that the newly generated block ammount and the block size
|
45
|
+
# are not in the badchar list when converted into a hex form. Helps speed
|
46
|
+
# things up a great deal when generating a decoder stub later as these
|
47
|
+
# values may be used throughout.
|
48
|
+
|
49
|
+
if( not number_is_valid?( state, blocks.length - 1 ) or not number_is_valid?( state, ~( blocks.length - 1 ) ) )
|
50
|
+
next
|
51
|
+
end
|
52
|
+
|
53
|
+
if( not number_is_valid?( state, size ) or not number_is_valid?( state, ~size ) )
|
54
|
+
next
|
55
|
+
end
|
56
|
+
|
57
|
+
@blocks_out = blocks
|
58
|
+
@block_size = size
|
59
|
+
|
60
|
+
break
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
raise RuntimeError, "Unable to generate seed block." if( @blocks_out.empty? )
|
65
|
+
|
66
|
+
state.decoder_stub = compute_decoder( state )
|
67
|
+
end
|
68
|
+
|
69
|
+
state.decoder_stub
|
70
|
+
end
|
71
|
+
|
72
|
+
#
|
73
|
+
#
|
74
|
+
#
|
75
|
+
def encode_block( state, data )
|
76
|
+
|
77
|
+
buffer = ''
|
78
|
+
|
79
|
+
@blocks_out.each do | block |
|
80
|
+
buffer << block.pack( 'C*' )
|
81
|
+
end
|
82
|
+
|
83
|
+
buffer
|
84
|
+
end
|
85
|
+
|
86
|
+
protected
|
87
|
+
|
88
|
+
#
|
89
|
+
# Is a number in its byte form valid against the badchars?
|
90
|
+
#
|
91
|
+
def number_is_valid?( state, number )
|
92
|
+
size = 'C'
|
93
|
+
if( number > 0xFFFF )
|
94
|
+
size = 'V'
|
95
|
+
elsif( number > 0xFF )
|
96
|
+
size = 'v'
|
97
|
+
end
|
98
|
+
return Rex::Text.badchar_index( [ number ].pack( size ), state.badchars ).nil?
|
99
|
+
end
|
100
|
+
|
101
|
+
#
|
102
|
+
# Calculate Shannon's entropy.
|
103
|
+
#
|
104
|
+
def entropy( data )
|
105
|
+
entropy = 0.to_f
|
106
|
+
(0..255).each do | byte |
|
107
|
+
freq = data.to_s.count( byte.chr ).to_f / data.to_s.length
|
108
|
+
if( freq > 0 )
|
109
|
+
entropy -= freq * Math.log2( freq )
|
110
|
+
end
|
111
|
+
end
|
112
|
+
return entropy / 8
|
113
|
+
end
|
114
|
+
|
115
|
+
#
|
116
|
+
# Compute the encoded blocks (and associated seed)
|
117
|
+
#
|
118
|
+
def compute_encoded( state, len )
|
119
|
+
|
120
|
+
blocks_in = ::Array.new
|
121
|
+
|
122
|
+
input = '' << state.buf
|
123
|
+
|
124
|
+
block_padding = ( input.length % len ) > 0 ? len - ( input.length % len ) : 0
|
125
|
+
|
126
|
+
if( block_padding > 0 )
|
127
|
+
0.upto( block_padding-1 ) do
|
128
|
+
input << [ rand( 255 ) ].pack( 'C' )
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
while( input.length > 0 )
|
133
|
+
blocks_in << input[0..len-1].unpack( 'C*' )
|
134
|
+
input = input[len..input.length]
|
135
|
+
end
|
136
|
+
|
137
|
+
seed = compute_seed( blocks_in, len, block_padding, state.badchars.unpack( 'C*' ) )
|
138
|
+
|
139
|
+
if( not seed )
|
140
|
+
return [ nil, nil ]
|
141
|
+
end
|
142
|
+
|
143
|
+
blocks_out = [ seed ]
|
144
|
+
|
145
|
+
blocks_in.each do | block |
|
146
|
+
blocks_out << compute_block( blocks_out.last, block )
|
147
|
+
end
|
148
|
+
|
149
|
+
return [ blocks_out, len ]
|
150
|
+
end
|
151
|
+
|
152
|
+
#
|
153
|
+
# Generate the decoder stub which is functionally equivalent to the following:
|
154
|
+
#
|
155
|
+
# source = &end;
|
156
|
+
# dest = source + BLOCK_SIZE;
|
157
|
+
# counter = BLOCK_COUNT * ( BLOCK_SIZE / chunk_size );
|
158
|
+
# do
|
159
|
+
# {
|
160
|
+
# encoded = *(CHUNK_SIZE *)dest;
|
161
|
+
# dest += chunk_size;
|
162
|
+
# decoded = *(CHUNK_SIZE *)source;
|
163
|
+
# *(CHUNK_SIZE *)source = decoded ^ encoded;
|
164
|
+
# source += chunk_size;
|
165
|
+
# } while( --counter );
|
166
|
+
#
|
167
|
+
# end:
|
168
|
+
#
|
169
|
+
def compute_decoder( state )
|
170
|
+
|
171
|
+
@machine.create_variable( 'source' )
|
172
|
+
@machine.create_variable( 'dest' )
|
173
|
+
@machine.create_variable( 'counter' )
|
174
|
+
@machine.create_variable( 'encoded' )
|
175
|
+
@machine.create_variable( 'decoded' )
|
176
|
+
|
177
|
+
chunk_size = Rex::Poly::Machine::BYTE
|
178
|
+
if( @machine.native_size() == Rex::Poly::Machine::QWORD )
|
179
|
+
if( @block_size % Rex::Poly::Machine::QWORD == 0 )
|
180
|
+
chunk_size = Rex::Poly::Machine::QWORD
|
181
|
+
elsif( @block_size % Rex::Poly::Machine::DWORD == 0 )
|
182
|
+
chunk_size = Rex::Poly::Machine::DWORD
|
183
|
+
elsif( @block_size % Rex::Poly::Machine::WORD == 0 )
|
184
|
+
chunk_size = Rex::Poly::Machine::WORD
|
185
|
+
end
|
186
|
+
elsif( @machine.native_size() == Rex::Poly::Machine::DWORD )
|
187
|
+
if( @block_size % Rex::Poly::Machine::DWORD == 0 )
|
188
|
+
chunk_size = Rex::Poly::Machine::DWORD
|
189
|
+
elsif( @block_size % Rex::Poly::Machine::WORD == 0 )
|
190
|
+
chunk_size = Rex::Poly::Machine::WORD
|
191
|
+
end
|
192
|
+
elsif( @machine.native_size() == Rex::Poly::Machine::WORD )
|
193
|
+
if( @block_size % Rex::Poly::Machine::WORD == 0 )
|
194
|
+
chunk_size = Rex::Poly::Machine::WORD
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
# Block 1 - Set the source variable to the address of the start block
|
199
|
+
@machine.create_block_primitive( 'block1', 'set', 'source', 'location' )
|
200
|
+
|
201
|
+
# Block 2 - Set the source variable to the address of the 1st encoded block
|
202
|
+
@machine.create_block_primitive( 'block2', 'add', 'source', 'end' )
|
203
|
+
|
204
|
+
# Block 3 - Set the destingation variable to the value of the source variable
|
205
|
+
@machine.create_block_primitive( 'block3', 'set', 'dest', 'source' )
|
206
|
+
|
207
|
+
# Block 4 - Set the destingation variable to the address of the 2nd encoded block
|
208
|
+
@machine.create_block_primitive( 'block4', 'add', 'dest', @block_size )
|
209
|
+
|
210
|
+
# Block 5 - Sets the loop counter to the number of blocks to process
|
211
|
+
@machine.create_block_primitive( 'block5', 'set', 'counter', ( ( @block_size / chunk_size ) * (@blocks_out.length - 1) ) )
|
212
|
+
|
213
|
+
# Block 6 - Set the encoded variable to the byte pointed to by the dest variable
|
214
|
+
@machine.create_block_primitive( 'block6', 'load', 'encoded', 'dest', chunk_size )
|
215
|
+
|
216
|
+
# Block 7 - Increment the destination variable by one
|
217
|
+
@machine.create_block_primitive( 'block7', 'add', 'dest', chunk_size )
|
218
|
+
|
219
|
+
# Block 8 - Set the decoded variable to the byte pointed to by the source variable
|
220
|
+
@machine.create_block_primitive( 'block8', 'load', 'decoded', 'source', chunk_size )
|
221
|
+
|
222
|
+
# Block 9 - Xor the decoded variable with the encoded variable
|
223
|
+
@machine.create_block_primitive( 'block9', 'xor', 'decoded', 'encoded' )
|
224
|
+
|
225
|
+
# Block 10 - store the newly decoded byte
|
226
|
+
@machine.create_block_primitive( 'block10', 'store', 'source', 'decoded', chunk_size )
|
227
|
+
|
228
|
+
# Block 11 - Increment the source variable by one
|
229
|
+
@machine.create_block_primitive( 'block11', 'add', 'source', chunk_size )
|
230
|
+
|
231
|
+
# Block 12 - Jump back up to the outer_loop block while the counter variable > 0
|
232
|
+
@machine.create_block_primitive( 'block12', 'loop', 'counter', 'block6' )
|
233
|
+
|
234
|
+
# Try to generate the decoder stub...
|
235
|
+
decoder = @machine.generate
|
236
|
+
|
237
|
+
if( not decoder )
|
238
|
+
raise RuntimeError, "Unable to generate decoder stub."
|
239
|
+
end
|
240
|
+
|
241
|
+
decoder
|
242
|
+
end
|
243
|
+
|
244
|
+
#
|
245
|
+
# Compute the seed block which will successfully decode all proceeding encoded
|
246
|
+
# blocks while ensuring the encoded blocks do not contain any badchars.
|
247
|
+
#
|
248
|
+
def compute_seed( blocks_in, block_size, block_padding, badchars )
|
249
|
+
seed = []
|
250
|
+
redo_bytes = []
|
251
|
+
|
252
|
+
0.upto( block_size-1 ) do | index |
|
253
|
+
|
254
|
+
seed_bytes = (0..255).sort_by do
|
255
|
+
rand()
|
256
|
+
end
|
257
|
+
|
258
|
+
seed_bytes.each do | seed_byte |
|
259
|
+
|
260
|
+
next if( badchars.include?( seed_byte ) )
|
261
|
+
|
262
|
+
success = true
|
263
|
+
|
264
|
+
previous_byte = seed_byte
|
265
|
+
|
266
|
+
if( redo_bytes.length < 256 )
|
267
|
+
redo_bytes = (0..255).sort_by do
|
268
|
+
rand()
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
272
|
+
blocks_in.each do | block |
|
273
|
+
|
274
|
+
decoded_byte = block[ index ]
|
275
|
+
|
276
|
+
encoded_byte = previous_byte ^ decoded_byte
|
277
|
+
|
278
|
+
if( badchars.include?( encoded_byte ) )
|
279
|
+
# the padding bytes we added earlier can be changed if they are causing us to fail.
|
280
|
+
if( block == blocks_in.last and index >= (block_size-block_padding) )
|
281
|
+
if( redo_bytes.empty? )
|
282
|
+
success = false
|
283
|
+
break
|
284
|
+
end
|
285
|
+
block[ index ] = redo_bytes.shift
|
286
|
+
redo
|
287
|
+
end
|
288
|
+
|
289
|
+
success = false
|
290
|
+
break
|
291
|
+
end
|
292
|
+
|
293
|
+
previous_byte = encoded_byte
|
294
|
+
end
|
295
|
+
|
296
|
+
if( success )
|
297
|
+
seed << seed_byte
|
298
|
+
break
|
299
|
+
end
|
300
|
+
end
|
301
|
+
|
302
|
+
end
|
303
|
+
|
304
|
+
if( seed.length == block_size )
|
305
|
+
return seed
|
306
|
+
end
|
307
|
+
|
308
|
+
return nil
|
309
|
+
end
|
310
|
+
|
311
|
+
#
|
312
|
+
# Compute the next encoded block by xoring the previous
|
313
|
+
# encoded block with the next decoded block.
|
314
|
+
#
|
315
|
+
def compute_block( encoded, decoded )
|
316
|
+
block = []
|
317
|
+
0.upto( encoded.length-1 ) do | index |
|
318
|
+
block << ( encoded[ index ] ^ decoded[ index ] )
|
319
|
+
end
|
320
|
+
return block
|
321
|
+
end
|
322
|
+
|
323
|
+
end
|
324
|
+
|
325
|
+
end
|
326
|
+
|
327
|
+
end
|