# -*- coding: binary -*-

module Rex

  module Poly

    #
    # 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.
    #
    class Machine

      QWORD = 8
      DWORD = 4
      WORD  = 2
      BYTE  = 1

      #
      # A Permutation!
      #
      class Permutation

        attr_accessor :active, :offset

        attr_reader :name, :primitive, :length, :args

        #
        # Create a new permutation object.
        #
        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

        #
        # Add in a child permutation to this one. Used to build the permutation tree.
        #
        def add_child( child )
          @children << child
        end

        #
        # Does this permutation have children?
        #
        def has_children?
          not @children.empty?
        end

        #
        # Remove any existing children. Called by the machines generate function
        # to build a fresh tree in case generate was previously called.
        #
        def remove_children
          @children.clear
        end

        #
        # Actully render this permutation into a raw buffer.
        #
        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

        #
        # Test if this permutation raw buffer is valid in this machine (e.g. against the badchar list).
        #
        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

        #
        # Try to find a solution within the solution space by performing a depth first search
        # into the permutation tree and backtracking when needed.
        #
        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

      end

      #
      # A symbolic permutation to mark locations like the begining and end of a group of blocks.
      # Used to calculate usefull offsets.
      #
      class SymbolicPermutation < Permutation
        def initialize( name, machine, initial_offset=0 )
          super( name, '', machine, '' )
          # fudge the initial symbolic offset with a default (it gets patched correctly later),
          # helps with the end symbolic block to not be 0 (as its a forward reference it really
          # slows things down if we leave it 0)
          @offset = initial_offset
          # A symbolic block is allways active!
          @active = true
        end

        #
        # We block all attempts to set the active state of this permutation so as
        # it is always true. This lets us always address the offset.
        #
        def active=( value )
        end
      end

      #
      # A primitive is a machine defined permutation which accepts some arguments when it is called.
      #
      class Primitive

        #
        # Initialize this primitive with its target source procedure and the machine it belongs to.
        #
        def initialize( source )
          @source = source
        end

        #
        # Call the primitives source procedure, passing in the arguments.
        #
        def call( name, machine, *args )
          return @source.call( name, machine, *args )
        end

      end

      #
      #
      #
      class Block

        #attr_accessor :next, :previous
        attr_reader :name

        def initialize( name )
          @name         = name
          @next         = nil
          @previous     = nil
          @permutations = ::Array.new
        end

        def shuffle
          @permutations = @permutations.shuffle
        end

        def solve
          @permutations.first.solve
        end

        def << ( permutation )
          @permutations << permutation
        end

        def each
          @permutations.each do | permutation |
            yield permutation
          end
        end

      end

      #
      # A class to hold a solution for a Rex::Poly::Machine problem.
      #
      class Solution

        attr_reader :offset

        def initialize
          @permutations = ::Array.new
          @reg_state    = ::Array.new
          @offset       = 0
        end

        #
        # Reset this solution to an empty state.
        #
        def reset
          @offset = 0
          @permutations.each do | permutation |
            permutation.active = false
            permutation.offset = 0
          end
          @permutations.clear
          @reg_state.clear
        end

        #
        # Push a new permutation onto this solutions permutations list and save the associated register/variables state
        #
        def push( permutation, reg_available, reg_consumed, variables )
          permutation.active = true
          permutation.offset = @offset
          @offset += permutation.length
          @permutations.push( permutation )
          @reg_state.push( [ [].concat(reg_available), [].concat(reg_consumed), {}.merge(variables) ] )
        end

        #
        # Pop off the last permutaion and register/variables state from this solution.
        #
        def pop
          reg_available, reg_consumed, variables = @reg_state.pop
          permutation = @permutations.pop
          permutation.active = false
          permutation.offset = 0
          @offset -= permutation.length
          return permutation, reg_available, reg_consumed, variables
        end

        #
        # Render the final buffer.
        #
        def buffer
          previous_offset = nil
          count           = 0
          # perform an N-pass fixup for offsets...
          while( true ) do
            # If we cant get the offsets fixed within a fixed ammount of tries we return
            # nil to indicate failure and keep searching for a solution that will work.
            if( count > 64 )
              return nil
            end
            # Reset the solution offset so as to update it for this pass
            @offset = 0
            # perform a single pass to ensure we are using the correct offset values
            @permutations.each do | permutation |
              permutation.offset = @offset
              # Note: calling render() can throw both UndefinedPermutation and UnallowedPermutation exceptions,
              # however as we assume we only ever return the buffer once a final solution has been generated
              # we should never have either of those exceptions thrown.
              permutation.render
              @offset += permutation.length
            end
            # If we have generated two consecutive passes which are the same length we can stop fixing up the offsets.
            if( not previous_offset.nil? and @offset == previous_offset )
              break
            end
            count +=1
            previous_offset = @offset
          end
          # now a final pass to render the solution into the raw buffer
          raw = ''
          @permutations.each do | permutation |
            #$stderr.puts "#{permutation.name} - #{ "0x%08X (%d)" % [ permutation.offset, permutation.length] } "
            raw << permutation.render
          end
          return raw
        end

      end

      #
      # Create a new machine instance.
      #
      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

      #
      # Overloaded by a subclass to return the maximum native general register size supported.
      #
      def native_size
        nil
      end

      #
      # Use METASM to assemble a line of asm using this machines current cpu.
      #
      def assemble( asm )
        return Metasm::Shellcode.assemble( @cpu, asm ).encode_string
      end

      #
      # Check if a data blob is valid against the badchar list (or perform any other validation here)
      #
      def is_valid?( data )
        if( data.nil? )
          return false
        end
        return Rex::Text.badchar_index( data, @badchars ).nil?
      end

      #
      # Generate a 64 bit number whoes bytes are valid in this machine.
      #
      def make_safe_qword( number=nil )
        return _make_safe_number( QWORD, number ) & 0xFFFFFFFFFFFFFFFF
      end

      #
      # Generate a 32 bit number whoes bytes are valid in this machine.
      #
      def make_safe_dword( number=nil )
        return _make_safe_number( DWORD, number ) & 0xFFFFFFFF
      end

      #
      # Generate a 16 bit number whoes bytes are valid in this machine.
      #
      def make_safe_word( number=nil )
        return _make_safe_number( WORD, number ) & 0xFFFF
      end

      #
      # Generate a 8 bit number whoes bytes are valid in this machine.
      #
      def make_safe_byte( number=nil )
        return _make_safe_number( BYTE, number ) & 0xFF
      end

      #
      # 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.
      #
      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

      #
      # If the temp variable was assigned we release it.
      #
      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 a variable name into its currently assigned register value.
      #
      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

      #
      # Check this solution is still currently valid (as offsets change it may not be).
      #
      def solution_is_valid?
        return self.is_valid?( @solution.buffer )
      end

      #
      # 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.
      #
      def solution_push( permutation )
        @solution.push( permutation, @reg_available, @reg_consumed, @variables  )
      end

      #
      # Backtrack one step in the solution and restore the register/variable state.
      #
      def solution_pop
        permutation, @reg_available, @reg_consumed, @variables = @solution.pop

        @reg_available.push( @reg_available.shift )
      end

      #
      # 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
      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 a block which is based on a primitive defined by this machine.
      #
      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

      #
      # 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.
      #
      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

      #
      # Does a given block exist?
      #
      def block_exist?( name )
        return @blocks.include?( name )
      end

      #
      # Does a given block exist?
      #
      def variable_exist?( name )
        return @variables.include?( name )
      end

      # XXX: ambiguity between variable names and block name may introduce confusion!!! make them be unique.

      #
      # Resolve a given value into either a number literal, a block offset or
      # a variables assigned register.
      #
      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

      #
      # Get the block previous to the target block.
      #
      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

      #
      # Get the block next to the target block.
      #
      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

      #
      # Try to generate a solution.
      #
      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

      #
      # An UndefinedPermutation exception is raised when a permutation can't render yet
      # as the conditions required are not yet satisfied.
      #
      class UndefinedPermutation < RuntimeError
        def initialize( msg=nil )
          super
        end
      end

      #
      # An UnallowedPermutation exception is raised when a permutation can't ever render
      # as the conditions supplied are impossible to satisfy.
      #
      class UnallowedPermutation < RuntimeError
        def initialize( msg=nil )
          super
        end
      end

      #
      # An InvalidPermutation exception is raised when a permutation receives a invalid
      # argument and cannot continue to render. This is a fatal exception.
      #
      class InvalidPermutation < RuntimeError
        def initialize( msg=nil )
          super
        end
      end

      protected

      #
      # 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.
      #
      def _register_value( regnum, size=nil )
        nil
      end

      #
      # Perform the actual variable creation.
      #
      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

      #
      # Create a block which is based on a primitive defined by this machine.
      #
      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

      #
      # Overloaded by a subclass to create any primitives available in this machine.
      #
      def _create_primitives
        nil
      end

      #
      # Rex::Poly::Machine::Primitive
      #
      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

      #
      # 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.
      #
      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

    end

  end

end
