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,13 @@
1
+ # -*- coding: binary -*-
2
+
3
+ module Rex
4
+
5
+ module Poly
6
+
7
+ require 'metasm'
8
+ require 'rex/poly/machine/machine'
9
+ require 'rex/poly/machine/x86'
10
+
11
+ end
12
+
13
+ end
@@ -0,0 +1,830 @@
1
+ # -*- coding: binary -*-
2
+
3
+ module Rex
4
+
5
+ module Poly
6
+
7
+ #
8
+ # A machine capable of creating a small blob of code in a metamorphic kind of way.
9
+ # Note: this is designed to perform an exhaustive search for a solution and can be
10
+ # slow. If you need a speedier option, the origional Rex::Polly::Block stuff is a
11
+ # better choice.
12
+ #
13
+ class Machine
14
+
15
+ QWORD = 8
16
+ DWORD = 4
17
+ WORD = 2
18
+ BYTE = 1
19
+
20
+ #
21
+ # A Permutation!
22
+ #
23
+ class Permutation
24
+
25
+ attr_accessor :active, :offset
26
+
27
+ attr_reader :name, :primitive, :length, :args
28
+
29
+ #
30
+ # Create a new permutation object.
31
+ #
32
+ def initialize( name, primitive, machine, source, args=nil )
33
+ @name = name
34
+ @primitive = primitive
35
+ @machine = machine
36
+ @source = source
37
+ @args = args
38
+ @active = false
39
+ @valid = true
40
+ @length = 0
41
+ @offset = 0
42
+ @children = ::Array.new
43
+ end
44
+
45
+ #
46
+ # Add in a child permutation to this one. Used to build the permutation tree.
47
+ #
48
+ def add_child( child )
49
+ @children << child
50
+ end
51
+
52
+ #
53
+ # Does this permutation have children?
54
+ #
55
+ def has_children?
56
+ not @children.empty?
57
+ end
58
+
59
+ #
60
+ # Remove any existing children. Called by the machines generate function
61
+ # to build a fresh tree in case generate was previously called.
62
+ #
63
+ def remove_children
64
+ @children.clear
65
+ end
66
+
67
+ #
68
+ # Actully render this permutation into a raw buffer.
69
+ #
70
+ def render
71
+ raw = ''
72
+ # Zero the length as we will be rendering the raw buffer and the length may change.
73
+ @length = 0
74
+ # If this permutation source is a Primitive/Procedure we can call it, otherwise we have a string
75
+ if( @source.kind_of?( Primitive ) or @source.kind_of?( ::Proc ) )
76
+ if( @source.kind_of?( Primitive ) )
77
+ raw = @source.call( @name, @machine, *@args )
78
+ elsif( @source.kind_of?( ::Proc ) )
79
+ raw = @source.call
80
+ end
81
+ # If the primitive/procedure returned an array, it is an array of assembly strings which we can assemble.
82
+ if( raw.kind_of?( ::Array ) )
83
+ lines = raw
84
+ raw = ''
85
+ # itterate over each line of assembly
86
+ lines.each do | asm |
87
+ # parse the asm and substitute in any offset values specified...
88
+ offsets = asm.scan( /:([\S]+)_offset/ )
89
+ offsets.each do | name, |
90
+ asm = asm.gsub( ":#{name}_offset", @machine.block_offset( name ).to_s )
91
+ end
92
+ # and substitute in and register values for any variables specified...
93
+ regs = asm.scan( /:([\S]+)_reg([\d]+)/ )
94
+ regs.each do | name, size |
95
+ asm = asm.gsub( ":#{name}_reg#{size}", @machine.variable_value( name, size.to_i ) )
96
+ end
97
+ # assemble it into a raw blob
98
+ blob = @machine.assemble( asm )
99
+ #if( not @machine.is_valid?( blob ) )
100
+ # p "#{name}(#{primitive}):#{asm} is invalid"
101
+ #end
102
+ raw << blob
103
+ end
104
+ end
105
+ else
106
+ # the source must just be a static string
107
+ raw = @source
108
+ end
109
+ # Update the length to reflect the new raw buffer
110
+ @length = raw.to_s.length
111
+ # As the temp variable is only assigned for the duration of a single permutation we
112
+ # can now release it if it was used in this permutation.
113
+ @machine.release_temp_variable
114
+ return raw.to_s
115
+ end
116
+
117
+ #
118
+ # Test if this permutation raw buffer is valid in this machine (e.g. against the badchar list).
119
+ #
120
+ def is_valid?
121
+ result = false
122
+ if( @valid )
123
+ begin
124
+ result = @machine.is_valid?( self.render )
125
+ rescue UnallowedPermutation
126
+ # This permutation is unallowed and can never be rendered so just mark it as
127
+ # not valid to skip it during future attempts.
128
+ @valid = false
129
+ rescue UndefinedPermutation
130
+ # allow an undefined permutation to fail validation but keep it marked
131
+ # as valid as it may be defined and passed validation later.
132
+ ensure
133
+ # Should a temporary variable have been assigned we can release it here.
134
+ @machine.release_temp_variable
135
+ end
136
+ end
137
+ return result
138
+ end
139
+
140
+ #
141
+ # Try to find a solution within the solution space by performing a depth first search
142
+ # into the permutation tree and backtracking when needed.
143
+ #
144
+ def solve
145
+ # Check to see if this permutation can make part of a valid solution
146
+ if( self.is_valid? )
147
+ # record this permutation as part of the final solution (the current machines register state is also saved here)
148
+ @machine.solution_push( self )
149
+ # If we have no children we are at the end of the tree and have a potential full solution.
150
+ if( not self.has_children? )
151
+ # We have a solution but doing a final pass to update offsets may introduce bad chars
152
+ # so we test for this and keep searching if this isnt a real solution after all.
153
+ if( not @machine.solution_is_valid? )
154
+ # remove this permutation and keep searching
155
+ @machine.solution_pop
156
+ return false
157
+ end
158
+ # Return true to unwind the recursive call as we have got a final solution.
159
+ return true
160
+ end
161
+ # Itterate over the children of this permutation (the perutations of the proceeding block).
162
+ @children.each do | child |
163
+ # Traverse into this child to keep trying to generate a solution...
164
+ if( child.solve )
165
+ # Keep returning true to unwind as we are done.
166
+ return true
167
+ end
168
+ end
169
+ # If we get here this permutation, origionally thought to be good for a solution, is not after all,
170
+ # so remove it from the machines final solution, restoring the register state aswell.
171
+ @machine.solution_pop
172
+ end
173
+ # No children can be made form part of the solution, return failure for this path in the tree.
174
+ return false
175
+ end
176
+
177
+ end
178
+
179
+ #
180
+ # A symbolic permutation to mark locations like the begining and end of a group of blocks.
181
+ # Used to calculate usefull offsets.
182
+ #
183
+ class SymbolicPermutation < Permutation
184
+ def initialize( name, machine, initial_offset=0 )
185
+ super( name, '', machine, '' )
186
+ # fudge the initial symbolic offset with a default (it gets patched correctly later),
187
+ # helps with the end symbolic block to not be 0 (as its a forward reference it really
188
+ # slows things down if we leave it 0)
189
+ @offset = initial_offset
190
+ # A symbolic block is allways active!
191
+ @active = true
192
+ end
193
+
194
+ #
195
+ # We block all attempts to set the active state of this permutation so as
196
+ # it is always true. This lets us always address the offset.
197
+ #
198
+ def active=( value )
199
+ end
200
+ end
201
+
202
+ #
203
+ # A primitive is a machine defined permutation which accepts some arguments when it is called.
204
+ #
205
+ class Primitive
206
+
207
+ #
208
+ # Initialize this primitive with its target source procedure and the machine it belongs to.
209
+ #
210
+ def initialize( source )
211
+ @source = source
212
+ end
213
+
214
+ #
215
+ # Call the primitives source procedure, passing in the arguments.
216
+ #
217
+ def call( name, machine, *args )
218
+ return @source.call( name, machine, *args )
219
+ end
220
+
221
+ end
222
+
223
+ #
224
+ #
225
+ #
226
+ class Block
227
+
228
+ #attr_accessor :next, :previous
229
+ attr_reader :name
230
+
231
+ def initialize( name )
232
+ @name = name
233
+ @next = nil
234
+ @previous = nil
235
+ @permutations = ::Array.new
236
+ end
237
+
238
+ def shuffle
239
+ @permutations = @permutations.shuffle
240
+ end
241
+
242
+ def solve
243
+ @permutations.first.solve
244
+ end
245
+
246
+ def << ( permutation )
247
+ @permutations << permutation
248
+ end
249
+
250
+ def each
251
+ @permutations.each do | permutation |
252
+ yield permutation
253
+ end
254
+ end
255
+
256
+ end
257
+
258
+ #
259
+ # A class to hold a solution for a Rex::Poly::Machine problem.
260
+ #
261
+ class Solution
262
+
263
+ attr_reader :offset
264
+
265
+ def initialize
266
+ @permutations = ::Array.new
267
+ @reg_state = ::Array.new
268
+ @offset = 0
269
+ end
270
+
271
+ #
272
+ # Reset this solution to an empty state.
273
+ #
274
+ def reset
275
+ @offset = 0
276
+ @permutations.each do | permutation |
277
+ permutation.active = false
278
+ permutation.offset = 0
279
+ end
280
+ @permutations.clear
281
+ @reg_state.clear
282
+ end
283
+
284
+ #
285
+ # Push a new permutation onto this solutions permutations list and save the associated register/variables state
286
+ #
287
+ def push( permutation, reg_available, reg_consumed, variables )
288
+ permutation.active = true
289
+ permutation.offset = @offset
290
+ @offset += permutation.length
291
+ @permutations.push( permutation )
292
+ @reg_state.push( [ [].concat(reg_available), [].concat(reg_consumed), {}.merge(variables) ] )
293
+ end
294
+
295
+ #
296
+ # Pop off the last permutaion and register/variables state from this solution.
297
+ #
298
+ def pop
299
+ reg_available, reg_consumed, variables = @reg_state.pop
300
+ permutation = @permutations.pop
301
+ permutation.active = false
302
+ permutation.offset = 0
303
+ @offset -= permutation.length
304
+ return permutation, reg_available, reg_consumed, variables
305
+ end
306
+
307
+ #
308
+ # Render the final buffer.
309
+ #
310
+ def buffer
311
+ previous_offset = nil
312
+ count = 0
313
+ # perform an N-pass fixup for offsets...
314
+ while( true ) do
315
+ # If we cant get the offsets fixed within a fixed ammount of tries we return
316
+ # nil to indicate failure and keep searching for a solution that will work.
317
+ if( count > 64 )
318
+ return nil
319
+ end
320
+ # Reset the solution offset so as to update it for this pass
321
+ @offset = 0
322
+ # perform a single pass to ensure we are using the correct offset values
323
+ @permutations.each do | permutation |
324
+ permutation.offset = @offset
325
+ # Note: calling render() can throw both UndefinedPermutation and UnallowedPermutation exceptions,
326
+ # however as we assume we only ever return the buffer once a final solution has been generated
327
+ # we should never have either of those exceptions thrown.
328
+ permutation.render
329
+ @offset += permutation.length
330
+ end
331
+ # If we have generated two consecutive passes which are the same length we can stop fixing up the offsets.
332
+ if( not previous_offset.nil? and @offset == previous_offset )
333
+ break
334
+ end
335
+ count +=1
336
+ previous_offset = @offset
337
+ end
338
+ # now a final pass to render the solution into the raw buffer
339
+ raw = ''
340
+ @permutations.each do | permutation |
341
+ #$stderr.puts "#{permutation.name} - #{ "0x%08X (%d)" % [ permutation.offset, permutation.length] } "
342
+ raw << permutation.render
343
+ end
344
+ return raw
345
+ end
346
+
347
+ end
348
+
349
+ #
350
+ # Create a new machine instance.
351
+ #
352
+ def initialize( badchars, cpu )
353
+ @badchars = badchars
354
+ @cpu = cpu
355
+
356
+ @reg_available = ::Array.new
357
+ @reg_consumed = ::Array.new
358
+ @variables = ::Hash.new
359
+ @blocks = ::Hash.new
360
+ @primitives = ::Hash.new
361
+ @solution = Solution.new
362
+
363
+ _create_primitives
364
+
365
+ @blocks['begin'] = Block.new( 'begin' )
366
+ @blocks['begin'] << SymbolicPermutation.new( 'begin', self )
367
+
368
+ _create_variable( 'temp' )
369
+ end
370
+
371
+ #
372
+ # Overloaded by a subclass to return the maximum native general register size supported.
373
+ #
374
+ def native_size
375
+ nil
376
+ end
377
+
378
+ #
379
+ # Use METASM to assemble a line of asm using this machines current cpu.
380
+ #
381
+ def assemble( asm )
382
+ return Metasm::Shellcode.assemble( @cpu, asm ).encode_string
383
+ end
384
+
385
+ #
386
+ # Check if a data blob is valid against the badchar list (or perform any other validation here)
387
+ #
388
+ def is_valid?( data )
389
+ if( data.nil? )
390
+ return false
391
+ end
392
+ return Rex::Text.badchar_index( data, @badchars ).nil?
393
+ end
394
+
395
+ #
396
+ # Generate a 64 bit number whoes bytes are valid in this machine.
397
+ #
398
+ def make_safe_qword( number=nil )
399
+ return _make_safe_number( QWORD, number ) & 0xFFFFFFFFFFFFFFFF
400
+ end
401
+
402
+ #
403
+ # Generate a 32 bit number whoes bytes are valid in this machine.
404
+ #
405
+ def make_safe_dword( number=nil )
406
+ return _make_safe_number( DWORD, number ) & 0xFFFFFFFF
407
+ end
408
+
409
+ #
410
+ # Generate a 16 bit number whoes bytes are valid in this machine.
411
+ #
412
+ def make_safe_word( number=nil )
413
+ return _make_safe_number( WORD, number ) & 0xFFFF
414
+ end
415
+
416
+ #
417
+ # Generate a 8 bit number whoes bytes are valid in this machine.
418
+ #
419
+ def make_safe_byte( number=nil )
420
+ return _make_safe_number( BYTE, number ) & 0xFF
421
+ end
422
+
423
+ #
424
+ # Create a variable by name which will be assigned a register during generation. We can
425
+ # optionally assign a static register value to a variable if needed.
426
+ #
427
+ def create_variable( name, reg=nil )
428
+ # Sanity check we aren't trying to create one of the reserved variables.
429
+ if( name == 'temp' )
430
+ raise RuntimeError, "Unable to create variable, '#{name}' is a reserved variable name."
431
+ end
432
+ return _create_variable( name, reg )
433
+ end
434
+
435
+ #
436
+ # If the temp variable was assigned we release it.
437
+ #
438
+ def release_temp_variable
439
+ if( @variables['temp'] )
440
+ regnum = @variables['temp']
441
+ # Sanity check the temp variable was actually assigned (it may not have been if the last permutation didnot use it)
442
+ if( regnum )
443
+ # place the assigned register back in the available list for consumption later.
444
+ @reg_available.push( @reg_consumed.delete( regnum ) )
445
+ # unasign the temp vars register
446
+ @variables['temp'] = nil
447
+ return true
448
+ end
449
+ end
450
+ return false
451
+ end
452
+
453
+ #
454
+ # Resolve a variable name into its currently assigned register value.
455
+ #
456
+ def variable_value( name, size=nil )
457
+ # Sanity check we this variable has been created
458
+ if( not @variables.has_key?( name ) )
459
+ raise RuntimeError, "Unknown register '#{name}'."
460
+ end
461
+ # Pull out its current register value if it has been assigned one
462
+ regnum = @variables[ name ]
463
+ if( not regnum )
464
+ regnum = @reg_available.pop
465
+ if( not regnum )
466
+ raise RuntimeError, "Unable to assign variable '#{name}' a register value, none available."
467
+ end
468
+ # and add it to the consumed list so we can track it later
469
+ @reg_consumed << regnum
470
+ # and now assign the variable the register
471
+ @variables[ name ] = regnum
472
+ end
473
+ # resolve the register number int a string representation (e.g. 0 in x86 is EAX if size is 32)
474
+ return _register_value( regnum, size )
475
+ end
476
+
477
+ #
478
+ # Check this solution is still currently valid (as offsets change it may not be).
479
+ #
480
+ def solution_is_valid?
481
+ return self.is_valid?( @solution.buffer )
482
+ end
483
+
484
+ #
485
+ # As the solution advances we save state for each permutation step in the solution. This lets
486
+ # use rewind at a later stage if the solving algorithm wishes to perform some backtracking.
487
+ #
488
+ def solution_push( permutation )
489
+ @solution.push( permutation, @reg_available, @reg_consumed, @variables )
490
+ end
491
+
492
+ #
493
+ # Backtrack one step in the solution and restore the register/variable state.
494
+ #
495
+ def solution_pop
496
+ permutation, @reg_available, @reg_consumed, @variables = @solution.pop
497
+
498
+ @reg_available.push( @reg_available.shift )
499
+ end
500
+
501
+ #
502
+ # Create a block by name and add in its list of permutations.
503
+ #
504
+ # XXX: this doesnt support the fuzzy order of block dependencies ala the origional rex::poly
505
+ def create_block( name, *permutation_sources )
506
+ # Sanity check we aren't trying to create one of the reserved symbolic blocks.
507
+ if( name == 'begin' or name == 'end' )
508
+ raise RuntimeError, "Unable to add block, '#{name}' is a reserved block name."
509
+ end
510
+ # If this is the first time this block is being created, create the block object to hold the permutation list
511
+ if( not @blocks[name] )
512
+ @blocks[name] = Block.new( name )
513
+ end
514
+ # Now create a new permutation object for every one supplied.
515
+ permutation_sources.each do | source |
516
+ @blocks[name] << Permutation.new( name, '', self, source )
517
+ end
518
+ return name
519
+ end
520
+
521
+ #
522
+ # Create a block which is based on a primitive defined by this machine.
523
+ #
524
+ def create_block_primitive( block_name, primitive_name, *args )
525
+ # Santiy check this primitive is actually available and is not an internal primitive (begins with an _).
526
+ if( not @primitives[primitive_name] or primitive_name[0] == "_" )
527
+ raise RuntimeError, "Unable to add block, Primitive '#{primitive_name}' is not available."
528
+ end
529
+ # Sanity check we aren't trying to create one of the reserved symbolic blocks.
530
+ if( block_name == 'begin' or block_name == 'end' )
531
+ raise RuntimeError, "Unable to add block, '#{block_name}' is a reserved block name."
532
+ end
533
+ return _create_block_primitive( block_name, primitive_name, *args )
534
+ end
535
+
536
+ #
537
+ # Get the offset for a blocks active permutation. This is easy for backward references as
538
+ # they will already have been rendered and their sizes known. For forward references we
539
+ # can't know in advance but the correct value can be known later once the final solution is
540
+ # available and a final pass to generate the raw buffer is made.
541
+ #
542
+ def block_offset( name )
543
+ if( name == 'end' )
544
+ return @solution.offset
545
+ elsif( @blocks[name] )
546
+ @blocks[name].each do | permutation |
547
+ if( permutation.active )
548
+ return permutation.offset
549
+ end
550
+ end
551
+ end
552
+ # If we are forward referencing a block it will be at least the current solutions offset +1
553
+ return @solution.offset + 1
554
+ end
555
+
556
+ #
557
+ # Does a given block exist?
558
+ #
559
+ def block_exist?( name )
560
+ return @blocks.include?( name )
561
+ end
562
+
563
+ #
564
+ # Does a given block exist?
565
+ #
566
+ def variable_exist?( name )
567
+ return @variables.include?( name )
568
+ end
569
+
570
+ # XXX: ambiguity between variable names and block name may introduce confusion!!! make them be unique.
571
+
572
+ #
573
+ # Resolve a given value into either a number literal, a block offset or
574
+ # a variables assigned register.
575
+ #
576
+ def resolve_value( value, size=nil )
577
+ if( block_exist?( value ) )
578
+ return block_offset( value )
579
+ elsif( variable_exist?( value ) )
580
+ return variable_value( value, size )
581
+ end
582
+ return value.to_i
583
+ end
584
+
585
+ #
586
+ # Get the block previous to the target block.
587
+ #
588
+ def block_previous( target_block )
589
+ previous_block = nil
590
+ @blocks.each_key do | current_block |
591
+ if( current_block == target_block )
592
+ return previous_block
593
+ end
594
+ previous_block = current_block
595
+ end
596
+ return nil
597
+ end
598
+
599
+ #
600
+ # Get the block next to the target block.
601
+ #
602
+ def block_next( target_block )
603
+ @blocks.each_key do | current_block |
604
+ if( block_previous( current_block ) == target_block )
605
+ return current_block
606
+ end
607
+ end
608
+ return nil
609
+ end
610
+
611
+ #
612
+ # Try to generate a solution.
613
+ #
614
+ def generate
615
+
616
+ if( @blocks.has_key?( 'end' ) )
617
+ @blocks.delete( 'end' )
618
+ end
619
+
620
+ @blocks['end'] = Block.new( 'end' )
621
+ @blocks['end'] << SymbolicPermutation.new( 'end', self, 1 )
622
+
623
+ # Mix up the permutation orders for each block and create the tree structure.
624
+ previous = ::Array.new
625
+ @blocks.each_value do | block |
626
+ # Shuffle the order of the blocks permutations.
627
+ block.shuffle
628
+ # create the tree by adding the current blocks permutations as children of the previous block.
629
+ current = ::Array.new
630
+ block.each do | permutation |
631
+ permutation.remove_children
632
+ previous.each do | prev |
633
+ prev.add_child( permutation )
634
+ end
635
+ current << permutation
636
+ end
637
+ previous = current
638
+ end
639
+
640
+ # Shuffle the order of the available registers
641
+ @reg_available = @reg_available.shuffle
642
+
643
+ # We must try every permutation of the register orders, so if we fail to
644
+ # generate a solution we rotate the available registers to try again with
645
+ # a different order. This ensures we perform and exhaustive search.
646
+ 0.upto( @reg_available.length - 1 ) do
647
+
648
+ @solution.reset
649
+
650
+ # Start from the root node in the solution space and generate a
651
+ # solution by traversing the solution space's tree structure.
652
+ if( @blocks['begin'].solve )
653
+ # Return the solutions buffer (perform a last pass to fixup all offsets)...
654
+ return @solution.buffer
655
+ end
656
+
657
+ @reg_available.push( @reg_available.shift )
658
+ end
659
+
660
+ # :(
661
+ nil
662
+ end
663
+
664
+ #
665
+ # An UndefinedPermutation exception is raised when a permutation can't render yet
666
+ # as the conditions required are not yet satisfied.
667
+ #
668
+ class UndefinedPermutation < RuntimeError
669
+ def initialize( msg=nil )
670
+ super
671
+ end
672
+ end
673
+
674
+ #
675
+ # An UnallowedPermutation exception is raised when a permutation can't ever render
676
+ # as the conditions supplied are impossible to satisfy.
677
+ #
678
+ class UnallowedPermutation < RuntimeError
679
+ def initialize( msg=nil )
680
+ super
681
+ end
682
+ end
683
+
684
+ #
685
+ # An InvalidPermutation exception is raised when a permutation receives a invalid
686
+ # argument and cannot continue to render. This is a fatal exception.
687
+ #
688
+ class InvalidPermutation < RuntimeError
689
+ def initialize( msg=nil )
690
+ super
691
+ end
692
+ end
693
+
694
+ protected
695
+
696
+ #
697
+ # Overloaded by a subclass to resolve a register number into a suitable register
698
+ # name for the target architecture. E.g on x64 the register number 0 with size 64
699
+ # would resolve to RCX. Size is nil by default to indicate we want the default
700
+ # machine size, e.g. 32bit DWORD on x86 or 64bit QWORD on x64.
701
+ #
702
+ def _register_value( regnum, size=nil )
703
+ nil
704
+ end
705
+
706
+ #
707
+ # Perform the actual variable creation.
708
+ #
709
+ def _create_variable( name, reg=nil )
710
+ regnum = nil
711
+ # Sanity check this variable has not already been created.
712
+ if( @variables[name] )
713
+ raise RuntimeError, "Variable '#{name}' is already created."
714
+ end
715
+ # If a fixed register is being assigned to this variable then resolve it
716
+ if( reg )
717
+ # Resolve the register name into a register number
718
+ @reg_available.each do | num |
719
+ if( _register_value( num ) == reg.downcase )
720
+ regnum = num
721
+ break
722
+ end
723
+ end
724
+ # If an invalid register name was given or the chosen register is not available we must fail.
725
+ if( not regnum )
726
+ raise RuntimeError, "Register '#{reg}' is unknown or unavailable."
727
+ end
728
+ # Sanity check another variable isnt assigned this register
729
+ if( @variables.has_value?( regnum ) )
730
+ raise RuntimeError, "Register number '#{regnum}' is already consumed by variable '#{@variables[name]}'."
731
+ end
732
+ # Finally we consume the register chosen so we dont select it again later.
733
+ @reg_consumed << @reg_available.delete( regnum )
734
+ end
735
+ # Create the variable and assign it a register number (or nil if not yet assigned)
736
+ @variables[name] = regnum
737
+ return name
738
+ end
739
+
740
+ #
741
+ # Create a block which is based on a primitive defined by this machine.
742
+ #
743
+ def _create_block_primitive( block_name, primitive_name, *args )
744
+ # If this is the first time this block is being created, create the array to hold the permutation list
745
+ if( not @blocks[block_name] )
746
+ @blocks[block_name] = Block.new( block_name )
747
+ end
748
+ # Now create a new permutation object for every one supplied.
749
+ @primitives[primitive_name].each do | source |
750
+ @blocks[block_name] << Permutation.new( block_name, primitive_name, self, source, args )
751
+ end
752
+ return block_name
753
+ end
754
+
755
+ #
756
+ # Overloaded by a subclass to create any primitives available in this machine.
757
+ #
758
+ def _create_primitives
759
+ nil
760
+ end
761
+
762
+ #
763
+ # Rex::Poly::Machine::Primitive
764
+ #
765
+ def _create_primitive( name, *permutations )
766
+ # If this is the first time this primitive is being created, create the array to hold the permutation list
767
+ if( not @primitives[name] )
768
+ @primitives[name] = ::Array.new
769
+ end
770
+ # Add in the permutation object (Rex::Poly::Machine::Primitive) for every one supplied.
771
+ permutations.each do | permutation |
772
+ @primitives[name] << Primitive.new( permutation )
773
+ end
774
+ end
775
+
776
+ #
777
+ # Helper function to generate a number whoes byte representation is valid in this
778
+ # machine (does not contain any badchars for example). Optionally we can supply a
779
+ # number and the resulting addition/subtraction of this number against the newly
780
+ # generated value is also tested for validity. This helps in the assembly primitives
781
+ # which can use these values.
782
+ #
783
+ def _make_safe_number( bytes, number=nil )
784
+ format = ''
785
+ if( bytes == BYTE )
786
+ format = 'C'
787
+ elsif( bytes == WORD )
788
+ format = 'v'
789
+ elsif( bytes == DWORD )
790
+ format = 'V'
791
+ elsif( bytes == QWORD )
792
+ format = 'Q'
793
+ else
794
+ raise RuntimeError, "Invalid size '#{bytes}' used in _make_safe_number."
795
+ end
796
+
797
+ goodchars = (0..255).to_a
798
+
799
+ @badchars.unpack( 'C*' ).each do | b |
800
+ goodchars.delete( b.chr )
801
+ end
802
+
803
+ while( true ) do
804
+ value = 0
805
+
806
+ 0.upto( bytes-1 ) do | i |
807
+ value |= ( (goodchars[ rand(goodchars.length) ] << i*8) & (0xFF << i*8) )
808
+ end
809
+
810
+ if( not is_valid?( [ value ].pack(format) ) or not is_valid?( [ ~value ].pack(format) ) )
811
+ redo
812
+ end
813
+
814
+ if( not number.nil? )
815
+ if( not is_valid?( [ value + number ].pack(format) ) or not is_valid?( [ value - number ].pack(format) ) )
816
+ redo
817
+ end
818
+ end
819
+
820
+ break
821
+ end
822
+
823
+ return value
824
+ end
825
+
826
+ end
827
+
828
+ end
829
+
830
+ end