class Rex::Poly::Machine

A machine capable of creating a small blob of code in a metamorphic kind of way. Note: this is designed to perform an exhaustive search for a solution and can be slow. If you need a speedier option, the origional Rex::Polly::Block stuff is a better choice.

Constants

BYTE
DWORD
QWORD
WORD

Public Class Methods

new( badchars, cpu ) click to toggle source

Create a new machine instance.

# File lib/rex/poly/machine/machine.rb, line 351
def initialize( badchars, cpu )
  @badchars      = badchars
  @cpu           = cpu

  @reg_available = ::Array.new
  @reg_consumed  = ::Array.new
  @variables     = ::Hash.new
  @blocks        = ::Hash.new
  @primitives    = ::Hash.new
  @solution      = Solution.new

  _create_primitives

  @blocks['begin'] = Block.new( 'begin' )
  @blocks['begin'] << SymbolicPermutation.new( 'begin', self )

  _create_variable( 'temp' )
end

Public Instance Methods

assemble( asm ) click to toggle source

Use METASM to assemble a line of asm using this machines current cpu.

# File lib/rex/poly/machine/machine.rb, line 380
def assemble( asm )
  return Metasm::Shellcode.assemble( @cpu, asm ).encode_string
end
block_exist?( name ) click to toggle source

Does a given block exist?

# File lib/rex/poly/machine/machine.rb, line 558
def block_exist?( name )
  return @blocks.include?( name )
end
block_next( target_block ) click to toggle source

Get the block next to the target block.

# File lib/rex/poly/machine/machine.rb, line 601
def block_next( target_block )
  @blocks.each_key do | current_block |
    if( block_previous( current_block ) == target_block )
      return current_block
    end
  end
  return nil
end
block_offset( name ) click to toggle source

Get the offset for a blocks active permutation. This is easy for backward references as they will already have been rendered and their sizes known. For forward references we can't know in advance but the correct value can be known later once the final solution is available and a final pass to generate the raw buffer is made.

# File lib/rex/poly/machine/machine.rb, line 541
def block_offset( name )
  if( name == 'end' )
    return @solution.offset
  elsif( @blocks[name] )
    @blocks[name].each do | permutation |
      if( permutation.active )
        return permutation.offset
      end
    end
  end
  # If we are forward referencing a block it will be at least the current solutions offset +1
  return @solution.offset + 1
end
block_previous( target_block ) click to toggle source

Get the block previous to the target block.

# File lib/rex/poly/machine/machine.rb, line 587
def block_previous( target_block )
  previous_block = nil
  @blocks.each_key do | current_block |
    if( current_block == target_block )
      return previous_block
    end
    previous_block = current_block
  end
  return nil
end
create_block( name, *permutation_sources ) click to toggle source

Create a block by name and add in its list of permutations.

XXX: this doesnt support the fuzzy order of block dependencies ala the origional rex::poly

# File lib/rex/poly/machine/machine.rb, line 504
def create_block( name, *permutation_sources )
  # Sanity check we aren't trying to create one of the reserved symbolic blocks.
  if( name == 'begin' or name == 'end' )
    raise RuntimeError, "Unable to add block, '#{name}' is a reserved block name."
  end
  # If this is the first time this block is being created, create the block object to hold the permutation list
  if( not @blocks[name] )
    @blocks[name] = Block.new( name )
  end
  # Now create a new permutation object for every one supplied.
  permutation_sources.each do | source |
    @blocks[name] << Permutation.new( name, '', self, source )
  end
  return name
end
create_block_primitive( block_name, primitive_name, *args ) click to toggle source

Create a block which is based on a primitive defined by this machine.

# File lib/rex/poly/machine/machine.rb, line 523
def create_block_primitive( block_name, primitive_name, *args )
  # Santiy check this primitive is actually available and is not an internal primitive (begins with an _).
  if( not @primitives[primitive_name] or primitive_name[0] == "_" )
    raise RuntimeError, "Unable to add block, Primitive '#{primitive_name}' is not available."
  end
  # Sanity check we aren't trying to create one of the reserved symbolic blocks.
  if( block_name == 'begin' or block_name == 'end' )
    raise RuntimeError, "Unable to add block, '#{block_name}' is a reserved block name."
  end
  return _create_block_primitive( block_name, primitive_name, *args )
end
create_variable( name, reg=nil ) click to toggle source

Create a variable by name which will be assigned a register during generation. We can optionally assign a static register value to a variable if needed.

# File lib/rex/poly/machine/machine.rb, line 426
def create_variable( name, reg=nil )
  # Sanity check we aren't trying to create one of the reserved variables.
  if( name == 'temp' )
    raise RuntimeError, "Unable to create variable, '#{name}' is a reserved variable name."
  end
  return _create_variable( name, reg )
end
generate() click to toggle source

Try to generate a solution.

