PowerShellMafia / PowerSploit

PowerSploit - A PowerShell Post-Exploitation Framework
Other
11.77k stars 4.59k forks source link

Add support for Windows 10 v1803 to Invoke-ReflectivePEInjection #289

Open tonymeehan opened 6 years ago

tonymeehan commented 6 years ago

Summary

This change adds support for Windows 10 v1803 April 2018 Update to Invoke-ReflectivePEInjection.

Description

The latest update to Windows 10, RS4 (also called Windows 10 1803 or Windows 10 build 17134), introduced some changes that breaks Invoke-ReflectivePEInjection.

First, the GetMethod() lookup here to find GetProcAddress in kernel32.dll no longer works. It fails with the following error:

Exception calling "GetMethod" with "1" argument(s): "Ambiguous match found."

If you run GetMethods() on $UnsafeNativeMethods, you'll see there are two GetProcAddress results on Windows 10 v1803.

$UnsafeNativeMethods.GetMethods() | Out-File methods.txt
...
Name                       : GetProcAddress
DeclaringType              : Microsoft.Win32.UnsafeNativeMethods
ReflectedType              : Microsoft.Win32.UnsafeNativeMethods
MemberType                 : Method
MetadataToken              : 100663839
Module                     : System.dll
IsSecurityCritical         : True
IsSecuritySafeCritical     : True
IsSecurityTransparent      : False
MethodHandle               : System.RuntimeMethodHandle
Attributes                 : PrivateScope, Public, Static, HideBySig, PinvokeImpl
CallingConvention          : Standard
ReturnType                 : System.IntPtr
ReturnTypeCustomAttributes : IntPtr 
ReturnParameter            : IntPtr 
IsGenericMethod            : False
IsGenericMethodDefinition  : False
ContainsGenericParameters  : False
MethodImplementationFlags  : PreserveSig
IsPublic                   : True
IsPrivate                  : False
IsFamily                   : False
IsAssembly                 : False
IsFamilyAndAssembly        : False
IsFamilyOrAssembly         : False
IsStatic                   : True
IsFinal                    : False
IsVirtual                  : False
IsHideBySig                : True
IsAbstract                 : False
IsSpecialName              : False
IsConstructor              : False
CustomAttributes           : {[System.Runtime.InteropServices.DllImportAttribute("kernel32.dll", EntryPoint = 
                             "GetProcAddress", CharSet = 2, ExactSpelling = True, SetLastError = True, PreserveSig = True, 
                             CallingConvention = 1, BestFitMapping = False, ThrowOnUnmappableChar = False)], 
                             [System.Runtime.InteropServices.PreserveSigAttribute()]}

Name                       : GetProcAddress
DeclaringType              : Microsoft.Win32.UnsafeNativeMethods
ReflectedType              : Microsoft.Win32.UnsafeNativeMethods
MemberType                 : Method
MetadataToken              : 100663864
Module                     : System.dll
IsSecurityCritical         : True
IsSecuritySafeCritical     : True
IsSecurityTransparent      : False
MethodHandle               : System.RuntimeMethodHandle
Attributes                 : PrivateScope, Public, Static, HideBySig, PinvokeImpl
CallingConvention          : Standard
ReturnType                 : System.IntPtr
ReturnTypeCustomAttributes : IntPtr 
ReturnParameter            : IntPtr 
IsGenericMethod            : False
IsGenericMethodDefinition  : False
ContainsGenericParameters  : False
MethodImplementationFlags  : PreserveSig
IsPublic                   : True
IsPrivate                  : False
IsFamily                   : False
IsAssembly                 : False
IsFamilyAndAssembly        : False
IsFamilyOrAssembly         : False
IsStatic                   : True
IsFinal                    : False
IsVirtual                  : False
IsHideBySig                : True
IsAbstract                 : False
IsSpecialName              : False
IsConstructor              : False
CustomAttributes           : {[System.Runtime.InteropServices.DllImportAttribute("kernel32.dll", EntryPoint = 
                             "GetProcAddress", CharSet = 2, ExactSpelling = False, SetLastError = False, PreserveSig = 
                             True, CallingConvention = 1, BestFitMapping = False, ThrowOnUnmappableChar = False)], 
                             [System.Runtime.InteropServices.PreserveSigAttribute()]}

The only apparent difference between the two is ExactSpelling. The solution here that appears to work on Windows 7 SP1 and newer and Windows Server 2k8 R2 and newer is to always select the first method to avoid the ambiguous match exception.

$GetProcAddress = $UnsafeNativeMethods.GetMethods() | Where {$_.Name -eq "GetProcAddress"} | Select-Object -first 1

The second issue is here. $Kern32Handle must be of type System.IntPtr instead of System.Runtime.InteropServices.HandleRef. This can be observed in the following exception:

Exception calling "Invoke" with "2" argument(s): "Object of type 'System.Runtime.InteropServices.HandleRef' cannot be
converted to type 'System.IntPtr'."

The solution to this problem is to try System.Runtime.InteropServices.HandleRef and fall back to System.IntPtr if there's an exception.

How was it tested?

I tested this on the following versions of Windows, but would definitely welcome more testing and validation that this is the best solution.

mr64bit commented 6 years ago

GetMethod has an overload that lets you tell it which function overload you want by supplying an array of types.

Changing line #1002 to this is a better fix. $GetProcAddress = $UnsafeNativeMethods.GetMethod('GetProcAddress', [Type[]]@([System.Runtime.InteropServices.HandleRef], [String]))

tonymeehan commented 6 years ago

Thanks @mr64bit I'll update the PR with your suggestion.