metasploit-framework/modules/nops/x64/simple.rb

246 lines
9.9 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 warrent 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
good_bytes = []
# 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...
while true
# 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 chosed 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 and pop_count
total_size -= opcodes_stack.pop().length
pop_count -= 1
end
end
next
end
# Reset the try_count for the next itteration.
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 and not 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 cant generate a sled.
sled = nil
elsif not random
if not 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