# File lib/rex/poly/machine/machine.rb, line 613
def generate

  if( @blocks.has_key?( 'end' ) )
    @blocks.delete( 'end' )
  end

  @blocks['end'] = Block.new( 'end' )
  @blocks['end'] << SymbolicPermutation.new( 'end', self, 1 )

  # Mix up the permutation orders for each block and create the tree structure.
  previous = ::Array.new
  @blocks.each_value do | block |
    # Shuffle the order of the blocks permutations.
    block.shuffle
    # create the tree by adding the current blocks permutations as children of the previous block.
    current = ::Array.new
    block.each do | permutation |
      permutation.remove_children
      previous.each do | prev |
        prev.add_child( permutation )
      end
      current << permutation
    end
    previous = current
  end

  # Shuffle the order of the available registers
  @reg_available = @reg_available.shuffle

  # We must try every permutation of the register orders, so if we fail to
  # generate a solution we rotate the available registers to try again with
  # a different order. This ensures we perform and exhaustive search.
  0.upto( @reg_available.length - 1 ) do

    @solution.reset

    # Start from the root node in the solution space and generate a
    # solution by traversing the solution space's tree structure.
    if( @blocks['begin'].solve )
      # Return the solutions buffer (perform a last pass to fixup all offsets)...
      return @solution.buffer
    end

    @reg_available.push( @reg_available.shift )
  end

  # :(
  nil
end
is_valid?( data ) click to toggle source

Check if a data blob is valid against the badchar list (or perform any other validation here)

# File lib/rex/poly/machine/machine.rb, line 387
def is_valid?( data )
  if( data.nil? )
    return false
  end
  return Rex::Text.badchar_index( data, @badchars ).nil?
end
make_safe_byte( number=nil ) click to toggle source

Generate a 8 bit number whoes bytes are valid in this machine.

# File lib/rex/poly/machine/machine.rb, line 418
def make_safe_byte( number=nil )
  return _make_safe_number( BYTE, number ) & 0xFF
end
make_safe_dword( number=nil ) click to toggle source

Generate a 32 bit number whoes bytes are valid in this machine.

# File lib/rex/poly/machine/machine.rb, line 404
def make_safe_dword( number=nil )
  return _make_safe_number( DWORD, number ) & 0xFFFFFFFF
end
make_safe_qword( number=nil ) click to toggle source

Generate a 64 bit number whoes bytes are valid in this machine.

# File lib/rex/poly/machine/machine.rb, line 397
def make_safe_qword( number=nil )
  return _make_safe_number( QWORD, number ) & 0xFFFFFFFFFFFFFFFF
end
make_safe_word( number=nil ) click to toggle source

Generate a 16 bit number whoes bytes are valid in this machine.

# File lib/rex/poly/machine/machine.rb, line 411
def make_safe_word( number=nil )
  return _make_safe_number( WORD, number ) & 0xFFFF
end
native_size() click to toggle source

Overloaded by a subclass to return the maximum native general register size supported.

# File lib/rex/poly/machine/machine.rb, line 373
def native_size
  nil
end
release_temp_variable() click to toggle source

If the temp variable was assigned we release it.

# File lib/rex/poly/machine/machine.rb, line 437
def release_temp_variable
  if( @variables['temp'] )
    regnum = @variables['temp']
    # Sanity check the temp variable was actually assigned (it may not have been if the last permutation didnot use it)
    if( regnum )
      # place the assigned register back in the available list for consumption later.
      @reg_available.push( @reg_consumed.delete( regnum ) )
      # unasign the temp vars register
      @variables['temp'] = nil
      return true
    end
  end
  return false
end
resolve_value( value, size=nil ) click to toggle source

Resolve a given value into either a number literal, a block offset or a variables assigned register.

# File lib/rex/poly/machine/machine.rb, line 575
def resolve_value( value, size=nil )
  if( block_exist?( value ) )
    return block_offset( value )
  elsif( variable_exist?( value ) )
    return variable_value( value, size )
  end
  return value.to_i
end
solution_is_valid?() click to toggle source

Check this solution is still currently valid (as offsets change it may not be).

# File lib/rex/poly/machine/machine.rb, line 479
def solution_is_valid?
  return self.is_valid?( @solution.buffer )
end
solution_pop() click to toggle source

Backtrack one step in the solution and restore the register/variable state.

# File lib/rex/poly/machine/machine.rb, line 494
def solution_pop
  permutation, @reg_available, @reg_consumed, @variables = @solution.pop

  @reg_available.push( @reg_available.shift )
end
solution_push( permutation ) click to toggle source

As the solution advances we save state for each permutation step in the solution. This lets use rewind at a later stage if the solving algorithm wishes to perform some backtracking.

# File lib/rex/poly/machine/machine.rb, line 487
def solution_push( permutation )
  @solution.push( permutation, @reg_available, @reg_consumed, @variables  )
end
variable_exist?( name ) click to toggle source

Does a given block exist?

# File lib/rex/poly/machine/machine.rb, line 565
def variable_exist?( name )
  return @variables.include?( name )
end
variable_value( name, size=nil ) click to toggle source

Resolve a variable name into its currently assigned register value.

