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
+
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