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!

Defined Under Namespace

Classes: UnitTest

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.



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

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

Instance Attribute Details

#badcharsObject

:nodoc:



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

def badchars
  @badchars
end

#save_registersObject

:nodoc:



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

def save_registers
  @save_registers
end

Instance Method Details

#generate_sled(length) ⇒ Object

Generates the Opty2 multi-byte NOP sled.



25
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
# File 'lib/rex/nop/opty2.rb', line 25

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