247 lines
8.3 KiB
Ruby
247 lines
8.3 KiB
Ruby
##
|
|
# This module requires Metasploit: https://metasploit.com/download
|
|
# Current source: https://github.com/rapid7/metasploit-framework
|
|
##
|
|
|
|
class MetasploitModule < Msf::Nop
|
|
|
|
def initialize
|
|
super(
|
|
'Name' => 'Simple',
|
|
'Alias' => 'x64_simple',
|
|
'Description' => 'An x64 single/multi byte NOP instruction generator.',
|
|
'Author' => [ 'sf' ],
|
|
'License' => MSF_LICENSE,
|
|
'Arch' => ARCH_X64)
|
|
|
|
register_advanced_options([ OptBool.new('RandomNops', [ false, 'Generate a random NOP sled', true ]) ])
|
|
register_advanced_options([ OptBool.new('MultiByte', [ false, 'Generate a multi byte instruction NOP sled', false ]) ])
|
|
end
|
|
|
|
# This instruction list is far from complete (Only single byte instructions and some multi byte ADD/MOV instructions are used).
|
|
# A more complete list might warrant an pseudo assembler (Rex::Arch::X64) instead of hardcoding these.
|
|
INSTRUCTIONS = [
|
|
[ "\x90", 0, 'nop' ],
|
|
[ "\x91", 0, 'xchg eax, ecx' ],
|
|
[ "\x92", 0, 'xchg eax, edx' ],
|
|
[ "\x93", 0, 'xchg eax, ebx' ],
|
|
[ "\x94", 0, 'xchg eax, esp' ],
|
|
[ "\x95", 0, 'xchg eax, ebp' ],
|
|
[ "\x96", 0, 'xchg eax, esi' ],
|
|
[ "\x97", 0, 'xchg eax, edi' ],
|
|
[ "\x98", 0, 'cwde' ],
|
|
[ "\x99", 0, 'cdq' ],
|
|
[ "\x9B", 0, 'wait' ],
|
|
[ "\x9C", 0, 'pushfq' ],
|
|
[ "\x9D", 0, 'popfq' ],
|
|
[ "\x9E", 0, 'sahf' ],
|
|
[ "\x9F", 0, 'lahf' ],
|
|
[ "\xFC", 0, 'cld' ],
|
|
[ "\xFD", 0, 'std' ],
|
|
[ "\xF8", 0, 'clc' ],
|
|
[ "\xF9", 0, 'cmc' ],
|
|
[ "\x50", 0, 'push rax' ],
|
|
[ "\x51", 0, 'push rcx' ],
|
|
[ "\x52", 0, 'push rdx' ],
|
|
[ "\x53", 0, 'push rbx' ],
|
|
[ "\x54", 0, 'push rsp' ],
|
|
[ "\x55", 0, 'push rbp' ],
|
|
[ "\x56", 0, 'push rsi' ],
|
|
[ "\x57", 0, 'push rdi' ],
|
|
[ "\x58", 0, 'pop rax' ],
|
|
[ "\x59", 0, 'pop rcx' ],
|
|
[ "\x5A", 0, 'pop rdx' ],
|
|
[ "\x5B", 0, 'pop rbx' ],
|
|
[ "\x5C", 0, 'pop rsp' ],
|
|
[ "\x5D", 0, 'pop rbp' ],
|
|
[ "\x5E", 0, 'pop rsi' ],
|
|
[ "\x5F", 0, 'pop rdi' ],
|
|
[ "\x04", 1, 'add al, 0x??' ],
|
|
[ "\x80\xC3", 1, 'add bl, 0x??' ],
|
|
[ "\x80\xC1", 1, 'add cl, 0x??' ],
|
|
[ "\x80\xC2", 1, 'add dl, 0x??' ],
|
|
[ "\x80\xC4", 1, 'add ah, 0x??' ],
|
|
[ "\x80\xC7", 1, 'add bh, 0x??' ],
|
|
[ "\x80\xC5", 1, 'add ch, 0x??' ],
|
|
[ "\x80\xC6", 1, 'add dh, 0x??' ],
|
|
[ "\x66\x05", 2, 'add ax, 0x????' ],
|
|
[ "\x66\x81\xC3", 2, 'add bx, 0x????' ],
|
|
[ "\x66\x81\xC1", 2, 'add cx, 0x????' ],
|
|
[ "\x66\x81\xC2", 2, 'add dx, 0x????' ],
|
|
[ "\x66\x81\xC6", 2, 'add si, 0x????' ],
|
|
[ "\x66\x81\xC7", 2, 'add di, 0x????' ],
|
|
[ "\x66\x41\x81\xC0", 2, 'add r8w, 0x????' ],
|
|
[ "\x66\x41\x81\xC1", 2, 'add r9w, 0x????' ],
|
|
[ "\x66\x41\x81\xC2", 2, 'add r10w, 0x????' ],
|
|
[ "\x66\x41\x81\xC3", 2, 'add r11w, 0x????' ],
|
|
[ "\x66\x41\x81\xC4", 2, 'add r12w, 0x????' ],
|
|
[ "\x66\x41\x81\xC5", 2, 'add r13w, 0x????' ],
|
|
[ "\x66\x41\x81\xC6", 2, 'add r14w, 0x????' ],
|
|
[ "\x66\x41\x81\xC7", 2, 'add r15w, 0x????' ],
|
|
[ "\x05", 4, 'add eax, 0x????????' ],
|
|
[ "\x81\xC3", 4, 'add ebx, 0x????????' ],
|
|
[ "\x81\xC1", 4, 'add ecx, 0x????????' ],
|
|
[ "\x81\xC2", 4, 'add edx, 0x????????' ],
|
|
[ "\x81\xC6", 4, 'add esi, 0x????????' ],
|
|
[ "\x81\xC7", 4, 'add edi, 0x????????' ],
|
|
[ "\x41\x81\xC0", 4, 'add r8d, 0x????????' ],
|
|
[ "\x41\x81\xC1", 4, 'add r9d, 0x????????' ],
|
|
[ "\x41\x81\xC2", 4, 'add r10d, 0x????????' ],
|
|
[ "\x41\x81\xC3", 4, 'add r11d, 0x????????' ],
|
|
[ "\x41\x81\xC4", 4, 'add r12d, 0x????????' ],
|
|
[ "\x41\x81\xC5", 4, 'add r13d, 0x????????' ],
|
|
[ "\x41\x81\xC6", 4, 'add r14d, 0x????????' ],
|
|
[ "\x41\x81\xC7", 4, 'add r15d, 0x????????' ],
|
|
[ "\x48\xB8", 8, 'mov rax, 0x????????????????' ],
|
|
[ "\x48\xBB", 8, 'mov rbx, 0x????????????????' ],
|
|
[ "\x48\xB9", 8, 'mov rcx, 0x????????????????' ],
|
|
[ "\x48\xBA", 8, 'mov rdx, 0x????????????????' ],
|
|
[ "\x48\xBE", 8, 'mov rsi, 0x????????????????' ],
|
|
[ "\x48\xBF", 8, 'mov rdi, 0x????????????????' ],
|
|
[ "\x49\xB8", 8, 'mov r8, 0x????????????????' ],
|
|
[ "\x49\xB9", 8, 'mov r8, 0x????????????????' ],
|
|
[ "\x49\xBA", 8, 'mov r10, 0x????????????????' ],
|
|
[ "\x49\xBB", 8, 'mov r11, 0x????????????????' ],
|
|
[ "\x49\xBC", 8, 'mov r12, 0x????????????????' ],
|
|
[ "\x49\xBD", 8, 'mov r13, 0x????????????????' ],
|
|
[ "\x49\xBE", 8, 'mov r14, 0x????????????????' ],
|
|
[ "\x49\xBF", 8, 'mov r15, 0x????????????????' ],
|
|
]
|
|
|
|
I_OP = 0
|
|
I_SIZE = 1
|
|
I_TEXT = 2
|
|
|
|
REGISTERS = [
|
|
[ 'rsp', 'esp', 'sp' ],
|
|
[ 'rbp', 'ebp', 'bp' ],
|
|
[ 'rax', 'eax', 'ax', 'al', 'ah' ],
|
|
[ 'rbx', 'ebx', 'bx', 'bl', 'bh' ],
|
|
[ 'rcx', 'ecx', 'cx', 'cl', 'ch' ],
|
|
[ 'rdx', 'edx', 'dx', 'dl', 'dh' ],
|
|
[ 'rsi', 'esi', 'si' ],
|
|
[ 'rdi', 'edi', 'di' ],
|
|
[ 'r8', 'r8d', 'r8w', 'r8b' ],
|
|
[ 'r9', 'r9d', 'r9w', 'r9b' ],
|
|
[ 'r10', 'r10d', 'r10w', 'r10b' ],
|
|
[ 'r11', 'r11d', 'r11w', 'r11b' ],
|
|
[ 'r12', 'r12d', 'r12w', 'r12b' ],
|
|
[ 'r13', 'r13d', 'r13w', 'r13b' ],
|
|
[ 'r14', 'r14d', 'r14w', 'r14b' ],
|
|
[ 'r15', 'r15d', 'r15w', 'r15b' ],
|
|
]
|
|
|
|
def generate_random_sled(length, instructions, badchars, badregs)
|
|
opcodes_stack = []
|
|
total_size = 0
|
|
sled = ''
|
|
try_count = 0
|
|
|
|
# Fixup SaveRegisters so for example, if we wish to preserve RSP we also should also preserve ESP and SP
|
|
REGISTERS.each { |reg| reg.each { |x| badregs += reg if badregs.include?(x) } }
|
|
badregs = badregs.uniq
|
|
|
|
# If we are preserving RSP we should avoid all PUSH/POP instructions...
|
|
if badregs.include?('rsp')
|
|
badregs.push('push')
|
|
badregs.push('pop')
|
|
end
|
|
|
|
# Loop while we still have bytes to fill in the sled...
|
|
loop do
|
|
# Pick a random instruction and see if we can use it...
|
|
instruction = instructions[rand(instructions.length)]
|
|
|
|
# Avoid using any bad mnemonics/registers...
|
|
try_another = false
|
|
badregs.each do |bad|
|
|
try_another = true if instruction[I_TEXT].include?(bad.downcase)
|
|
break if try_another
|
|
end
|
|
next if try_another
|
|
|
|
# Get the first bytes of the chosen instructions opcodes...
|
|
opcodes = instruction[I_OP]
|
|
|
|
# If their are additional bytes to append, do it now...
|
|
1.upto(instruction[I_SIZE]) do |_i|
|
|
opcodes += Rex::Text.rand_char(badchars)
|
|
end
|
|
|
|
# If we have gone over the requested sled length, try again.
|
|
if total_size + opcodes.length > length
|
|
try_count -= 1
|
|
|
|
# If we have tried unsuccessfully 32 times we start unwinding the chosen opcode_stack to speed things up
|
|
if try_count == 0
|
|
pop_count = 4
|
|
while opcodes_stack.length && pop_count
|
|
total_size -= opcodes_stack.pop.length
|
|
pop_count -= 1
|
|
end
|
|
end
|
|
next
|
|
end
|
|
|
|
# Reset the try_count for the next iteration.
|
|
try_count = 32
|
|
|
|
# save the opcodes we just generated.
|
|
opcodes_stack.push(opcodes)
|
|
|
|
# Increment the total size appropriately.
|
|
total_size += opcodes.length
|
|
|
|
# Once we have generated the requested amount of bytes we can finish.
|
|
break if total_size == length
|
|
end
|
|
|
|
# Now that we have chosen all the instructions to use we must generate the actual sled.
|
|
opcodes_stack.each do |opcodes_|
|
|
sled += opcodes_
|
|
end
|
|
|
|
return sled
|
|
end
|
|
|
|
def generate_sled(length, opts)
|
|
badchars = opts['BadChars'] || ''
|
|
random = opts['Random'] || datastore['RandomNops']
|
|
badregs = opts['SaveRegisters'] || []
|
|
good_instructions = []
|
|
sled = ''
|
|
|
|
# Weed out any instructions which will contain a bad char/instruction...
|
|
INSTRUCTIONS.each do |instruction|
|
|
good = true
|
|
# If the instruction contains some bad chars we wont use it...
|
|
badchars.each_char do |bc|
|
|
if instruction[I_OP].include?(bc)
|
|
good = false
|
|
break
|
|
end
|
|
end
|
|
# if we are only to generate single byte instructions, weed out the multi byte ones...
|
|
good = false if (instruction[I_SIZE] > 0) && !datastore['MultiByte']
|
|
|
|
good_instructions.push(instruction) if good
|
|
end
|
|
|
|
# After we have pruned the instruction list we can proceed to generate a sled...
|
|
if good_instructions.empty?
|
|
# If we are left with no valid instructions to use we simple can't generate a sled.
|
|
sled = nil
|
|
elsif !random
|
|
if !badchars.include?("\x90")
|
|
sled += "\x90" * length
|
|
else
|
|
sled = nil
|
|
end
|
|
else
|
|
sled += generate_random_sled(length, good_instructions, badchars, badregs)
|
|
end
|
|
|
|
return sled
|
|
end
|
|
end
|