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