Class: Rex::Poly::Machine::Permutation

Inherits:
Object
  • Object
show all
Defined in:
lib/rex/poly/machine/machine.rb

Overview

A Permutation!

Direct Known Subclasses

SymbolicPermutation

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name, primitive, machine, source, args = nil) ⇒ Permutation

Create a new permutation object.


31
32
33
34
35
36
37
38
39
40
41
42
# 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

Instance Attribute Details

#activeObject

Returns the value of attribute active


24
25
26
# File 'lib/rex/poly/machine/machine.rb', line 24

def active
  @active
end

#argsObject (readonly)

Returns the value of attribute args


26
27
28
# File 'lib/rex/poly/machine/machine.rb', line 26

def args
  @args
end

#lengthObject (readonly)

Returns the value of attribute length


26
27
28
# File 'lib/rex/poly/machine/machine.rb', line 26

def length
  @length
end

#nameObject (readonly)

Returns the value of attribute name


26
27
28
# File 'lib/rex/poly/machine/machine.rb', line 26

def name
  @name
end

#offsetObject

Returns the value of attribute offset


24
25
26
# File 'lib/rex/poly/machine/machine.rb', line 24

def offset
  @offset
end

#primitiveObject (readonly)

Returns the value of attribute primitive


26
27
28
# File 'lib/rex/poly/machine/machine.rb', line 26

def primitive
  @primitive
end

Instance Method Details

#add_child(child) ⇒ Object

Add in a child permutation to this one. Used to build the permutation tree.


47
48
49
# File 'lib/rex/poly/machine/machine.rb', line 47

def add_child( child )
  @children << child
end

#has_children?Boolean

Does this permutation have children?

Returns:

  • (Boolean)

54
55
56
# File 'lib/rex/poly/machine/machine.rb', line 54

def has_children?
  not @children.empty?
end

#is_valid?Boolean

Test if this permutation raw buffer is valid in this machine (e.g. against the badchar list).

Returns:

  • (Boolean)

119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# 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_childrenObject

Remove any existing children. Called by the machines generate function to build a fresh tree in case generate was previously called.


62
63
64
# File 'lib/rex/poly/machine/machine.rb', line 62

def remove_children
  @children.clear
end

#renderObject

Actully render this permutation into a raw buffer.


69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# 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

#solveObject

Try to find a solution within the solution space by performing a depth first search into the permutation tree and backtracking when needed.


143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
# 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