Class: Rex::Nop::Opty2

Inherits:
Object
  • Object
show all
Defined in:
lib/rex/nop/opty2.rb

Overview

This class provides an interface to generating multi-byte NOP sleds for x86. Optyx and spoonm get the creds!

Constant Summary collapse

Table =
Rex::Nop::Opty2Tables::StateTable

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(badchars = '', save_registers = nil) ⇒ Opty2

Returns a new instance of Opty2


18
19
20
21
# File 'lib/rex/nop/opty2.rb', line 18

def initialize(badchars = '', save_registers = nil)
  self.badchars       = badchars
  self.save_registers = (save_registers || []) | [ 'esp', 'ebp']
end

Instance Attribute Details

#badcharsObject

:nodoc:


105
106
107
# File 'lib/rex/nop/opty2.rb', line 105

def badchars
  @badchars
end

#save_registersObject

:nodoc:


105
106
107
# File 'lib/rex/nop/opty2.rb', line 105

def save_registers
  @save_registers
end

Instance Method Details

#generate_sled(length) ⇒ Object

Generates the Opty2 multi-byte NOP sled.


26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
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
# File 'lib/rex/nop/opty2.rb', line 26

def generate_sled(length)
  return '' if (length <= 0)

  # Initialize the sled buffer, the previous state, and the current stream
  # length.
  sled = ''
  prev = 256
  slen = 0

  # Initialize the byte count array
  counts = []

  256.times { |idx| counts[idx] = 0 }

  # Initialize the bad register mask
  mask = 0

  save_registers.each { |reg|
    mask |= 1 << (Rex::Arch::X86.reg_number(reg))
  }
  mask = mask << 16

  # Initialize the bad byte lookup table
  bad_bytes = []
  (badchars || '').each_byte { |byte|
    bad_bytes[byte] = 1
  }

  # Build the sled
  while (length > 0)
    low  = -1
    lows = []

    Table[prev].each { |nt|
      nt.each { |e|
        # Skip it if it's masked off or too large
        next if ((e & mask) != 0)
        next if (((e >> 8) & 0xff) > slen)

        byte = e & 0xff

        # Skip it if it's a bad byte
        next if (bad_bytes[byte] == 1)

        # Use it if it's a better value
        if ((low == -1) or (low > counts[byte]))
          low  = counts[byte]
          lows = [byte]
        # Otherwise, if it's just as good..
        elsif (low == counts[byte])
          lows << byte
        end
      }
    }

    # If we didn't find at least one byte possibility, then we're stuck.
    # Abort.
    if (low == -1)
      raise RuntimeError, "Failed to find a valid byte."
    end

    # Pick a random character for the possiblities
    prev = lows[rand(lows.length)]

    # Increment its used count
    counts[prev] += 1

    # Prepend the byte to the sled
    sled = prev.chr + sled

    # Increment the sled length
    slen   += 1
    length -= 1
  end

  # Return the sled
  sled
end