# File lib/rex/poly/machine/machine.rb, line 455
def variable_value( name, size=nil )
  # Sanity check we this variable has been created
  if( not @variables.has_key?( name ) )
    raise RuntimeError, "Unknown register '#{name}'."
  end
  # Pull out its current register value if it has been assigned one
  regnum = @variables[ name ]
  if( not regnum )
    regnum = @reg_available.pop
    if( not regnum )
      raise RuntimeError, "Unable to assign variable '#{name}' a register value, none available."
    end
    # and add it to the consumed list so we can track it later
    @reg_consumed << regnum
    # and now assign the variable the register
    @variables[ name ] = regnum
  end
  # resolve the register number int a string representation (e.g. 0 in x86 is EAX if size is 32)
  return _register_value( regnum, size )
end

Protected Instance Methods

_create_block_primitive( block_name, primitive_name, *args ) click to toggle source

Create a block which is based on a primitive defined by this machine.

# File lib/rex/poly/machine/machine.rb, line 742
def _create_block_primitive( block_name, primitive_name, *args )
  # If this is the first time this block is being created, create the array to hold the permutation list
  if( not @blocks[block_name] )
    @blocks[block_name] = Block.new( block_name )
  end
  # Now create a new permutation object for every one supplied.
  @primitives[primitive_name].each do | source |
    @blocks[block_name] << Permutation.new( block_name, primitive_name, self, source, args )
  end
  return block_name
end
_create_primitive( name, *permutations ) click to toggle source

Rex::Poly::Machine::Primitive

# File lib/rex/poly/machine/machine.rb, line 764
def _create_primitive( name, *permutations )
  # If this is the first time this primitive is being created, create the array to hold the permutation list
  if( not @primitives[name] )
    @primitives[name] = ::Array.new
  end
  # Add in the permutation object (Rex::Poly::Machine::Primitive) for every one supplied.
  permutations.each do | permutation |
    @primitives[name] << Primitive.new( permutation )
  end
end
_create_primitives() click to toggle source

Overloaded by a subclass to create any primitives available in this machine.

# File lib/rex/poly/machine/machine.rb, line 757
def _create_primitives
  nil
end
_create_variable( name, reg=nil ) click to toggle source

Perform the actual variable creation.

# File lib/rex/poly/machine/machine.rb, line 708
def _create_variable( name, reg=nil )
  regnum = nil
  # Sanity check this variable has not already been created.
  if( @variables[name] )
    raise RuntimeError, "Variable '#{name}' is already created."
  end
  # If a fixed register is being assigned to this variable then resolve it
  if( reg )
    # Resolve the register name into a register number
    @reg_available.each do | num |
      if( _register_value( num ) == reg.downcase )
        regnum = num
        break
      end
    end
    # If an invalid register name was given or the chosen register is not available we must fail.
    if( not regnum )
      raise RuntimeError, "Register '#{reg}' is unknown or unavailable."
    end
    # Sanity check another variable isnt assigned this register
    if( @variables.has_value?( regnum ) )
      raise RuntimeError, "Register number '#{regnum}' is already consumed by variable '#{@variables[name]}'."
    end
    # Finally we consume the register chosen so we dont select it again later.
    @reg_consumed << @reg_available.delete( regnum )
  end
  # Create the variable and assign it a register number (or nil if not yet assigned)
  @variables[name] = regnum
  return name
end
_make_safe_number( bytes, number=nil ) click to toggle source

Helper function to generate a number whoes byte representation is valid in this machine (does not contain any badchars for example). Optionally we can supply a number and the resulting addition/subtraction of this number against the newly generated value is also tested for validity. This helps in the assembly primitives which can use these values.

# File lib/rex/poly/machine/machine.rb, line 782
def _make_safe_number( bytes, number=nil )
  format = ''
  if( bytes == BYTE )
    format = 'C'
  elsif( bytes == WORD )
    format = 'v'
  elsif( bytes == DWORD )
    format = 'V'
  elsif( bytes == QWORD )
    format = 'Q'
  else
    raise RuntimeError, "Invalid size '#{bytes}' used in _make_safe_number."
  end

  goodchars = (0..255).to_a

  @badchars.unpack( 'C*' ).each do | b |
    goodchars.delete( b.chr )
  end

  while( true ) do
    value = 0

    0.upto( bytes-1 ) do | i |
      value |= ( (goodchars[ rand(goodchars.length) ] << i*8) & (0xFF << i*8) )
    end

    if( not is_valid?( [ value ].pack(format) ) or not is_valid?( [ ~value ].pack(format) ) )
      redo
    end

    if( not number.nil? )
      if( not is_valid?( [ value + number ].pack(format) ) or not is_valid?( [ value - number ].pack(format) ) )
        redo
      end
    end

    break
  end

  return value
end
_register_value( regnum, size=nil ) click to toggle source

Overloaded by a subclass to resolve a register number into a suitable register name for the target architecture. E.g on x64 the register number 0 with size 64 would resolve to RCX. Size is nil by default to indicate we want the default machine size, e.g. 32bit DWORD on x86 or 64bit QWORD on x64.

# File lib/rex/poly/machine/machine.rb, line 701
def _register_value( regnum, size=nil )
  nil
end