##
# $Id$
##

##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# web site for more information on licensing and terms of use.
#   http://metasploit.com/
##


require 'msf/core'


class Metasploit3 < Msf::Nop

	def initialize
		super(
			'Name'        => 'Simple',
			'Alias'       => 'x64_simple',
			'Version'     => '$Revision$',
			'Description' => 'An x64 single/multi byte NOP instruction generator.',
			'Author'      => [ 'sf' ],
			'License'     => MSF_LICENSE,
			'Arch'        => ARCH_X86_64 )

		register_advanced_options( [ OptBool.new( 'RandomNops', [ false, "Generate a random NOP sled", true ] ) ], self.class )
		register_advanced_options( [ OptBool.new( 'MultiByte',  [ false, "Generate a multi byte instruction NOP sled", false ] ) ], self.class )
	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 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
