# -*- coding: binary -*-

###
#
# A target for an exploit.
#
###
class Msf::Module::Target

  ###
  #
  # Target-specific brute force information, such as the addresses
  # to step, the step size (if the framework default is bad), and
  # other stuff.
  #
  ###
  class Bruteforce < Hash

    #
    # Initializes a brute force target from the supplied brute forcing
    # information.
    #
    def initialize(hash)
      update(hash)
    end

    #
    # Returns a hash of addresses that should be stepped during
    # exploitation and passed in to the bruteforce exploit
    # routine.
    #
    def start_addresses
      if (self['Start'] and self['Start'].kind_of?(Hash) == false)
        return {'Address' => self['Start'] }
      else
        return self['Start']
      end
    end

    #
    # Returns a hash of addresses that should be stopped at once
    # they are reached.
    #
    def stop_addresses
      if (self['Stop'] and self['Stop'].kind_of?(Hash) == false)
        return {'Address' => self['Stop'] }
      else
        return self['Stop']
      end
    end

    #
    # The step size to use, or zero if the framework should figure
    # it out.
    #
    def step_size
      self['Step'] || 0
    end

    #
    # Returns the default step direction.  -1 indicates that brute forcing
    # should go toward lower addresses.  1 indicates that brute forcing
    # should go toward higher addresses.
    #
    def default_direction
      dd = self['DefaultDirection']

      if (dd and dd.to_s.match(/(-1|backward)/i))
        return -1
      end

      return 1
    end

    #
    # The delay to add between attempts
    #
    def delay
      self['Delay'].to_i || 0
    end
  end

  #
  # Serialize from an array to a Target instance.
  #
  def self.from_a(ary)
    return nil if (ary.length < 2)

    self.new(ary.shift, ary.shift)
  end

  #
  # Transforms the supplied source into an array of Targets.
  #
  def self.transform(src)
    Rex::Transformer.transform(src, Array, [ self, String ], 'Target')
  end

  #
  # Initializes an instance of a bruteforce target from the supplied
  # information.  The hash of options that this constructor takes is as
  # follows:
  #
  # Platform
  #
  # 	The platform(s) that this target is to operate against.
  #
  # SaveRegisters
  #
  # 	The registers that must be saved by NOP generators.
  #
  # Arch
  #
  # 	The architectures, if any, that this target is specific to (E.g.
  # 	ARCH_X86).
  #
  # Bruteforce
  #
  # 	Settings specific to a target that supports brute forcing.  See the
  # 	BruteForce class.
  #
  # Ret
  #
  # 	The target-specific return address or addresses that will be used.
  #
  # Payload
  #
  # 	Payload-specific options, such as append, prepend, and other values that
  # 	can be set on a per-exploit or per-target basis.
  #
  # DefaultOptions
  #
  #   DefaultOptions hash to be imported into the datastore.
  #
  def initialize(name, opts)
    opts = {} unless opts

    self.name            = name
    self.opts            = opts
    self.save_registers  = opts['SaveRegisters']
    self.ret             = opts['Ret']
    self.default_options = opts['DefaultOptions']

    if opts['Platform']
      self.platform = Msf::Module::PlatformList.transform(opts['Platform'])
    end

    if opts['Arch']
      self.arch = Rex::Transformer.transform(opts['Arch'], Array, [String], 'Arch')
    end

    # Does this target have brute force information?
    if opts['Bruteforce']
      self.bruteforce = Bruteforce.new(opts['Bruteforce'])
    end
  end

  #
  # Index the options directly.
  #
  def [](key)
    opts[key]
  end

  #
  # Returns whether or not this is a bruteforce target, forces boolean
  # result.
  #
  def bruteforce?
    return (bruteforce != nil)
  end

  ##
  #
  # Target-specific payload modifications
  #
  ##

  #
  # The bad characters specific to this target for the payload.
  #
  def payload_badchars
    opts['Payload'] ? opts['Payload']['BadChars'] : nil
  end

  #
  # Payload prepend information for this target.
  #
  def payload_prepend
    opts['Payload'] ? opts['Payload']['Prepend'] : nil
  end

  #
  # Payload append information for this target.
  #
  def payload_append
    opts['Payload'] ? opts['Payload']['Append'] : nil
  end

  #
  # Payload prepend encoder information for this target.
  #
  def payload_prepend_encoder
    opts['Payload'] ? opts['Payload']['PrependEncoder'] : nil
  end

  #
  # Payload append encoder information for this target.
  #
  def payload_append_encoder
    opts['Payload'] ? opts['Payload']['AppendEncoder'] : nil
  end

  #
  # Payload stack adjustment information for this target.
  #
  def payload_stack_adjustment
    opts['Payload'] ? opts['Payload']['StackAdjustment'] : nil
  end

  #
  # Whether NOP generation should be enabled or disabled
  #
  def payload_disable_nops
    opts['Payload'] ? opts['Payload']['DisableNops'] : nil
  end

  #
  # Payload max nops information for this target.
  #
  def payload_max_nops
    opts['Payload'] ? opts['Payload']['MaxNops'] : nil
  end

  #
  # Payload min nops information for this target.
  #
  def payload_min_nops
    opts['Payload'] ? opts['Payload']['MinNops'] : nil
  end

  #
  # Payload space information for this target.
  #
  def payload_space
    opts['Payload'] ? opts['Payload']['Space'] : nil
  end

  #
  # The payload encoder or encoders that can be used when generating the
  # encoded payload (such as x86/shikata_ga_nai and so on).
  #
  def payload_encoder
    opts['Payload'] ? opts['Payload']['Encoder'] : nil
  end

  #
  # The payload NOP generator or generators that can be used when generating the
  # encoded payload (such as x86/opty2 and so on).
  #
  def payload_nop
    opts['Payload'] ? opts['Payload']['Nop'] : nil
  end

  #
  # The payload encoder type or types that can be used when generating the
  # encoded payload (such as alphanum, unicode, xor, and so on).
  #
  def payload_encoder_type
    opts['Payload'] ? opts['Payload']['EncoderType'] : nil
  end

  #
  # A hash of options that be initialized in the select encoder's datastore
  # that may be required as parameters for the encoding operation.  This is
  # particularly useful when a specific encoder type is being used (as
  # specified by the EncoderType hash element).
  #
  def payload_encoder_options
    opts['Payload'] ? opts['Payload']['EncoderOptions'] : nil
  end

  #
  # Returns a hash of extended options that are applicable to payloads used
  # against this particular target.
  #
  def payload_extended_options
    opts['Payload'] ? opts['Payload']['ExtendedOptions'] : nil
  end

  #
  # The name of the target (E.g. Windows XP SP0/SP1)
  #
  attr_reader :name
  #
  # The platforms that this target is for.
  #
  attr_reader :platform
  #
  # The architectures, if any, that the target is specific to.
  #
  attr_reader :arch
  #
  # The target-specific options, like payload settings and other stuff like
  # that.
  #
  attr_reader :opts
  #
  # An alias for the target 'Ret' option.
  #
  attr_reader :ret
  #
  # The list of registers that need to be saved.
  #
  attr_reader :save_registers
  #
  # The bruteforce target information that will be non-nil if a Bruteforce
  # option is passed to the constructor of the class.
  #
  attr_reader :bruteforce
  #
  # DefaultOptions hash to be imported into the datastore.
  #
  attr_reader :default_options

protected

  attr_writer :name, :platform, :arch, :opts, :ret, :save_registers # :nodoc:
  attr_writer :bruteforce # :nodoc:
  attr_writer :default_options # :nodoc:

end
