Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rapid7
GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/nops/x64/simple.rb
19516 views
1
##
2
# This module requires Metasploit: https://metasploit.com/download
3
# Current source: https://github.com/rapid7/metasploit-framework
4
##
5
6
class MetasploitModule < Msf::Nop
7
8
def initialize
9
super(
10
'Name' => 'Simple',
11
'Alias' => 'x64_simple',
12
'Description' => 'An x64 single/multi byte NOP instruction generator.',
13
'Author' => [ 'sf' ],
14
'License' => MSF_LICENSE,
15
'Arch' => ARCH_X64)
16
17
register_advanced_options([ OptBool.new('RandomNops', [ false, 'Generate a random NOP sled', true ]) ])
18
register_advanced_options([ OptBool.new('MultiByte', [ false, 'Generate a multi byte instruction NOP sled', false ]) ])
19
end
20
21
# This instruction list is far from complete (Only single byte instructions and some multi byte ADD/MOV instructions are used).
22
# A more complete list might warrant an pseudo assembler (Rex::Arch::X64) instead of hardcoding these.
23
INSTRUCTIONS = [
24
[ "\x90", 0, 'nop' ],
25
[ "\x91", 0, 'xchg eax, ecx' ],
26
[ "\x92", 0, 'xchg eax, edx' ],
27
[ "\x93", 0, 'xchg eax, ebx' ],
28
[ "\x94", 0, 'xchg eax, esp' ],
29
[ "\x95", 0, 'xchg eax, ebp' ],
30
[ "\x96", 0, 'xchg eax, esi' ],
31
[ "\x97", 0, 'xchg eax, edi' ],
32
[ "\x98", 0, 'cwde' ],
33
[ "\x99", 0, 'cdq' ],
34
[ "\x9B", 0, 'wait' ],
35
[ "\x9C", 0, 'pushfq' ],
36
[ "\x9D", 0, 'popfq' ],
37
[ "\x9E", 0, 'sahf' ],
38
[ "\x9F", 0, 'lahf' ],
39
[ "\xFC", 0, 'cld' ],
40
[ "\xFD", 0, 'std' ],
41
[ "\xF8", 0, 'clc' ],
42
[ "\xF9", 0, 'cmc' ],
43
[ "\x50", 0, 'push rax' ],
44
[ "\x51", 0, 'push rcx' ],
45
[ "\x52", 0, 'push rdx' ],
46
[ "\x53", 0, 'push rbx' ],
47
[ "\x54", 0, 'push rsp' ],
48
[ "\x55", 0, 'push rbp' ],
49
[ "\x56", 0, 'push rsi' ],
50
[ "\x57", 0, 'push rdi' ],
51
[ "\x58", 0, 'pop rax' ],
52
[ "\x59", 0, 'pop rcx' ],
53
[ "\x5A", 0, 'pop rdx' ],
54
[ "\x5B", 0, 'pop rbx' ],
55
[ "\x5C", 0, 'pop rsp' ],
56
[ "\x5D", 0, 'pop rbp' ],
57
[ "\x5E", 0, 'pop rsi' ],
58
[ "\x5F", 0, 'pop rdi' ],
59
[ "\x04", 1, 'add al, 0x??' ],
60
[ "\x80\xC3", 1, 'add bl, 0x??' ],
61
[ "\x80\xC1", 1, 'add cl, 0x??' ],
62
[ "\x80\xC2", 1, 'add dl, 0x??' ],
63
[ "\x80\xC4", 1, 'add ah, 0x??' ],
64
[ "\x80\xC7", 1, 'add bh, 0x??' ],
65
[ "\x80\xC5", 1, 'add ch, 0x??' ],
66
[ "\x80\xC6", 1, 'add dh, 0x??' ],
67
[ "\x66\x05", 2, 'add ax, 0x????' ],
68
[ "\x66\x81\xC3", 2, 'add bx, 0x????' ],
69
[ "\x66\x81\xC1", 2, 'add cx, 0x????' ],
70
[ "\x66\x81\xC2", 2, 'add dx, 0x????' ],
71
[ "\x66\x81\xC6", 2, 'add si, 0x????' ],
72
[ "\x66\x81\xC7", 2, 'add di, 0x????' ],
73
[ "\x66\x41\x81\xC0", 2, 'add r8w, 0x????' ],
74
[ "\x66\x41\x81\xC1", 2, 'add r9w, 0x????' ],
75
[ "\x66\x41\x81\xC2", 2, 'add r10w, 0x????' ],
76
[ "\x66\x41\x81\xC3", 2, 'add r11w, 0x????' ],
77
[ "\x66\x41\x81\xC4", 2, 'add r12w, 0x????' ],
78
[ "\x66\x41\x81\xC5", 2, 'add r13w, 0x????' ],
79
[ "\x66\x41\x81\xC6", 2, 'add r14w, 0x????' ],
80
[ "\x66\x41\x81\xC7", 2, 'add r15w, 0x????' ],
81
[ "\x05", 4, 'add eax, 0x????????' ],
82
[ "\x81\xC3", 4, 'add ebx, 0x????????' ],
83
[ "\x81\xC1", 4, 'add ecx, 0x????????' ],
84
[ "\x81\xC2", 4, 'add edx, 0x????????' ],
85
[ "\x81\xC6", 4, 'add esi, 0x????????' ],
86
[ "\x81\xC7", 4, 'add edi, 0x????????' ],
87
[ "\x41\x81\xC0", 4, 'add r8d, 0x????????' ],
88
[ "\x41\x81\xC1", 4, 'add r9d, 0x????????' ],
89
[ "\x41\x81\xC2", 4, 'add r10d, 0x????????' ],
90
[ "\x41\x81\xC3", 4, 'add r11d, 0x????????' ],
91
[ "\x41\x81\xC4", 4, 'add r12d, 0x????????' ],
92
[ "\x41\x81\xC5", 4, 'add r13d, 0x????????' ],
93
[ "\x41\x81\xC6", 4, 'add r14d, 0x????????' ],
94
[ "\x41\x81\xC7", 4, 'add r15d, 0x????????' ],
95
[ "\x48\xB8", 8, 'mov rax, 0x????????????????' ],
96
[ "\x48\xBB", 8, 'mov rbx, 0x????????????????' ],
97
[ "\x48\xB9", 8, 'mov rcx, 0x????????????????' ],
98
[ "\x48\xBA", 8, 'mov rdx, 0x????????????????' ],
99
[ "\x48\xBE", 8, 'mov rsi, 0x????????????????' ],
100
[ "\x48\xBF", 8, 'mov rdi, 0x????????????????' ],
101
[ "\x49\xB8", 8, 'mov r8, 0x????????????????' ],
102
[ "\x49\xB9", 8, 'mov r8, 0x????????????????' ],
103
[ "\x49\xBA", 8, 'mov r10, 0x????????????????' ],
104
[ "\x49\xBB", 8, 'mov r11, 0x????????????????' ],
105
[ "\x49\xBC", 8, 'mov r12, 0x????????????????' ],
106
[ "\x49\xBD", 8, 'mov r13, 0x????????????????' ],
107
[ "\x49\xBE", 8, 'mov r14, 0x????????????????' ],
108
[ "\x49\xBF", 8, 'mov r15, 0x????????????????' ],
109
]
110
111
I_OP = 0
112
I_SIZE = 1
113
I_TEXT = 2
114
115
REGISTERS = [
116
[ 'rsp', 'esp', 'sp' ],
117
[ 'rbp', 'ebp', 'bp' ],
118
[ 'rax', 'eax', 'ax', 'al', 'ah' ],
119
[ 'rbx', 'ebx', 'bx', 'bl', 'bh' ],
120
[ 'rcx', 'ecx', 'cx', 'cl', 'ch' ],
121
[ 'rdx', 'edx', 'dx', 'dl', 'dh' ],
122
[ 'rsi', 'esi', 'si' ],
123
[ 'rdi', 'edi', 'di' ],
124
[ 'r8', 'r8d', 'r8w', 'r8b' ],
125
[ 'r9', 'r9d', 'r9w', 'r9b' ],
126
[ 'r10', 'r10d', 'r10w', 'r10b' ],
127
[ 'r11', 'r11d', 'r11w', 'r11b' ],
128
[ 'r12', 'r12d', 'r12w', 'r12b' ],
129
[ 'r13', 'r13d', 'r13w', 'r13b' ],
130
[ 'r14', 'r14d', 'r14w', 'r14b' ],
131
[ 'r15', 'r15d', 'r15w', 'r15b' ],
132
]
133
134
def generate_random_sled(length, instructions, badchars, badregs)
135
opcodes_stack = []
136
total_size = 0
137
sled = ''
138
try_count = 0
139
140
# Fixup SaveRegisters so for example, if we wish to preserve RSP we also should also preserve ESP and SP
141
REGISTERS.each { |reg| reg.each { |x| badregs += reg if badregs.include?(x) } }
142
badregs = badregs.uniq
143
144
# If we are preserving RSP we should avoid all PUSH/POP instructions...
145
if badregs.include?('rsp')
146
badregs.push('push')
147
badregs.push('pop')
148
end
149
150
# Loop while we still have bytes to fill in the sled...
151
loop do
152
# Pick a random instruction and see if we can use it...
153
instruction = instructions[rand(instructions.length)]
154
155
# Avoid using any bad mnemonics/registers...
156
try_another = false
157
badregs.each do |bad|
158
try_another = true if instruction[I_TEXT].include?(bad.downcase)
159
break if try_another
160
end
161
next if try_another
162
163
# Get the first bytes of the chosen instructions opcodes...
164
opcodes = instruction[I_OP]
165
166
# If their are additional bytes to append, do it now...
167
1.upto(instruction[I_SIZE]) do |_i|
168
opcodes += Rex::Text.rand_char(badchars)
169
end
170
171
# If we have gone over the requested sled length, try again.
172
if total_size + opcodes.length > length
173
try_count -= 1
174
175
# If we have tried unsuccessfully 32 times we start unwinding the chosen opcode_stack to speed things up
176
if try_count == 0
177
pop_count = 4
178
while opcodes_stack.length && pop_count
179
total_size -= opcodes_stack.pop.length
180
pop_count -= 1
181
end
182
end
183
next
184
end
185
186
# Reset the try_count for the next iteration.
187
try_count = 32
188
189
# save the opcodes we just generated.
190
opcodes_stack.push(opcodes)
191
192
# Increment the total size appropriately.
193
total_size += opcodes.length
194
195
# Once we have generated the requested amount of bytes we can finish.
196
break if total_size == length
197
end
198
199
# Now that we have chosen all the instructions to use we must generate the actual sled.
200
opcodes_stack.each do |opcodes_|
201
sled += opcodes_
202
end
203
204
return sled
205
end
206
207
def generate_sled(length, opts)
208
badchars = opts['BadChars'] || ''
209
random = opts['Random'] || datastore['RandomNops']
210
badregs = opts['SaveRegisters'] || []
211
good_instructions = []
212
sled = ''
213
214
# Weed out any instructions which will contain a bad char/instruction...
215
INSTRUCTIONS.each do |instruction|
216
good = true
217
# If the instruction contains some bad chars we wont use it...
218
badchars.each_char do |bc|
219
if instruction[I_OP].include?(bc)
220
good = false
221
break
222
end
223
end
224
# if we are only to generate single byte instructions, weed out the multi byte ones...
225
good = false if (instruction[I_SIZE] > 0) && !datastore['MultiByte']
226
227
good_instructions.push(instruction) if good
228
end
229
230
# After we have pruned the instruction list we can proceed to generate a sled...
231
if good_instructions.empty?
232
# If we are left with no valid instructions to use we simple can't generate a sled.
233
sled = nil
234
elsif !random
235
if !badchars.include?("\x90")
236
sled += "\x90" * length
237
else
238
sled = nil
239
end
240
else
241
sled += generate_random_sled(length, good_instructions, badchars, badregs)
242
end
243
244
return sled
245
end
246
end
247
248