metasploit-framework/lib/rex/nop/opty2.rb

109 lines
2.1 KiB
Ruby

require 'rex/arch/x86'
require 'rex/nop/opty2_tables'
module Rex
module Nop
###
#
# This class provides an interface to generating multi-byte NOP sleds for x86.
# Optyx and spoonm get the creds!
#
###
class Opty2
Table = Rex::Nop::Opty2Tables::StateTable
def initialize(badchars = '', save_registers = nil)
self.badchars = badchars
self.save_registers = (save_registers || []) | [ 'esp', 'ebp']
end
#
# Generates the Opty2 multi-byte NOP sled.
#
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
attr_accessor :badchars, :save_registers # :nodoc:
end
end
end