class Rex::Poly::Machine::Permutation
A Permutation
!
Attributes
active[RW]
args[R]
length[R]
name[R]
offset[RW]
primitive[R]
Public Class Methods
new( name, primitive, machine, source, args=nil )
click to toggle source
Create a new permutation object.
# File lib/rex/poly/machine/machine.rb, line 31 def initialize( name, primitive, machine, source, args=nil ) @name = name @primitive = primitive @machine = machine @source = source @args = args @active = false @valid = true @length = 0 @offset = 0 @children = ::Array.new end
Public Instance Methods
add_child( child )
click to toggle source
Add in a child permutation to this one. Used to build the permutation tree.
# File lib/rex/poly/machine/machine.rb, line 47 def add_child( child ) @children << child end
has_children?()
click to toggle source
Does this permutation have children?
# File lib/rex/poly/machine/machine.rb, line 54 def has_children? not @children.empty? end
is_valid?()
click to toggle source
Test if this permutation raw buffer is valid in this machine (e.g. against the badchar list).
# File lib/rex/poly/machine/machine.rb, line 119 def is_valid? result = false if( @valid ) begin result = @machine.is_valid?( self.render ) rescue UnallowedPermutation # This permutation is unallowed and can never be rendered so just mark it as # not valid to skip it during future attempts. @valid = false rescue UndefinedPermutation # allow an undefined permutation to fail validation but keep it marked # as valid as it may be defined and passed validation later. ensure # Should a temporary variable have been assigned we can release it here. @machine.release_temp_variable end end return result end
remove_children()
click to toggle source
Remove any existing children. Called by the machines generate function to build a fresh tree in case generate was previously called.
# File lib/rex/poly/machine/machine.rb, line 62 def remove_children @children.clear end
render()
click to toggle source
Actully render this permutation into a raw buffer.
# File lib/rex/poly/machine/machine.rb, line 69 def render raw = '' # Zero the length as we will be rendering the raw buffer and the length may change. @length = 0 # If this permutation source is a Primitive/Procedure we can call it, otherwise we have a string if( @source.kind_of?( Primitive ) or @source.kind_of?( ::Proc ) ) if( @source.kind_of?( Primitive ) ) raw = @source.call( @name, @machine, *@args ) elsif( @source.kind_of?( ::Proc ) ) raw = @source.call end # If the primitive/procedure returned an array, it is an array of assembly strings which we can assemble. if( raw.kind_of?( ::Array ) ) lines = raw raw = '' # itterate over each line of assembly lines.each do | asm | # parse the asm and substitute in any offset values specified... offsets = asm.scan( /:([\S]+)_offset/ ) offsets.each do | name, | asm = asm.gsub( ":#{name}_offset", @machine.block_offset( name ).to_s ) end # and substitute in and register values for any variables specified... regs = asm.scan( /:([\S]+)_reg([\d]+)/ ) regs.each do | name, size | asm = asm.gsub( ":#{name}_reg#{size}", @machine.variable_value( name, size.to_i ) ) end # assemble it into a raw blob blob = @machine.assemble( asm ) #if( not @machine.is_valid?( blob ) ) # p "#{name}(#{primitive}):#{asm} is invalid" #end raw << blob end end else # the source must just be a static string raw = @source end # Update the length to reflect the new raw buffer @length = raw.to_s.length # As the temp variable is only assigned for the duration of a single permutation we # can now release it if it was used in this permutation. @machine.release_temp_variable return raw.to_s end
solve()
click to toggle source
Try to find a solution within the solution space by performing a depth first search into the permutation tree and backtracking when needed.
# File lib/rex/poly/machine/machine.rb, line 143 def solve # Check to see if this permutation can make part of a valid solution if( self.is_valid? ) # record this permutation as part of the final solution (the current machines register state is also saved here) @machine.solution_push( self ) # If we have no children we are at the end of the tree and have a potential full solution. if( not self.has_children? ) # We have a solution but doing a final pass to update offsets may introduce bad chars # so we test for this and keep searching if this isnt a real solution after all. if( not @machine.solution_is_valid? ) # remove this permutation and keep searching @machine.solution_pop return false end # Return true to unwind the recursive call as we have got a final solution. return true end # Itterate over the children of this permutation (the perutations of the proceeding block). @children.each do | child | # Traverse into this child to keep trying to generate a solution... if( child.solve ) # Keep returning true to unwind as we are done. return true end end # If we get here this permutation, origionally thought to be good for a solution, is not after all, # so remove it from the machines final solution, restoring the register state aswell. @machine.solution_pop end # No children can be made form part of the solution, return failure for this path in the tree. return false end